lib.rs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. use ggez::graphics::spritebatch::{SpriteBatch, SpriteIdx};
  2. use ggez::graphics::{DrawParam, Drawable, Image};
  3. use ggez::{Context, GameError};
  4. use std::path::Path;
  5. /// we only care about 16x16 tilesets
  6. const TILE_SIZE: f32 = 1.0 / 16.0;
  7. #[derive(Eq, PartialEq, Debug, Copy, Clone)]
  8. pub enum Color {
  9. Red,
  10. Green,
  11. Blue,
  12. }
  13. impl From<Color> for ggez::graphics::Color {
  14. fn from(color: Color) -> ggez::graphics::Color {
  15. match color {
  16. Color::Red => [1.0, 0.0, 0.0, 1.0].into(),
  17. Color::Green => [0.0, 1.0, 0.0, 1.0].into(),
  18. Color::Blue => [0.0, 0.0, 1.0, 1.0].into(),
  19. }
  20. }
  21. }
  22. pub struct Board {
  23. size: Size,
  24. contents: Vec<(u8, SpriteIdx)>,
  25. tileset: Tileset,
  26. }
  27. pub struct Tileset {
  28. tile_size: Size,
  29. batch: SpriteBatch,
  30. }
  31. impl Tileset {
  32. pub fn from_file(
  33. ctx: &mut Context,
  34. tile_size: impl Into<Size>,
  35. file: impl AsRef<Path>,
  36. ) -> Result<Tileset, GameError> {
  37. let tile_size = tile_size.into();
  38. let image = Image::new(ctx, file)?;
  39. let mut batch = SpriteBatch::new(image);
  40. batch.set_filter(ggez::graphics::FilterMode::Nearest);
  41. Ok(Tileset { tile_size, batch })
  42. }
  43. fn to_screen(&self, coord: impl Into<Coord>) -> [f32; 2] {
  44. let Coord { x, y } = coord.into();
  45. [
  46. (x * self.tile_size.width) as f32,
  47. (y * self.tile_size.height) as f32,
  48. ]
  49. }
  50. }
  51. #[derive(Debug, PartialEq, Eq, Hash)]
  52. pub struct Size {
  53. width: usize,
  54. height: usize,
  55. }
  56. impl From<[usize; 2]> for Size {
  57. fn from([width, height]: [usize; 2]) -> Size {
  58. Size { width, height }
  59. }
  60. }
  61. #[derive(Debug, PartialEq, Eq, Hash)]
  62. pub struct Coord {
  63. x: usize,
  64. y: usize,
  65. }
  66. impl From<[usize; 2]> for Coord {
  67. fn from([x, y]: [usize; 2]) -> Coord {
  68. Coord { x, y }
  69. }
  70. }
  71. impl Board {
  72. pub fn new(size: impl Into<Size>, mut tileset: Tileset) -> Board {
  73. let size = size.into();
  74. let mut contents = Vec::new();
  75. for y in 0..size.height {
  76. for x in 0..size.width {
  77. let param = DrawParam::new()
  78. .src(Board::sprite_location(0u8).into())
  79. .dest(tileset.to_screen([x, y]));
  80. let idx = tileset.batch.add(param);
  81. contents.push((0u8, idx));
  82. }
  83. }
  84. Board {
  85. size,
  86. contents,
  87. tileset,
  88. }
  89. }
  90. fn sprite_location(ch: u8) -> [f32; 4] {
  91. let u = f32::from(ch % 16) * TILE_SIZE;
  92. let v = f32::from(ch / 16) * TILE_SIZE;
  93. [u, v, TILE_SIZE, TILE_SIZE]
  94. }
  95. pub fn draw(&self, ctx: &mut Context) -> Result<(), ggez::GameError> {
  96. self.tileset.batch.draw(ctx, DrawParam::new())
  97. }
  98. pub fn set(&mut self, at: impl Into<Coord>, ch: u8) {
  99. let at = at.into();
  100. let idx = at.x + at.y * self.size.width;
  101. let param = DrawParam::new()
  102. .src(Board::sprite_location(ch).into())
  103. .dest(self.tileset.to_screen(at));
  104. self.tileset.batch.set(self.contents[idx].1, param).unwrap();
  105. }
  106. pub fn set_with_color(
  107. &mut self,
  108. at: impl Into<Coord>,
  109. ch: u8,
  110. color: impl Into<ggez::graphics::Color>,
  111. ) {
  112. let at = at.into();
  113. let idx = at.x + at.y * self.size.width;
  114. let param = DrawParam::new()
  115. .src(Board::sprite_location(ch).into())
  116. .dest(self.tileset.to_screen(at))
  117. .color(color.into());
  118. self.tileset.batch.set(self.contents[idx].1, param).unwrap();
  119. }
  120. pub fn get(&mut self, at: impl Into<Coord>) -> u8 {
  121. let at = at.into();
  122. let idx = at.x + at.y * self.size.width;
  123. self.contents[idx].0
  124. }
  125. pub fn print(&mut self, at: impl Into<Coord>, msg: &str) {
  126. let Coord { x, y } = at.into();
  127. for (idx, ch) in msg.chars().enumerate() {
  128. self.set([idx + x, y], ch as u8);
  129. }
  130. }
  131. pub fn clear(&mut self) {
  132. for (n, contents) in self.contents.iter_mut().enumerate() {
  133. let x = n % self.size.width;
  134. let y = n / self.size.width;
  135. let param = DrawParam::new()
  136. .src(Board::sprite_location(0).into())
  137. .dest(self.tileset.to_screen([x, y]));
  138. contents.0 = 0;
  139. self.tileset.batch.set(contents.1, param).unwrap();
  140. }
  141. }
  142. }