main.rs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. #[macro_use] extern crate specs_derive;
  2. use ggez::{Context, ContextBuilder, GameResult};
  3. use ggez::event::{self, EventHandler};
  4. use ggez::graphics;
  5. use std::path::Path;
  6. use specs::{Component, RunNow, System, NullStorage, VecStorage};
  7. use specs::world::Builder;
  8. #[allow(dead_code)]
  9. mod consts {
  10. pub const SPEED: u32 = 2;
  11. pub const TILE_SIZE: u32 = 24;
  12. pub const HALF_TILE: u32 = TILE_SIZE / 2;
  13. pub const QUARTER_TILE: u32 = TILE_SIZE / 4;
  14. pub const BOARD_WIDTH: usize = 16;
  15. pub const BOARD_HEIGHT: usize = 12;
  16. pub const SCALE: u32 = 3;
  17. pub const TILED_TRUE: tiled::PropertyValue =
  18. tiled::PropertyValue::BoolValue(true);
  19. }
  20. #[derive(Component, Debug)]
  21. #[storage(VecStorage)]
  22. struct Position {
  23. x: f32,
  24. y: f32,
  25. }
  26. impl Position {
  27. fn to_point(&self) -> ggez::nalgebra::Point2<f32> {
  28. ggez::nalgebra::Point2::new(self.x, self.y)
  29. }
  30. }
  31. #[derive(Component, Debug)]
  32. #[storage(VecStorage)]
  33. struct Sprite {
  34. u: u8,
  35. v: u8,
  36. }
  37. impl Sprite {
  38. fn to_rect(&self) -> graphics::Rect {
  39. graphics::Rect {
  40. x: (1.0 / 32.0) * self.u as f32,
  41. y: (1.0 / 32.0) * self.v as f32,
  42. w: 1.0 / 32.0,
  43. h: 1.0 / 32.0,
  44. }
  45. }
  46. }
  47. #[derive(Debug, Copy, Clone)]
  48. enum DrawLayer {
  49. Background,
  50. Foreground,
  51. Decoration,
  52. }
  53. static DRAW_LAYERS: [DrawLayer;3] = [
  54. DrawLayer::Background,
  55. DrawLayer::Foreground,
  56. DrawLayer::Decoration,
  57. ];
  58. #[derive(Component, Default, Debug)]
  59. #[storage(NullStorage)]
  60. struct Background;
  61. #[derive(Component, Default, Debug)]
  62. #[storage(NullStorage)]
  63. struct Foreground;
  64. #[derive(Component, Default, Debug)]
  65. #[storage(NullStorage)]
  66. struct Decoration;
  67. fn world_from_file(w: &mut specs::World, path: &Path) {
  68. let tiled::Map {
  69. layers,
  70. ..
  71. } = tiled::parse_file(path).unwrap();
  72. for (phase, layer) in DRAW_LAYERS.iter().zip(layers) {
  73. for (row, y) in layer.tiles.iter().zip(0..) {
  74. for (&n, x) in row.iter().zip(0..) {
  75. if n != 0 {
  76. let x = x as f32 * 24.0;
  77. let y = y as f32 * 24.0;
  78. let u = ((n - 1) % 32) as u8;
  79. let v = ((n - u as u32 - 1) / 32) as u8;
  80. let mut e = w.create_entity()
  81. .with(Position { x, y })
  82. .with(Sprite { u, v });
  83. e = match phase {
  84. DrawLayer::Background => e.with(Background),
  85. DrawLayer::Foreground => e.with(Foreground),
  86. DrawLayer::Decoration => e.with(Decoration),
  87. };
  88. e.build();
  89. }
  90. }
  91. }
  92. }
  93. }
  94. struct MyGame {
  95. world: specs::World,
  96. sprites: graphics::spritebatch::SpriteBatch,
  97. }
  98. struct Draw<'t, Phase> {
  99. ctx: &'t mut Context,
  100. sprites: &'t mut graphics::spritebatch::SpriteBatch,
  101. _phase: Phase,
  102. }
  103. impl<'a, 't, Phase: Component> System<'a> for Draw<'t, Phase> {
  104. type SystemData = (
  105. specs::ReadStorage<'a, Position>,
  106. specs::ReadStorage<'a, Sprite>,
  107. specs::ReadStorage<'a, Phase>,
  108. );
  109. fn run(&mut self, (positions, sprites, phase): Self::SystemData) {
  110. use specs::Join;
  111. for (pos, spr, _) in (&positions, &sprites, &phase).join() {
  112. let param = graphics::DrawParam {
  113. src: spr.to_rect(),
  114. dest: pos.to_point(),
  115. ..Default::default()
  116. };
  117. self.sprites.add(param);
  118. graphics::draw(
  119. self.ctx,
  120. self.sprites,
  121. ggez::nalgebra::Point2::new(0.0, 0.0),
  122. 0.0).unwrap();
  123. self.sprites.clear();
  124. }
  125. }
  126. }
  127. impl EventHandler for MyGame {
  128. fn update(&mut self, _ctx: &mut Context) -> GameResult<()> {
  129. Ok(())
  130. }
  131. fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
  132. use ggez::graphics as g;
  133. use ggez::nalgebra as n;
  134. g::set_background_color(ctx, g::BLACK);
  135. g::clear(ctx);
  136. Draw { ctx, sprites: &mut self.sprites, _phase: Background }.run_now(&self.world.res);
  137. Draw { ctx, sprites: &mut self.sprites, _phase: Foreground }.run_now(&self.world.res);
  138. Draw { ctx, sprites: &mut self.sprites, _phase: Decoration }.run_now(&self.world.res);
  139. g::draw(ctx, &self.sprites, n::Point2::new(0.0, 0.0), 0.0)?;
  140. self.sprites.clear();
  141. g::present(ctx);
  142. Ok(())
  143. }
  144. }
  145. fn main() -> Result<(), ggez::error::GameError> {
  146. let mut world = specs::World::new();
  147. world.register::<Position>();
  148. world.register::<Sprite>();
  149. world.register::<Background>();
  150. world.register::<Foreground>();
  151. world.register::<Decoration>();
  152. world_from_file(&mut world, &Path::new("assets/main.tmx"));
  153. // Make a Context and an EventLoop.
  154. let mut ctx = ContextBuilder::new("game", "me")
  155. .add_resource_path({
  156. let base = std::env::var("CARGO_MANIFEST_DIR").unwrap();
  157. let mut path = std::path::PathBuf::from(base);
  158. path.push("assets");
  159. path
  160. })
  161. .build()?;
  162. let image = graphics::Image::new(&mut ctx, "/spritesheet.png")?;
  163. let sprites = graphics::spritebatch::SpriteBatch::new(image);
  164. let mut my_game = MyGame {
  165. world,
  166. sprites,
  167. };
  168. event::run(&mut ctx, &mut my_game)
  169. }