tilemap-parser 3.1.23__tar.gz → 4.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/PKG-INFO +31 -3
  2. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/README.md +30 -2
  3. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/pyproject.toml +1 -1
  4. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/src/tilemap_parser/parser/__init__.py +4 -0
  5. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/src/tilemap_parser/parser/collision.py +39 -1
  6. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/src/tilemap_parser/parser/map_parse.py +29 -3
  7. tilemap_parser-4.1.0/src/tilemap_parser/parser/tmx_converter.py +447 -0
  8. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/src/tilemap_parser/runtime/map_loader.py +21 -1
  9. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/src/tilemap_parser.egg-info/PKG-INFO +31 -3
  10. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/src/tilemap_parser.egg-info/SOURCES.txt +4 -1
  11. tilemap_parser-4.1.0/tests/test_gid_collision.py +260 -0
  12. tilemap_parser-4.1.0/tests/test_tmx_converter.py +442 -0
  13. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/LICENSE +0 -0
  14. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/setup.cfg +0 -0
  15. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/src/tilemap_parser/__init__.py +0 -0
  16. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/src/tilemap_parser/parser/animation.py +0 -0
  17. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/src/tilemap_parser/parser/collision_loader.py +0 -0
  18. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/src/tilemap_parser/parser/node_parse.py +0 -0
  19. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/src/tilemap_parser/parser/particle.py +0 -0
  20. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/src/tilemap_parser/runtime/__init__.py +0 -0
  21. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/src/tilemap_parser/runtime/animation_player.py +0 -0
  22. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/src/tilemap_parser/runtime/area_node.py +0 -0
  23. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/src/tilemap_parser/runtime/camera.py +0 -0
  24. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/src/tilemap_parser/runtime/collision_cache.py +0 -0
  25. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/src/tilemap_parser/runtime/object_collision.py +0 -0
  26. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/src/tilemap_parser/runtime/particles.py +0 -0
  27. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/src/tilemap_parser/runtime/renderer.py +0 -0
  28. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/src/tilemap_parser/runtime/tile_collision.py +0 -0
  29. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/src/tilemap_parser/utils/__init__.py +0 -0
  30. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/src/tilemap_parser/utils/geometry.py +0 -0
  31. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/src/tilemap_parser.egg-info/dependency_links.txt +0 -0
  32. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/src/tilemap_parser.egg-info/requires.txt +0 -0
  33. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/src/tilemap_parser.egg-info/top_level.txt +0 -0
  34. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/tests/test_camera.py +0 -0
  35. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/tests/test_collision.py +0 -0
  36. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/tests/test_geometry.py +0 -0
  37. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/tests/test_integration_animation.py +0 -0
  38. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/tests/test_integration_collision.py +0 -0
  39. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/tests/test_integration_map_loader.py +0 -0
  40. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/tests/test_map_loader.py +0 -0
  41. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/tests/test_move_grounded.py +0 -0
  42. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/tests/test_object_collision.py +0 -0
  43. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/tests/test_object_surfaces.py +0 -0
  44. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/tests/test_particle_emitter.py +0 -0
  45. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/tests/test_render_scale.py +0 -0
  46. {tilemap_parser-3.1.23 → tilemap_parser-4.1.0}/tests/test_tile_collision.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tilemap-parser
3
- Version: 3.1.23
3
+ Version: 4.1.0
4
4
  Summary: Standalone parser/loader for tilemap-editor JSON maps, sprite animations, and collision detection runtime.
5
5
  Author: tilemap parser contributors
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -704,7 +704,10 @@ Standalone parser/loader for tilemap-editor JSON maps, sprite animations, and co
704
704
  ## Features
705
705
 
706
706
  - **Map parsing**: Load and query tilemaps, layers, objects, and autotile data from JSON
707
+ - **Chunked tile rendering**: Efficient visibility culling and chunk-based rendering with `TileLayerRenderer`
708
+ - **Camera system**: Centered/deadzone follow, lerp smoothing, screen-shake, and bounds clamping with `Camera`
707
709
  - **Animation**: Frame-based sprite animation with `AnimationPlayer`
710
+ - **Particle system**: Configurable particle emitters with shapes, color transitions, alpha fades, gravity, and batch rendering with `ParticleSystem` + `SpriteBatchRenderer`
708
711
  - **Collision (tile-based)**: Polygon collision detection for tilemaps with slide, platformer, and RPG movement modes via `CollisionRunner`
709
712
  - **Collision (object-to-object)**: Spatial-grid mixed-shape collision detection (rect, circle, capsule, polygon) with layer filtering via `ObjectCollisionManager`
710
713
  - **Capsule support**: Full capsule collision against all shape types
@@ -713,16 +716,22 @@ Standalone parser/loader for tilemap-editor JSON maps, sprite animations, and co
713
716
  ## Quick Start
714
717
 
715
718
  ```python
716
- from tilemap_parser import load_map, TileLayerRenderer
719
+ from tilemap_parser import load_map, TileLayerRenderer, Camera
717
720
 
721
+ # Load map and set up renderer
718
722
  game_data = load_map("path/to/map.json")
719
723
  renderer = TileLayerRenderer(game_data)
724
+
725
+ # Set up camera
726
+ camera = Camera(800, 600, mode="centered")
727
+ camera.follow(player)
720
728
  ```
721
729
 
722
730
  ```python
723
731
  from tilemap_parser import (
724
732
  CollisionRunner, CollisionCache,
725
733
  ObjectCollisionManager, CircleShape, RectangleShape,
734
+ ParticleSystem, ParticleSystemConfig
726
735
  )
727
736
 
728
737
  # Tile-based collision
@@ -735,10 +744,29 @@ manager = ObjectCollisionManager()
735
744
  manager.add_object(player)
736
745
  for hit in manager.check_all_collisions():
737
746
  hit.resolve() # separate both objects
747
+
748
+ # Particle system
749
+ particle_config = ParticleSystemConfig(
750
+ particle_shape="circle",
751
+ spawn_rate=10.0,
752
+ max_particles=100,
753
+ lifetime_min=0.5,
754
+ lifetime_max=2.0,
755
+ speed_min=50,
756
+ speed_max=100,
757
+ direction=270,
758
+ spread=45,
759
+ start_color_r=255, start_color_g=200, start_color_b=100, start_color_a=255,
760
+ end_color_r=255, end_color_g=100, end_color_b=50, end_color_a=0,
761
+ alpha_fade="fade_out",
762
+ gravity_x=0,
763
+ gravity_y=50,
764
+ )
765
+ particles = ParticleSystem(particle_config)
738
766
  ```
739
767
 
740
768
  ## Links
741
769
 
742
- - **Docs**: https://tilemap-parser.vercel.app/
770
+ - **Docs**: [https://deepwiki.com/FluffyBrudy/tilemap-parser](https://deepwiki.com/FluffyBrudy/tilemap-parser)
743
771
  - **Editor**: https://pypi.org/project/tilemap-editor/
744
772
  - **Repository**: https://github.com/FluffyBrudy/tilemap-parser
@@ -5,7 +5,10 @@ Standalone parser/loader for tilemap-editor JSON maps, sprite animations, and co
5
5
  ## Features
6
6
 
7
7
  - **Map parsing**: Load and query tilemaps, layers, objects, and autotile data from JSON
8
+ - **Chunked tile rendering**: Efficient visibility culling and chunk-based rendering with `TileLayerRenderer`
9
+ - **Camera system**: Centered/deadzone follow, lerp smoothing, screen-shake, and bounds clamping with `Camera`
8
10
  - **Animation**: Frame-based sprite animation with `AnimationPlayer`
11
+ - **Particle system**: Configurable particle emitters with shapes, color transitions, alpha fades, gravity, and batch rendering with `ParticleSystem` + `SpriteBatchRenderer`
9
12
  - **Collision (tile-based)**: Polygon collision detection for tilemaps with slide, platformer, and RPG movement modes via `CollisionRunner`
10
13
  - **Collision (object-to-object)**: Spatial-grid mixed-shape collision detection (rect, circle, capsule, polygon) with layer filtering via `ObjectCollisionManager`
11
14
  - **Capsule support**: Full capsule collision against all shape types
@@ -14,16 +17,22 @@ Standalone parser/loader for tilemap-editor JSON maps, sprite animations, and co
14
17
  ## Quick Start
15
18
 
16
19
  ```python
17
- from tilemap_parser import load_map, TileLayerRenderer
20
+ from tilemap_parser import load_map, TileLayerRenderer, Camera
18
21
 
22
+ # Load map and set up renderer
19
23
  game_data = load_map("path/to/map.json")
20
24
  renderer = TileLayerRenderer(game_data)
25
+
26
+ # Set up camera
27
+ camera = Camera(800, 600, mode="centered")
28
+ camera.follow(player)
21
29
  ```
22
30
 
23
31
  ```python
24
32
  from tilemap_parser import (
25
33
  CollisionRunner, CollisionCache,
26
34
  ObjectCollisionManager, CircleShape, RectangleShape,
35
+ ParticleSystem, ParticleSystemConfig
27
36
  )
28
37
 
29
38
  # Tile-based collision
@@ -36,10 +45,29 @@ manager = ObjectCollisionManager()
36
45
  manager.add_object(player)
37
46
  for hit in manager.check_all_collisions():
38
47
  hit.resolve() # separate both objects
48
+
49
+ # Particle system
50
+ particle_config = ParticleSystemConfig(
51
+ particle_shape="circle",
52
+ spawn_rate=10.0,
53
+ max_particles=100,
54
+ lifetime_min=0.5,
55
+ lifetime_max=2.0,
56
+ speed_min=50,
57
+ speed_max=100,
58
+ direction=270,
59
+ spread=45,
60
+ start_color_r=255, start_color_g=200, start_color_b=100, start_color_a=255,
61
+ end_color_r=255, end_color_g=100, end_color_b=50, end_color_a=0,
62
+ alpha_fade="fade_out",
63
+ gravity_x=0,
64
+ gravity_y=50,
65
+ )
66
+ particles = ParticleSystem(particle_config)
39
67
  ```
40
68
 
41
69
  ## Links
42
70
 
43
- - **Docs**: https://tilemap-parser.vercel.app/
71
+ - **Docs**: [https://deepwiki.com/FluffyBrudy/tilemap-parser](https://deepwiki.com/FluffyBrudy/tilemap-parser)
44
72
  - **Editor**: https://pypi.org/project/tilemap-editor/
45
73
  - **Repository**: https://github.com/FluffyBrudy/tilemap-parser
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "tilemap-parser"
7
- version = "3.1.23"
7
+ version = "4.1.0"
8
8
  description = "Standalone parser/loader for tilemap-editor JSON maps, sprite animations, and collision detection runtime."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -46,6 +46,7 @@ from .map_parse import (
46
46
  parse_map_json,
47
47
  )
48
48
  from .node_parse import ParsedNode, parse_nodes_dict, parse_nodes_file
49
+ from .tmx_converter import TmxParseError, parse_tmx_file, parse_tsx_file
49
50
  from .particle import (
50
51
  ALPHA_FADE_MODES,
51
52
  EMISSION_SHAPES,
@@ -84,6 +85,7 @@ __all__ = [
84
85
  "TilesetAnimation",
85
86
  "TileCollisionData",
86
87
  "TilesetCollision",
88
+ "TmxParseError",
87
89
  "parse_animation_dict",
88
90
  "parse_animation_file",
89
91
  "parse_animation_json",
@@ -96,6 +98,8 @@ __all__ = [
96
98
  "parse_map_json",
97
99
  "parse_nodes_dict",
98
100
  "parse_nodes_file",
101
+ "parse_tmx_file",
102
+ "parse_tsx_file",
99
103
  "parse_object_collision",
100
104
  "parse_tileset_collision",
101
105
  "ALPHA_FADE_MODES",
@@ -77,6 +77,44 @@ class TilesetCollision:
77
77
  return []
78
78
  return [shape.transform(tile_x, tile_y, scale) for shape in tile_data.shapes]
79
79
 
80
+ @classmethod
81
+ def merge(
82
+ cls,
83
+ collisions: List["TilesetCollision"],
84
+ firstgids: List[int],
85
+ ) -> "TilesetCollision":
86
+ """Merge multiple tileset collisions into one, offsetting keys by firstgid.
87
+
88
+ Each collision's tiles are re-keyed as ``firstgid + local_id`` so that
89
+ the resulting dict uses global tile IDs for lookup.
90
+
91
+ Args:
92
+ collisions: List of TilesetCollision objects to merge.
93
+ firstgids: List of firstgid offsets, one per collision, in the
94
+ same order as *collisions*. The offset is added to
95
+ each tile's local ID to produce the global key.
96
+
97
+ Usage::
98
+
99
+ merged = TilesetCollision.merge([ts0, ts1], [0, 200])
100
+ """
101
+ if not collisions:
102
+ return cls(tileset_name="merged", tile_size=(0, 0))
103
+ tile_size = collisions[0].tile_size
104
+ merged_tiles: Dict[int, TileCollisionData] = {}
105
+ for coll, offset in zip(collisions, firstgids, strict=True):
106
+ for local_id, data in coll.tiles.items():
107
+ gid = offset + local_id
108
+ merged_tiles[gid] = TileCollisionData(
109
+ tile_id=gid,
110
+ shapes=data.shapes[:],
111
+ )
112
+ return cls(
113
+ tileset_name="merged",
114
+ tile_size=tile_size,
115
+ tiles=merged_tiles,
116
+ )
117
+
80
118
 
81
119
  @dataclass
82
120
  class RectangleShape:
@@ -211,7 +249,7 @@ def parse_tileset_collision(data: JsonDict) -> TilesetCollision:
211
249
  tiles[tile_id] = TileCollisionData(tile_id=tile_id, shapes=shapes)
212
250
 
213
251
  return TilesetCollision(
214
- tileset_name=tileset_name, tile_size=tile_size, tiles=tiles
252
+ tileset_name=tileset_name, tile_size=tile_size, tiles=tiles,
215
253
  )
216
254
  except (KeyError, ValueError, TypeError) as e:
217
255
  raise CollisionParseError(f"Invalid tileset collision data: {e}") from e
@@ -105,7 +105,12 @@ class ParsedTile:
105
105
  pos: Point
106
106
  ttype: TilesetRef
107
107
  variant: int
108
+ gid: Optional[int] = None
108
109
  properties: Optional[JsonDict] = None
110
+ flip_h: bool = False
111
+ flip_v: bool = False
112
+ flip_d: bool = False
113
+ rotated_hex120: bool = False
109
114
 
110
115
 
111
116
  @dataclass
@@ -138,6 +143,8 @@ class TilesetAnimation:
138
143
  class ParsedTileset:
139
144
  path: str
140
145
  type: str
146
+ tile_count: int = 0
147
+ firstgid: int = 0
141
148
  properties: JsonDict = field(default_factory=dict)
142
149
  tile_properties: Dict[str, JsonDict] = field(default_factory=dict)
143
150
  animation: Optional[TilesetAnimation] = None
@@ -213,7 +220,19 @@ def _parse_tile(tile_data: JsonDict, ctx: str) -> ParsedTile:
213
220
  else:
214
221
  ttype = _coerce_int(ttype_raw, f"{ctx}.ttype")
215
222
  props = _optional_dict(tile_data.get("properties"), f"{ctx}.properties")
216
- return ParsedTile(pos=pos, ttype=ttype, variant=variant, properties=props)
223
+ gid_raw = tile_data.get("gid")
224
+ gid = _coerce_int(gid_raw, f"{ctx}.gid") if gid_raw is not None else None
225
+ return ParsedTile(
226
+ pos=pos,
227
+ ttype=ttype,
228
+ variant=variant,
229
+ gid=gid,
230
+ properties=props,
231
+ flip_h=tile_data.get("flip_h", False),
232
+ flip_v=tile_data.get("flip_v", False),
233
+ flip_d=tile_data.get("flip_d", False),
234
+ rotated_hex120=tile_data.get("rotated_hex120", False),
235
+ )
217
236
 
218
237
 
219
238
  def _parse_tiles(tiles_obj: JsonDict, ctx: str) -> Dict[Point, ParsedTile]:
@@ -365,6 +384,8 @@ def _parse_tilesets_list(tilesets_raw: List[Any], ctx: str) -> List[ParsedTilese
365
384
  ParsedTileset(
366
385
  path=path, type=ts_type, properties=props, tile_properties=tile_props,
367
386
  animation=animation,
387
+ tile_count=_coerce_int(ts_obj.get("tile_count", 0), f"{ctx}[{i}].tile_count"),
388
+ firstgid=_coerce_int(ts_obj.get("firstgid", 0), f"{ctx}[{i}].firstgid"),
368
389
  )
369
390
  )
370
391
  return out
@@ -484,8 +505,13 @@ def parse_map_file(path: Union[str, Path]) -> ParsedMap:
484
505
  p = Path(path)
485
506
  if not p.is_file():
486
507
  raise MapParseError(f"Not a file: {p}")
487
- if p.suffix.lower() != ".json":
488
- raise MapParseError(f"Expected .json map file, got {p.suffix!r}")
508
+ suffix = p.suffix.lower()
509
+ if suffix == ".tmx":
510
+ from .tmx_converter import parse_tmx_file
511
+
512
+ return parse_tmx_file(p)
513
+ if suffix != ".json":
514
+ raise MapParseError(f"Expected .json or .tmx map file, got {suffix!r}")
489
515
  try:
490
516
  text = p.read_text(encoding="utf-8")
491
517
  except OSError as e: