diff --git a/assets/units/tank.gif b/assets/units/tank.gif new file mode 100644 index 0000000..10dd42c Binary files /dev/null and b/assets/units/tank.gif differ diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..271800c --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" \ No newline at end of file diff --git a/src/interpolator.rs b/src/interpolator.rs new file mode 100644 index 0000000..2f94317 --- /dev/null +++ b/src/interpolator.rs @@ -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, v2: Vec2) -> Vec2 { + 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 + } + } + } +} diff --git a/src/main.rs b/src/main.rs index 9be6bc8..798b049 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,8 @@ +#![feature(div_duration)] + mod unit_kind; mod unit; +mod interpolator; use std::cell::RefCell; use std::rc::Rc; @@ -32,20 +35,22 @@ impl Game { pub fn tick(&mut self, window_state: &mut WindowState) { 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 { fn new(window_state: &mut WindowState) -> Self { setup_palette(window_state); - let tileset = Tileset::load("assets/hex2.gif", Vec2{x: 2, y: 1}); - let kind = UnitKind::new("bob"); + window_state.scramble_palette(); + 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 { - 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}), last_tick: Instant::now(), - tick_duration: Duration::from_secs(1) / 10, + tick_duration, current_tick: 0 } } @@ -62,12 +67,13 @@ impl skunk2d::Game for Game { } fn draw(&self, target: &mut Image) { + let now = Instant::now(); target.clear(); target.draw_hexmap(Vec2::zero(), &self.map); - self.unit.borrow().draw(target, &self.map); + self.unit.borrow().draw(target, &self.map, now); } } fn main() { - run::(640, 360); + run::(1920, 1080); } diff --git a/src/unit.rs b/src/unit.rs index 8c4fbb9..b734136 100644 --- a/src/unit.rs +++ b/src/unit.rs @@ -1,14 +1,32 @@ use std::rc::Rc; +use std::time::Instant; use skunk2d::{HexMap, Image, Vec2}; +use crate::interpolator::Interpolator; use crate::unit_kind::UnitKind; pub struct Unit { pub kind: Rc, - pub pos: Vec2 + pub pos: Vec2, + pub interpolator: Interpolator, + pub old_pos: Vec2 } impl Unit { - pub fn draw(&self, target: &mut Image, map: &HexMap) { - target.draw_image( map.coord_to_pixel(self.pos), &self.kind.sprite); + pub fn draw(&self, target: &mut Image, map: &HexMap, time: Instant) { + 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) { + 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) { + self.set_pos(self.pos + pos); } } \ No newline at end of file diff --git a/src/unit_kind.rs b/src/unit_kind.rs index 8fc38ec..6e9a296 100644 --- a/src/unit_kind.rs +++ b/src/unit_kind.rs @@ -1,25 +1,34 @@ use std::cell::RefCell; +use std::ops::Mul; use std::rc::Rc; +use std::time::Duration; use skunk2d::{Image, Vec2}; +use crate::interpolator::Interpolator; use crate::unit::Unit; pub struct UnitKind { pub sprite: Rc, - pub name: String + pub name: String, + pub speed: i32, + pub movement_duration: Duration } impl UnitKind { - pub fn new(name: &str) -> Rc { + pub fn new(name: &str, speed: i32, tick_duration: Duration) -> Rc { UnitKind { 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() } pub fn spawn(self: Rc, pos: Vec2) -> Rc> { RefCell::new(Unit { kind: self, - pos + pos, + interpolator: Interpolator::fake(), + old_pos: pos }).into() } }