Compare commits

..

No commits in common. "master" and "skunk2d" have entirely different histories.

13 changed files with 1833 additions and 2 deletions

1616
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -6,4 +6,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
skunk2d = {path = "../skunk2d"}
rand = "0.8.5" rand = "0.8.5"

BIN
assets/hex2.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1001 B

BIN
assets/hex3.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
assets/units/bob.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 910 B

BIN
assets/units/tank.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

1
assets/units/tank.pal Normal file
View File

@ -0,0 +1 @@
ŚŠŚüţü¤˘¤””DBD¬®¬””|~|\Z\śžś´˛´ŚŽŚ¤¦¤

BIN
assets/units/tank.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 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,3 +1,89 @@
fn main() { #![feature(div_duration)]
println!("Hello World nyaa");
mod unit_kind;
mod unit;
mod interpolator;
use std::cell::RefCell;
use std::rc::Rc;
use std::time::{Duration, Instant};
use rand::Rng;
use skunk2d::{Direction, Event, HexMap, Image, run, Tileset, Vec2, WindowState};
use crate::unit::Unit;
use crate::unit_kind::UnitKind;
//todo: keep unit_map position and unit's position in sync... how?
struct Game {
map: HexMap,
unit_map: Vec<Option<Rc<RefCell<Unit>>>>,
unit: Rc<RefCell<Unit>>,
last_tick: Instant,
tick_duration: Duration,
current_tick: i32,
}
fn setup_palette(ws: &mut WindowState) {
ws.set_palette(0, 0xc0, 0xf0, 0xd0);
ws.set_palette(2, 0x10, 0x30, 0x20);
ws.set_palette(1, 0xb0, 0xe0, 0xc0);
ws.set_palette(3, 0xa0, 0xd0, 0xb0);
ws.set_palette(255, 0xff, 0xff, 0xff);
ws.set_palette(254, 0x00, 0x00, 0x00);
ws.set_palette(253, 0x80, 0x80, 0x80);
}
impl Game {
pub fn tick(&mut self, window_state: &mut WindowState) {
window_state.log(format!("tick: {}", self.current_tick).as_str());
let mut unit = self.unit.borrow_mut();
unit.cool();
unit.move_unit(rand::thread_rng().gen(), &self.map);
//unit.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);
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", 4, tick_duration);
let map = HexMap::new(Vec2{x: 26, y: 22}, tileset, Vec2{ x: 72, y: 24 });
let idx_size = map.idx_size();
Game {
map,
unit_map: vec![None; idx_size],
unit: kind.spawn(Vec2{x: 5, y: 5}),
last_tick: Instant::now(),
tick_duration,
current_tick: 0
}
}
fn update(&mut self, window_state: &mut WindowState) {
if Instant::now() - self.last_tick >= self.tick_duration {
self.tick(window_state);
self.last_tick += self.tick_duration;
self.current_tick += 1;
}
}
fn on_event(&mut self, window_state: &mut WindowState, event: Event) {
}
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, now);
}
}
fn main() {
run::<Game>(1920, 1080, 60);
} }

47
src/unit.rs Normal file
View File

@ -0,0 +1,47 @@
use std::rc::Rc;
use std::time::Instant;
use skunk2d::{HexMap, Image, Vec2, Direction};
use crate::interpolator::Interpolator;
use crate::unit_kind::UnitKind;
pub struct Unit {
pub kind: Rc<UnitKind>,
pub pos: Vec2<i32>,
pub interpolator: Interpolator,
pub old_pos: Vec2<i32>,
pub cooldown: i32
}
impl Unit {
pub fn cool(&mut self) {
self.cooldown = (self.cooldown - 1).max(0)
}
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 move_unit(&mut self, dir: Direction, map: &HexMap) {
if self.cooldown == 0 {
let new_pos = HexMap::get_neighbour(self.pos, dir);
if map.is_valid_coord(new_pos) {
self.set_pos(new_pos);
self.cooldown = self.kind.speed;
}
}
}
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);
}
}

36
src/unit_kind.rs Normal file
View File

@ -0,0 +1,36 @@
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<Image>,
pub name: String,
pub speed: i32,
pub movement_duration: Duration
}
impl UnitKind {
pub fn new(name: &str, speed: i32, tick_duration: Duration) -> Rc<Self> {
UnitKind {
sprite: Image::load(format!("assets/units/{}.gif", name).as_str()),
name: name.into(),
speed,
movement_duration: tick_duration.mul(speed as u32)
}.into()
}
pub fn spawn(self: Rc<Self>, pos: Vec2<i32>) -> Rc<RefCell<Unit>> {
RefCell::new(Unit {
kind: self,
pos,
interpolator: Interpolator::fake(),
old_pos: pos,
cooldown: 0
}).into()
}
}