lib.rs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. use ggez::{Context,GameError};
  2. use ggez::graphics::{Drawable,DrawParam,Image};
  3. use ggez::graphics::spritebatch::{SpriteBatch,SpriteIdx};
  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(ctx: &mut Context, tile_size: impl Into<Size>, file: impl AsRef<Path>) -> Result<Tileset, GameError> {
  33. let tile_size = tile_size.into();
  34. let image = Image::new(ctx, file)?;
  35. let mut batch = SpriteBatch::new(image);
  36. batch.set_filter(ggez::graphics::FilterMode::Nearest);
  37. Ok(Tileset { tile_size, batch })
  38. }
  39. fn to_screen(&self, coord: impl Into<Coord>) -> [f32;2] {
  40. let Coord { x, y } = coord.into();
  41. [(x * self.tile_size.width) as f32,
  42. (y * self.tile_size.height) as f32,
  43. ]
  44. }
  45. }
  46. #[derive(Debug, PartialEq, Eq, Hash)]
  47. pub struct Size {
  48. width: usize,
  49. height: usize,
  50. }
  51. impl From<[usize;2]> for Size {
  52. fn from([width, height]: [usize;2]) -> Size {
  53. Size { width, height }
  54. }
  55. }
  56. #[derive(Debug, PartialEq, Eq, Hash)]
  57. pub struct Coord {
  58. x: usize,
  59. y: usize,
  60. }
  61. impl From<[usize;2]> for Coord {
  62. fn from([x, y]: [usize;2]) -> Coord {
  63. Coord { x, y }
  64. }
  65. }
  66. impl Board {
  67. pub fn new(size: impl Into<Size>, mut tileset: Tileset) -> Board {
  68. let size = size.into();
  69. let mut contents = Vec::new();
  70. for y in 0..size.height {
  71. for x in 0..size.width {
  72. let param = DrawParam::new()
  73. .src(Board::sprite_location(0u8).into())
  74. .dest(tileset.to_screen([x, y]));
  75. let idx = tileset.batch.add(param);
  76. contents.push((0u8, idx));
  77. }
  78. }
  79. Board { size, contents, tileset }
  80. }
  81. fn sprite_location(ch: u8) -> [f32;4] {
  82. let u = f32::from(ch % 16) * TILE_SIZE;
  83. let v = f32::from(ch / 16) * TILE_SIZE;
  84. [u, v, TILE_SIZE, TILE_SIZE]
  85. }
  86. pub fn draw(&self, ctx: &mut Context) -> Result<(), ggez::GameError> {
  87. self.tileset.batch.draw(ctx, DrawParam::new())
  88. }
  89. pub fn set(&mut self, at: impl Into<Coord>, ch: u8) {
  90. let at = at.into();
  91. let idx = at.x + at.y * self.size.width;
  92. let param = DrawParam::new()
  93. .src(Board::sprite_location(ch).into())
  94. .dest(self.tileset.to_screen(at));
  95. self.tileset.batch.set(self.contents[idx].1, param).unwrap();
  96. }
  97. pub fn set_with_color(&mut self, at: impl Into<Coord>, ch: u8, color: impl Into<ggez::graphics::Color>) {
  98. let at = at.into();
  99. let idx = at.x + at.y * self.size.width;
  100. let param = DrawParam::new()
  101. .src(Board::sprite_location(ch).into())
  102. .dest(self.tileset.to_screen(at))
  103. .color(color.into());
  104. self.tileset.batch.set(self.contents[idx].1, param).unwrap();
  105. }
  106. pub fn get(&mut self, at: impl Into<Coord>) -> u8 {
  107. let at = at.into();
  108. let idx = at.x + at.y * self.size.width;
  109. self.contents[idx].0
  110. }
  111. pub fn print(&mut self, at: impl Into<Coord>, msg: &str) {
  112. let Coord { x, y } = at.into();
  113. for (idx, ch) in msg.chars().enumerate() {
  114. self.set([idx + x, y], ch as u8);
  115. }
  116. }
  117. pub fn clear(&mut self) {
  118. for (n, contents) in self.contents.iter_mut().enumerate() {
  119. let x = n % self.size.width;
  120. let y = n / self.size.width;
  121. let param = DrawParam::new()
  122. .src(Board::sprite_location(0).into())
  123. .dest(self.tileset.to_screen([x, y]));
  124. contents.0 = 0;
  125. self.tileset.batch.set(contents.1, param).unwrap();
  126. }
  127. }
  128. }