map.py 3.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. # coding: utf-8
  2. import typing
  3. import tmx
  4. from synergine2_xyz.exceptions import ImproperlyConfiguredMap
  5. class XYZTile(object):
  6. def __init__(self, tile: tmx.Tile) -> None:
  7. self.tile = tile
  8. def property(self, name: str) -> typing.Union[str, int, float]:
  9. for property in self.tile.properties:
  10. if property.name == name:
  11. return property.value
  12. raise ImproperlyConfiguredMap('Tile with id "{}" don\'t contains "{}" property'.format(
  13. self.tile.id,
  14. name,
  15. ))
  16. class UnconstructedTile(XYZTile):
  17. pass
  18. class TMXMap(object):
  19. xyz_tile_class = XYZTile
  20. transform_zero_y_to_bottom = True
  21. def __init__(self, map_file_path: str) -> None:
  22. self.tmx_map = tmx.TileMap.load(map_file_path)
  23. self.tmx_layers = {} # type: typing.Dict[str, tmx.Layer]
  24. self.tmx_layer_tiles = {} # type: typing.Dict[str, typing.Dict[str, XYZTile]]
  25. self.tmx_tilesets = {} # type: typing.Dict[str, tmx.Tileset]
  26. self.tmx_tiles = {} # type: typing.Dict[int, XYZTile]
  27. self._load()
  28. @property
  29. def height(self) -> int:
  30. return self.tmx_map.height
  31. @property
  32. def width(self) -> int:
  33. return self.tmx_map.width
  34. def get_default_tileset(self) -> tmx.Tileset:
  35. return list(self.tmx_tilesets.values())[0]
  36. def get_default_tile(self) -> XYZTile:
  37. tileset = self.get_default_tileset()
  38. return self.xyz_tile_class(tileset.tiles[0])
  39. def _load(self) -> None:
  40. self._load_layers()
  41. self._load_tilesets()
  42. self._load_tiles()
  43. def _load_layers(self) -> None:
  44. for layer in self.tmx_map.layers:
  45. self.tmx_layers[layer.name] = layer
  46. def _load_tilesets(self) -> None:
  47. for tileset in self.tmx_map.tilesets:
  48. self.tmx_tilesets[tileset.name] = tileset
  49. for tile in tileset.tiles:
  50. self.tmx_tiles[tileset.firstgid + tile.id] = self.xyz_tile_class(tile)
  51. def _load_tiles(self) -> None:
  52. for layer_name, layer in self.tmx_layers.items():
  53. x = -1
  54. y = 0 if not self.transform_zero_y_to_bottom else self.height - 1
  55. y_modifier = 1 if not self.transform_zero_y_to_bottom else -1
  56. self.tmx_layer_tiles[layer_name] = {}
  57. # no tiles
  58. if not isinstance(layer, tmx.Layer):
  59. continue
  60. for layer_tile in layer.tiles:
  61. x += 1
  62. if x == self.width:
  63. x = 0
  64. y += y_modifier
  65. position_key = '{}.{}'.format(x, y)
  66. if not layer_tile.gid:
  67. tile = self.get_default_tile()
  68. elif not layer_tile.gid in self.tmx_tiles:
  69. # tile = UnconstructedTile()
  70. tile = self.get_default_tile()
  71. else:
  72. tile = self.tmx_tiles[layer_tile.gid]
  73. self.tmx_layer_tiles[layer_name][position_key] = tile
  74. def layer(self, name: str) -> tmx.Layer:
  75. return self.tmx_layers[name]
  76. def tileset(self, name: str) -> tmx.Tileset:
  77. return self.tmx_tilesets[name]
  78. def tile(self, gid: int) -> XYZTile:
  79. return self.tmx_tiles[gid]
  80. def layer_tiles(self, name: str) -> typing.Dict[str, XYZTile]:
  81. return self.tmx_layer_tiles[name]