mod.rs 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. use std::collections::HashMap;
  2. use std::fs::File;
  3. use std::io::BufReader;
  4. use std::path::Path;
  5. use ggez::GameError;
  6. use ggez::GameResult;
  7. use tiled::{
  8. parse_with_path, Image as TiledImage, Image, ImageLayer, Layer, LayerData, Map as TiledMap,
  9. Orientation, PropertyValue, Tileset,
  10. };
  11. use crate::map::decor::{Decor, DecorTile};
  12. use crate::map::terrain::{Terrain, TerrainTile};
  13. use crate::map::util::{
  14. extract_gids, extract_image_from_image_layer, extract_image_from_tileset, extract_layer,
  15. extract_tileset, extract_tileset_images, extract_tilesets_containing_gids,
  16. get_tileset_i_for_gid,
  17. };
  18. pub mod decor;
  19. pub mod terrain;
  20. pub mod util;
  21. pub struct Map {
  22. pub tiled_map: TiledMap,
  23. pub background_image: TiledImage,
  24. pub terrain: Terrain,
  25. pub decor: Decor,
  26. }
  27. impl Map {
  28. pub fn new(map_file_path: &Path) -> GameResult<Self> {
  29. let map_file = File::open(map_file_path)?;
  30. let map_file_reader = BufReader::new(map_file);
  31. let tiled_map = match parse_with_path(map_file_reader, map_file_path) {
  32. Ok(map) => map,
  33. Err(e) => {
  34. return GameResult::Err(GameError::ResourceLoadError(format!(
  35. "Fail to parse map: {:?}",
  36. e
  37. )))
  38. }
  39. };
  40. if &tiled_map.orientation != &Orientation::Orthogonal {
  41. return GameResult::Err(GameError::ResourceLoadError(
  42. "Map must be orthogonal orientation".to_string(),
  43. ));
  44. }
  45. // Background and roofs
  46. let background_image = extract_image_from_image_layer(&tiled_map, "background")?;
  47. let roofs_image = extract_image_from_image_layer(&tiled_map, "roofs")?;
  48. // let roofs_layer = ...
  49. // Terrain
  50. let terrain_tileset: Tileset = extract_tileset(&tiled_map, "terrain")?;
  51. let terrain_layer: Layer = extract_layer(&tiled_map, "terrain")?;
  52. let terrain_image = extract_image_from_tileset(&terrain_tileset)?;
  53. let mut terrain_tiles: HashMap<(u32, u32), TerrainTile> = HashMap::new();
  54. match &terrain_layer.tiles {
  55. LayerData::Finite(layer_tiles) => {
  56. for (x, tiles_row) in layer_tiles.iter().enumerate() {
  57. for (y, layer_tile) in tiles_row.iter().enumerate() {
  58. // FIXME BS NOW: et si gid = 0 ?
  59. let tile = terrain::get_tile_from_terrain_tileset_with_id(
  60. &terrain_tileset,
  61. layer_tile.gid,
  62. terrain_image.width as u32,
  63. terrain_image.height as u32,
  64. )?;
  65. terrain_tiles.insert((y as u32, x as u32), tile);
  66. }
  67. }
  68. }
  69. LayerData::Infinite(_) => {
  70. return GameResult::Err(GameError::ResourceLoadError(
  71. "Terrain layer must be finite".to_string(),
  72. ))
  73. }
  74. }
  75. let terrain = Terrain::new(terrain_tileset, terrain_layer, terrain_image, terrain_tiles);
  76. // Decor
  77. let mut decor_tiles: HashMap<(u32, u32), DecorTile> = HashMap::new();
  78. let decor_layer: Layer = extract_layer(&tiled_map, "decor")?;
  79. let decor_tile_gids = extract_gids(&decor_layer)?;
  80. let decor_tilesets: Vec<Tileset> =
  81. extract_tilesets_containing_gids(&tiled_map, decor_tile_gids);
  82. let decor_images: Vec<TiledImage> = extract_tileset_images(&decor_tilesets)?;
  83. match &decor_layer.tiles {
  84. LayerData::Finite(layer_tiles) => {
  85. for (x, tiles_row) in layer_tiles.iter().enumerate() {
  86. for (y, layer_tile) in tiles_row.iter().enumerate() {
  87. if layer_tile.gid == 0 {
  88. continue;
  89. }
  90. let tileset_i = get_tileset_i_for_gid(layer_tile.gid, &decor_tilesets)
  91. .expect("gid must be find");
  92. let tileset = decor_tilesets
  93. .get(tileset_i)
  94. .expect("Decor tileset must be here");
  95. let image = decor_images.get(tileset_i).expect("Image must exist");
  96. let tiled_tile_id = layer_tile.gid - tileset.first_gid;
  97. let tile_width = tileset.tile_width;
  98. let tile_height = tileset.tile_height;
  99. let relative_tile_width = tile_width as f32 / image.width as f32;
  100. let relative_tile_height = tile_height as f32 / image.height as f32;
  101. let len_by_width = image.width as u32 / tile_width;
  102. let tile_y = tiled_tile_id / len_by_width;
  103. let tile_x = tiled_tile_id - (tile_y * len_by_width);
  104. let tile = DecorTile::new(
  105. tileset_i,
  106. tile_width,
  107. tile_height,
  108. relative_tile_width,
  109. relative_tile_height,
  110. tile_x,
  111. tile_y,
  112. );
  113. decor_tiles.insert((y as u32, x as u32), tile);
  114. }
  115. }
  116. }
  117. LayerData::Infinite(_) => {
  118. return GameResult::Err(GameError::ResourceLoadError(
  119. "Decor layer must be finite".to_string(),
  120. ))
  121. }
  122. }
  123. let decor = Decor::new(decor_layer, decor_tilesets, decor_images, decor_tiles);
  124. GameResult::Ok(Map {
  125. tiled_map: tiled_map.clone(),
  126. background_image: background_image.clone(),
  127. terrain,
  128. decor,
  129. })
  130. }
  131. }