tilemap-parser 4.0.0__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.
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/PKG-INFO +31 -3
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/README.md +30 -2
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/pyproject.toml +1 -1
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/src/tilemap_parser/parser/__init__.py +4 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/src/tilemap_parser/parser/collision.py +39 -1
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/src/tilemap_parser/parser/map_parse.py +29 -3
- tilemap_parser-4.1.0/src/tilemap_parser/parser/tmx_converter.py +447 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/src/tilemap_parser/runtime/map_loader.py +21 -1
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/src/tilemap_parser.egg-info/PKG-INFO +31 -3
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/src/tilemap_parser.egg-info/SOURCES.txt +4 -1
- tilemap_parser-4.1.0/tests/test_gid_collision.py +260 -0
- tilemap_parser-4.1.0/tests/test_tmx_converter.py +442 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/LICENSE +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/setup.cfg +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/src/tilemap_parser/__init__.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/src/tilemap_parser/parser/animation.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/src/tilemap_parser/parser/collision_loader.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/src/tilemap_parser/parser/node_parse.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/src/tilemap_parser/parser/particle.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/src/tilemap_parser/runtime/__init__.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/src/tilemap_parser/runtime/animation_player.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/src/tilemap_parser/runtime/area_node.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/src/tilemap_parser/runtime/camera.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/src/tilemap_parser/runtime/collision_cache.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/src/tilemap_parser/runtime/object_collision.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/src/tilemap_parser/runtime/particles.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/src/tilemap_parser/runtime/renderer.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/src/tilemap_parser/runtime/tile_collision.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/src/tilemap_parser/utils/__init__.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/src/tilemap_parser/utils/geometry.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/src/tilemap_parser.egg-info/dependency_links.txt +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/src/tilemap_parser.egg-info/requires.txt +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/src/tilemap_parser.egg-info/top_level.txt +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/tests/test_camera.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/tests/test_collision.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/tests/test_geometry.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/tests/test_integration_animation.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/tests/test_integration_collision.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/tests/test_integration_map_loader.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/tests/test_map_loader.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/tests/test_move_grounded.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/tests/test_object_collision.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/tests/test_object_surfaces.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/tests/test_particle_emitter.py +0 -0
- {tilemap_parser-4.0.0 → tilemap_parser-4.1.0}/tests/test_render_scale.py +0 -0
- {tilemap_parser-4.0.0 → 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: 4.
|
|
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.
|
|
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.
|
|
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 = "4.
|
|
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
|
-
|
|
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
|
-
|
|
488
|
-
|
|
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:
|