lib.rs 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  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. pub struct Board {
  8. size: Size,
  9. contents: Vec<SpriteIdx>,
  10. tileset: Tileset,
  11. }
  12. pub struct Tileset {
  13. tile_size: Size,
  14. batch: SpriteBatch,
  15. }
  16. impl Tileset {
  17. pub fn from_file(ctx: &mut Context, tile_size: impl Into<Size>, file: impl AsRef<Path>) -> Result<Tileset, GameError> {
  18. let tile_size = tile_size.into();
  19. let image = Image::new(ctx, file)?;
  20. let mut batch = SpriteBatch::new(image);
  21. batch.set_filter(ggez::graphics::FilterMode::Nearest);
  22. Ok(Tileset { tile_size, batch })
  23. }
  24. fn to_screen(&self, coord: impl Into<Coord>) -> [f32;2] {
  25. let Coord { x, y } = coord.into();
  26. [(x * self.tile_size.width) as f32,
  27. (y * self.tile_size.height) as f32,
  28. ]
  29. }
  30. }
  31. #[derive(Debug, PartialEq, Eq, Hash)]
  32. pub struct Size {
  33. width: usize,
  34. height: usize,
  35. }
  36. impl From<[usize;2]> for Size {
  37. fn from([width, height]: [usize;2]) -> Size {
  38. Size { width, height }
  39. }
  40. }
  41. #[derive(Debug, PartialEq, Eq, Hash)]
  42. pub struct Coord {
  43. x: usize,
  44. y: usize,
  45. }
  46. impl From<[usize;2]> for Coord {
  47. fn from([x, y]: [usize;2]) -> Coord {
  48. Coord { x, y }
  49. }
  50. }
  51. impl Board {
  52. pub fn new(size: impl Into<Size>, mut tileset: Tileset) -> Board {
  53. let size = size.into();
  54. let mut contents = Vec::new();
  55. for y in 0..size.height {
  56. for x in 0..size.width {
  57. let param = DrawParam::new()
  58. .src(Board::sprite_location(0u8).into())
  59. .dest(tileset.to_screen([x, y]));
  60. let idx = tileset.batch.add(param);
  61. contents.push(idx);
  62. }
  63. }
  64. Board { size, contents, tileset }
  65. }
  66. fn sprite_location(ch: u8) -> [f32;4] {
  67. let u = f32::from(ch % 16) * TILE_SIZE;
  68. let v = f32::from(ch / 16) * TILE_SIZE;
  69. [u, v, TILE_SIZE, TILE_SIZE]
  70. }
  71. pub fn draw(&self, ctx: &mut Context) -> Result<(), ggez::GameError> {
  72. self.tileset.batch.draw(ctx, DrawParam::new())
  73. }
  74. pub fn set(&mut self, at: impl Into<Coord>, ch: u8) {
  75. let at = at.into();
  76. let idx = at.x + at.y * self.size.width;
  77. let param = DrawParam::new()
  78. .src(Board::sprite_location(ch).into())
  79. .dest(self.tileset.to_screen(at));
  80. self.tileset.batch.set(self.contents[idx], param).unwrap();
  81. }
  82. pub fn print(&mut self, at: impl Into<Coord>, msg: &str) {
  83. let Coord { x, y } = at.into();
  84. for (idx, ch) in msg.chars().enumerate() {
  85. self.set([idx + x, y], ch as u8);
  86. }
  87. }
  88. }
  89. #[cfg(test)]
  90. mod tests {
  91. #[test]
  92. fn it_works() {
  93. assert_eq!(2 + 2, 4);
  94. }
  95. }