interpolator

This commit is contained in:
dani 2023-07-06 13:40:13 +00:00
parent 74fa53a30a
commit c64d698e04
6 changed files with 91 additions and 14 deletions

BIN
assets/units/tank.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

2
rust-toolchain.toml Normal file
View File

@ -0,0 +1,2 @@
[toolchain]
channel = "nightly"

42
src/interpolator.rs Normal file
View File

@ -0,0 +1,42 @@
use std::time::{Duration, Instant};
use skunk2d::Vec2;
pub struct Interpolator {
start: Instant,
end: Instant,
length: Duration
}
impl Interpolator {
pub fn new(start: Instant, length: Duration) -> Self {
Interpolator {
start,
end: start + length,
length
}
}
//interpolator that will always return 1.0f64
pub fn fake() -> Self {
//ugly <_<
let meh = Instant::now() - Duration::from_secs(100);
Interpolator::new(meh, Duration::from_secs(1))
}
pub fn get(&self, pos: Instant) -> f64 {
(pos - self.start).div_duration_f64(self.length).max(0f64).min(1f64)
}
pub fn apply_vec2(&self, pos: Instant, v1: Vec2<i32>, v2: Vec2<i32>) -> Vec2<i32> {
let p = self.get(pos);
let delta = v2 - v1;
if delta.x.abs() > 100 || delta.y.abs() > 100 {
v2
} else {
Vec2 {
x: (v1.x as f64 + delta.x as f64 * p).round() as i32,
y: (v1.y as f64 + delta.y as f64 * p).round() as i32
}
}
}
}

View File

@ -1,5 +1,8 @@
#![feature(div_duration)]
mod unit_kind; mod unit_kind;
mod unit; mod unit;
mod interpolator;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
@ -32,20 +35,22 @@ impl Game {
pub fn tick(&mut self, window_state: &mut WindowState) { pub fn tick(&mut self, window_state: &mut WindowState) {
window_state.log(format!("tick: {}", self.current_tick).as_str()); window_state.log(format!("tick: {}", self.current_tick).as_str());
self.unit.borrow_mut().pos.y = self.current_tick % self.map.size().y; self.unit.borrow_mut().set_pos(Vec2{x: 5, y: self.current_tick % self.map.size().y});
} }
} }
impl skunk2d::Game for Game { impl skunk2d::Game for Game {
fn new(window_state: &mut WindowState) -> Self { fn new(window_state: &mut WindowState) -> Self {
setup_palette(window_state); setup_palette(window_state);
let tileset = Tileset::load("assets/hex2.gif", Vec2{x: 2, y: 1}); window_state.scramble_palette();
let kind = UnitKind::new("bob"); let tick_duration = Duration::from_secs(1) / 10;
let tileset = Tileset::load("assets/hex3.gif", Vec2{x: 1, y: 1});
let kind = UnitKind::new("tank", 1, tick_duration);
Game { Game {
map: HexMap::new(Vec2{x: 11, y: 11}, tileset, Vec2{ x: 23, y: 13 }), map: HexMap::new(Vec2{x: 26, y: 22}, tileset, Vec2{ x: 72, y: 24 }),
unit: kind.spawn(Vec2{x: 5, y: 5}), unit: kind.spawn(Vec2{x: 5, y: 5}),
last_tick: Instant::now(), last_tick: Instant::now(),
tick_duration: Duration::from_secs(1) / 10, tick_duration,
current_tick: 0 current_tick: 0
} }
} }
@ -62,12 +67,13 @@ impl skunk2d::Game for Game {
} }
fn draw(&self, target: &mut Image) { fn draw(&self, target: &mut Image) {
let now = Instant::now();
target.clear(); target.clear();
target.draw_hexmap(Vec2::zero(), &self.map); target.draw_hexmap(Vec2::zero(), &self.map);
self.unit.borrow().draw(target, &self.map); self.unit.borrow().draw(target, &self.map, now);
} }
} }
fn main() { fn main() {
run::<Game>(640, 360); run::<Game>(1920, 1080);
} }

View File

@ -1,14 +1,32 @@
use std::rc::Rc; use std::rc::Rc;
use std::time::Instant;
use skunk2d::{HexMap, Image, Vec2}; use skunk2d::{HexMap, Image, Vec2};
use crate::interpolator::Interpolator;
use crate::unit_kind::UnitKind; use crate::unit_kind::UnitKind;
pub struct Unit { pub struct Unit {
pub kind: Rc<UnitKind>, pub kind: Rc<UnitKind>,
pub pos: Vec2<i32> pub pos: Vec2<i32>,
pub interpolator: Interpolator,
pub old_pos: Vec2<i32>
} }
impl Unit { impl Unit {
pub fn draw(&self, target: &mut Image, map: &HexMap) { pub fn draw(&self, target: &mut Image, map: &HexMap, time: Instant) {
target.draw_image( map.coord_to_pixel(self.pos), &self.kind.sprite); let old_pos = map.coord_to_pixel(self.old_pos);
let new_pos = map.coord_to_pixel(self.pos);
let pos = self.interpolator.apply_vec2(time, old_pos, new_pos);
//todo: don't hardcode offset :P
target.draw_image( pos + Vec2{x: 0, y: -24}, &self.kind.sprite);
}
pub fn set_pos(&mut self, pos: Vec2<i32>) {
self.interpolator = Interpolator::new(Instant::now(), self.kind.movement_duration);
self.old_pos = self.pos;
self.pos = pos;
}
pub fn add_pos(&mut self, pos: Vec2<i32>) {
self.set_pos(self.pos + pos);
} }
} }

View File

@ -1,25 +1,34 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::ops::Mul;
use std::rc::Rc; use std::rc::Rc;
use std::time::Duration;
use skunk2d::{Image, Vec2}; use skunk2d::{Image, Vec2};
use crate::interpolator::Interpolator;
use crate::unit::Unit; use crate::unit::Unit;
pub struct UnitKind { pub struct UnitKind {
pub sprite: Rc<Image>, pub sprite: Rc<Image>,
pub name: String pub name: String,
pub speed: i32,
pub movement_duration: Duration
} }
impl UnitKind { impl UnitKind {
pub fn new(name: &str) -> Rc<Self> { pub fn new(name: &str, speed: i32, tick_duration: Duration) -> Rc<Self> {
UnitKind { UnitKind {
sprite: Image::load(format!("assets/units/{}.gif", name).as_str()), sprite: Image::load(format!("assets/units/{}.gif", name).as_str()),
name: name.into() name: name.into(),
speed,
movement_duration: tick_duration.mul(speed as u32)
}.into() }.into()
} }
pub fn spawn(self: Rc<Self>, pos: Vec2<i32>) -> Rc<RefCell<Unit>> { pub fn spawn(self: Rc<Self>, pos: Vec2<i32>) -> Rc<RefCell<Unit>> {
RefCell::new(Unit { RefCell::new(Unit {
kind: self, kind: self,
pos pos,
interpolator: Interpolator::fake(),
old_pos: pos
}).into() }).into()
} }
} }