|
@@ -3,9 +3,6 @@ use ggez::graphics::{DrawParam, Drawable, Image};
|
|
|
use ggez::{Context, GameError};
|
|
|
use std::path::Path;
|
|
|
|
|
|
-/// we only care about 16x16 tilesets
|
|
|
-const TILE_SIZE: f32 = 1.0 / 16.0;
|
|
|
-
|
|
|
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
|
|
|
pub enum Color {
|
|
|
Red,
|
|
@@ -23,28 +20,51 @@ impl From<Color> for ggez::graphics::Color {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-pub struct Board {
|
|
|
+pub struct Board<Idx: Tile> {
|
|
|
size: Size,
|
|
|
- contents: Vec<(u8, SpriteIdx)>,
|
|
|
- tileset: Tileset,
|
|
|
+ contents: Vec<(Idx, SpriteIdx)>,
|
|
|
+ tileset: Tileset<Idx>,
|
|
|
+}
|
|
|
+
|
|
|
+pub trait Tile: Copy {
|
|
|
+ fn to_location(self) -> [f32;4];
|
|
|
+ fn blank() -> Self;
|
|
|
}
|
|
|
|
|
|
-pub struct Tileset {
|
|
|
+impl Tile for u8 {
|
|
|
+ fn to_location(self) -> [f32;4] {
|
|
|
+ const TILE_SIZE: f32 = 1.0 / 16.0;
|
|
|
+ let u = f32::from(self % 16) * TILE_SIZE;
|
|
|
+ let v = f32::from(self / 16) * TILE_SIZE;
|
|
|
+ [u, v, TILE_SIZE, TILE_SIZE]
|
|
|
+ }
|
|
|
+
|
|
|
+ fn blank() -> Self {
|
|
|
+ 0
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+pub struct Tileset<Idx: Tile> {
|
|
|
tile_size: Size,
|
|
|
batch: SpriteBatch,
|
|
|
+ idx: std::marker::PhantomData<Idx>,
|
|
|
}
|
|
|
|
|
|
-impl Tileset {
|
|
|
+impl<Idx: Tile> Tileset<Idx> {
|
|
|
pub fn from_file(
|
|
|
ctx: &mut Context,
|
|
|
tile_size: impl Into<Size>,
|
|
|
file: impl AsRef<Path>,
|
|
|
- ) -> Result<Tileset, GameError> {
|
|
|
+ ) -> Result<Tileset<Idx>, GameError> {
|
|
|
let tile_size = tile_size.into();
|
|
|
let image = Image::new(ctx, file)?;
|
|
|
let mut batch = SpriteBatch::new(image);
|
|
|
batch.set_filter(ggez::graphics::FilterMode::Nearest);
|
|
|
- Ok(Tileset { tile_size, batch })
|
|
|
+ Ok(Tileset {
|
|
|
+ tile_size,
|
|
|
+ batch,
|
|
|
+ idx: std::marker::PhantomData,
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
fn to_screen(&self, coord: impl Into<Coord>) -> [f32; 2] {
|
|
@@ -80,17 +100,17 @@ impl From<[usize; 2]> for Coord {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl Board {
|
|
|
- pub fn new(size: impl Into<Size>, mut tileset: Tileset) -> Board {
|
|
|
+impl<Idx: Tile> Board<Idx> {
|
|
|
+ pub fn new(size: impl Into<Size>, mut tileset: Tileset<Idx>) -> Board<Idx> {
|
|
|
let size = size.into();
|
|
|
let mut contents = Vec::new();
|
|
|
for y in 0..size.height {
|
|
|
for x in 0..size.width {
|
|
|
let param = DrawParam::new()
|
|
|
- .src(Board::sprite_location(0u8).into())
|
|
|
+ .src(Idx::blank().to_location().into())
|
|
|
.dest(tileset.to_screen([x, y]));
|
|
|
let idx = tileset.batch.add(param);
|
|
|
- contents.push((0u8, idx));
|
|
|
+ contents.push((Idx::blank(), idx));
|
|
|
}
|
|
|
}
|
|
|
Board {
|
|
@@ -100,21 +120,21 @@ impl Board {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- fn sprite_location(ch: u8) -> [f32; 4] {
|
|
|
- let u = f32::from(ch % 16) * TILE_SIZE;
|
|
|
- let v = f32::from(ch / 16) * TILE_SIZE;
|
|
|
- [u, v, TILE_SIZE, TILE_SIZE]
|
|
|
- }
|
|
|
+ // fn sprite_location(ch: u8) -> [f32; 4] {
|
|
|
+ // let u = f32::from(ch % 16) * TILE_SIZE;
|
|
|
+ // let v = f32::from(ch / 16) * TILE_SIZE;
|
|
|
+ // [u, v, TILE_SIZE, TILE_SIZE]
|
|
|
+ // }
|
|
|
|
|
|
pub fn draw(&self, ctx: &mut Context) -> Result<(), ggez::GameError> {
|
|
|
self.tileset.batch.draw(ctx, DrawParam::new())
|
|
|
}
|
|
|
|
|
|
- pub fn set(&mut self, at: impl Into<Coord>, ch: u8) {
|
|
|
+ pub fn set(&mut self, at: impl Into<Coord>, ch: Idx) {
|
|
|
let at = at.into();
|
|
|
let idx = at.x + at.y * self.size.width;
|
|
|
let param = DrawParam::new()
|
|
|
- .src(Board::sprite_location(ch).into())
|
|
|
+ .src(ch.to_location().into())
|
|
|
.dest(self.tileset.to_screen(at));
|
|
|
self.tileset.batch.set(self.contents[idx].1, param).unwrap();
|
|
|
}
|
|
@@ -122,40 +142,42 @@ impl Board {
|
|
|
pub fn set_with_color(
|
|
|
&mut self,
|
|
|
at: impl Into<Coord>,
|
|
|
- ch: u8,
|
|
|
+ ch: Idx,
|
|
|
color: impl Into<ggez::graphics::Color>,
|
|
|
) {
|
|
|
let at = at.into();
|
|
|
let idx = at.x + at.y * self.size.width;
|
|
|
let param = DrawParam::new()
|
|
|
- .src(Board::sprite_location(ch).into())
|
|
|
+ .src(ch.to_location().into())
|
|
|
.dest(self.tileset.to_screen(at))
|
|
|
.color(color.into());
|
|
|
self.tileset.batch.set(self.contents[idx].1, param).unwrap();
|
|
|
}
|
|
|
|
|
|
- pub fn get(&mut self, at: impl Into<Coord>) -> u8 {
|
|
|
+ pub fn get(&mut self, at: impl Into<Coord>) -> Idx {
|
|
|
let at = at.into();
|
|
|
let idx = at.x + at.y * self.size.width;
|
|
|
self.contents[idx].0
|
|
|
}
|
|
|
|
|
|
- pub fn print(&mut self, at: impl Into<Coord>, msg: &str) {
|
|
|
- let Coord { x, y } = at.into();
|
|
|
- for (idx, ch) in msg.chars().enumerate() {
|
|
|
- self.set([idx + x, y], ch as u8);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
pub fn clear(&mut self) {
|
|
|
for (n, contents) in self.contents.iter_mut().enumerate() {
|
|
|
let x = n % self.size.width;
|
|
|
let y = n / self.size.width;
|
|
|
let param = DrawParam::new()
|
|
|
- .src(Board::sprite_location(0).into())
|
|
|
+ .src(Idx::blank().to_location().into())
|
|
|
.dest(self.tileset.to_screen([x, y]));
|
|
|
- contents.0 = 0;
|
|
|
+ contents.0 = Idx::blank();
|
|
|
self.tileset.batch.set(contents.1, param).unwrap();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+impl Board<u8> {
|
|
|
+ pub fn print(&mut self, at: impl Into<Coord>, msg: &str) {
|
|
|
+ let Coord { x, y } = at.into();
|
|
|
+ for (idx, ch) in msg.chars().enumerate() {
|
|
|
+ self.set([idx + x, y], ch as u8);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|