From c64d698e048fa47bc660e28ef2556d6e208ef138 Mon Sep 17 00:00:00 2001 From: dani Date: Thu, 6 Jul 2023 13:40:13 +0000 Subject: [PATCH] interpolator --- assets/units/tank.gif | Bin 0 -> 1446 bytes rust-toolchain.toml | 2 ++ src/interpolator.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 20 +++++++++++++------- src/unit.rs | 24 +++++++++++++++++++++--- src/unit_kind.rs | 17 +++++++++++++---- 6 files changed, 91 insertions(+), 14 deletions(-) create mode 100644 assets/units/tank.gif create mode 100644 rust-toolchain.toml create mode 100644 src/interpolator.rs diff --git a/assets/units/tank.gif b/assets/units/tank.gif new file mode 100644 index 0000000000000000000000000000000000000000..10dd42c11313e5b9890b80d4438404e98b654430 GIT binary patch literal 1446 zcmZ?wbhEHbOkhZ0XlGzxVPfg&>iP5U&yqz;rc9gS;^eYs-I^(rrqtBc#6-o+nKx(4 zrY${vJxi7?0jeBDqaiTNLO}69x1VcBu(M-;tC5}oGb1AdgW^AN=c3falGGH1^30M9 zg@B@b1>gLV%=|nC#h)zP3_zd*B0xEaf%UI~LSIVeyo^=ra$fH%&^cd{d%t4c`w`B|ZGxRQhP+E}jqbQZr3=`n=y4 z9rrV4efoX>Qi1B4mb&`fLXOIop5(TK?(C-CDSc%VCQq6=yLd+J%sEr~V-_?ooZ7f# z{_=$a%##;;7fxF9>T6^-;>HV?i z&RtA9wxLqs+R2GG1#X|)aXRUe-M+ZTjJ&*8*4(=FqN}^`t@Xa5$5K2q%-74UDn59s zKzi}}8N2JVBqC;;Pgvm4TqL6RW~<)x?J}`aNzn>{3tYSYiZL&BG}ljF!pwKk!NFm& z+A&r}i4dEU!3xSHoP07Fnk!E;x)voYT6uEIvV&dL>~5wvIp#Jp3A6}p-Qw}WUD|kd zm#Af0mj8VFi-lKi9atK;RN?q3)!hdk`At52DeuXw(u~`S;2j zg&W12InSH=6gu47()z3F>!EA83F3;X-OFks3*DKV%)8&{bh@QnoRlwgo1L-r)djQD z8_xccJfD4I<7v}NbETd=DBE>+2iv(jD?j+pGH-ut{>bpfvl}mWm6ZJME}gl5GrRxc z{_=dK)FbBmSKjfg`g-8{#6!IM3)X4Bf8EW>D(+qP*R1#9RmuMczlYUFvQ#aMk7t>) z+_mw{*QW_hUk--dZmD<3xUaZC(?g<7W*UQHsbZOgRHy2p53yZ3+g?2CHaMp7xX0vL o#^YX#XDc4}*?fEPxZi 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() } }