use ggez::{Context,GameError}; use ggez::graphics::{Drawable,DrawParam,Image}; use ggez::graphics::spritebatch::{SpriteBatch,SpriteIdx}; use std::path::Path; /// we only care about 16x16 tilesets const TILE_SIZE: f32 = 1.0 / 16.0; pub struct Board { size: Size, contents: Vec, tileset: Tileset, } pub struct Tileset { tile_size: Size, batch: SpriteBatch, } impl Tileset { pub fn from_file(ctx: &mut Context, tile_size: impl Into, file: impl AsRef) -> Result { 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 }) } fn to_screen(&self, coord: impl Into) -> [f32;2] { let Coord { x, y } = coord.into(); [(x * self.tile_size.width) as f32, (y * self.tile_size.height) as f32, ] } } #[derive(Debug, PartialEq, Eq, Hash)] pub struct Size { width: usize, height: usize, } impl From<[usize;2]> for Size { fn from([width, height]: [usize;2]) -> Size { Size { width, height } } } #[derive(Debug, PartialEq, Eq, Hash)] pub struct Coord { x: usize, y: usize, } impl From<[usize;2]> for Coord { fn from([x, y]: [usize;2]) -> Coord { Coord { x, y } } } impl Board { pub fn new(size: impl Into, mut tileset: Tileset) -> Board { 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()) .dest(tileset.to_screen([x, y])); let idx = tileset.batch.add(param); contents.push(idx); } } Board { size, contents, tileset } } 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, ch: u8) { let at = at.into(); let idx = at.x + at.y * self.size.width; let param = DrawParam::new() .src(Board::sprite_location(ch).into()) .dest(self.tileset.to_screen(at)); self.tileset.batch.set(self.contents[idx], param).unwrap(); } pub fn print(&mut self, at: impl Into, msg: &str) { let Coord { x, y } = at.into(); for (idx, ch) in msg.chars().enumerate() { self.set([idx + x, y], ch as u8); } } } #[cfg(test)] mod tests { #[test] fn it_works() { assert_eq!(2 + 2, 4); } }