#[macro_use] extern crate specs_derive; use ggez::{Context, ContextBuilder, GameResult}; use ggez::event::{self, EventHandler}; use ggez::graphics; use std::path::Path; use specs::{Component, RunNow, System, NullStorage, VecStorage}; use specs::world::Builder; #[allow(dead_code)] mod consts { pub const SPEED: u32 = 2; pub const TILE_SIZE: u32 = 24; pub const HALF_TILE: u32 = TILE_SIZE / 2; pub const QUARTER_TILE: u32 = TILE_SIZE / 4; pub const BOARD_WIDTH: usize = 16; pub const BOARD_HEIGHT: usize = 12; pub const SCALE: u32 = 3; pub const TILED_TRUE: tiled::PropertyValue = tiled::PropertyValue::BoolValue(true); } #[derive(Component, Debug)] #[storage(VecStorage)] struct Position { x: f32, y: f32, } impl Position { fn to_point(&self) -> ggez::nalgebra::Point2 { ggez::nalgebra::Point2::new(self.x, self.y) } } #[derive(Component, Debug)] #[storage(VecStorage)] struct Sprite { u: u8, v: u8, } impl Sprite { fn to_rect(&self) -> graphics::Rect { graphics::Rect { x: (1.0 / 32.0) * self.u as f32, y: (1.0 / 32.0) * self.v as f32, w: 1.0 / 32.0, h: 1.0 / 32.0, } } } #[derive(Debug, Copy, Clone)] enum DrawLayer { Background, Foreground, Decoration, } static DRAW_LAYERS: [DrawLayer;3] = [ DrawLayer::Background, DrawLayer::Foreground, DrawLayer::Decoration, ]; #[derive(Component, Default, Debug)] #[storage(NullStorage)] struct Background; #[derive(Component, Default, Debug)] #[storage(NullStorage)] struct Foreground; #[derive(Component, Default, Debug)] #[storage(NullStorage)] struct Decoration; fn world_from_file(w: &mut specs::World, path: &Path) { let tiled::Map { layers, .. } = tiled::parse_file(path).unwrap(); for (phase, layer) in DRAW_LAYERS.iter().zip(layers) { for (row, y) in layer.tiles.iter().zip(0..) { for (&n, x) in row.iter().zip(0..) { if n != 0 { let x = x as f32 * 24.0; let y = y as f32 * 24.0; let u = ((n - 1) % 32) as u8; let v = ((n - u as u32 - 1) / 32) as u8; let mut e = w.create_entity() .with(Position { x, y }) .with(Sprite { u, v }); e = match phase { DrawLayer::Background => e.with(Background), DrawLayer::Foreground => e.with(Foreground), DrawLayer::Decoration => e.with(Decoration), }; e.build(); } } } } } struct MyGame { world: specs::World, sprites: graphics::spritebatch::SpriteBatch, } struct Draw<'t, Phase> { ctx: &'t mut Context, sprites: &'t mut graphics::spritebatch::SpriteBatch, _phase: Phase, } impl<'a, 't, Phase: Component> System<'a> for Draw<'t, Phase> { type SystemData = ( specs::ReadStorage<'a, Position>, specs::ReadStorage<'a, Sprite>, specs::ReadStorage<'a, Phase>, ); fn run(&mut self, (positions, sprites, phase): Self::SystemData) { use specs::Join; for (pos, spr, _) in (&positions, &sprites, &phase).join() { let param = graphics::DrawParam { src: spr.to_rect(), dest: pos.to_point(), ..Default::default() }; self.sprites.add(param); graphics::draw( self.ctx, self.sprites, ggez::nalgebra::Point2::new(0.0, 0.0), 0.0).unwrap(); self.sprites.clear(); } } } impl EventHandler for MyGame { fn update(&mut self, _ctx: &mut Context) -> GameResult<()> { Ok(()) } fn draw(&mut self, ctx: &mut Context) -> GameResult<()> { use ggez::graphics as g; use ggez::nalgebra as n; g::set_background_color(ctx, g::BLACK); g::clear(ctx); Draw { ctx, sprites: &mut self.sprites, _phase: Background }.run_now(&self.world.res); Draw { ctx, sprites: &mut self.sprites, _phase: Foreground }.run_now(&self.world.res); Draw { ctx, sprites: &mut self.sprites, _phase: Decoration }.run_now(&self.world.res); g::draw(ctx, &self.sprites, n::Point2::new(0.0, 0.0), 0.0)?; self.sprites.clear(); g::present(ctx); Ok(()) } } fn main() -> Result<(), ggez::error::GameError> { let mut world = specs::World::new(); world.register::(); world.register::(); world.register::(); world.register::(); world.register::(); world_from_file(&mut world, &Path::new("assets/main.tmx")); // Make a Context and an EventLoop. let mut ctx = ContextBuilder::new("game", "me") .add_resource_path({ let base = std::env::var("CARGO_MANIFEST_DIR").unwrap(); let mut path = std::path::PathBuf::from(base); path.push("assets"); path }) .build()?; let image = graphics::Image::new(&mut ctx, "/spritesheet.png")?; let sprites = graphics::spritebatch::SpriteBatch::new(image); let mut my_game = MyGame { world, sprites, }; event::run(&mut ctx, &mut my_game) }