tilemap-parser 3.1.8__tar.gz → 3.1.9__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 (33) hide show
  1. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/PKG-INFO +1 -1
  2. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/pyproject.toml +1 -1
  3. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/src/tilemap_parser/parser/__init__.py +2 -0
  4. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/src/tilemap_parser/parser/map_parse.py +23 -1
  5. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/src/tilemap_parser/runtime/map_loader.py +13 -0
  6. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/src/tilemap_parser/runtime/renderer.py +41 -1
  7. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/src/tilemap_parser.egg-info/PKG-INFO +1 -1
  8. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/LICENSE +0 -0
  9. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/README.md +0 -0
  10. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/setup.cfg +0 -0
  11. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/src/tilemap_parser/__init__.py +0 -0
  12. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/src/tilemap_parser/parser/animation.py +0 -0
  13. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/src/tilemap_parser/parser/collision.py +0 -0
  14. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/src/tilemap_parser/parser/collision_loader.py +0 -0
  15. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/src/tilemap_parser/parser/node_parse.py +0 -0
  16. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/src/tilemap_parser/runtime/__init__.py +0 -0
  17. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/src/tilemap_parser/runtime/animation_player.py +0 -0
  18. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/src/tilemap_parser/runtime/area_node.py +0 -0
  19. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/src/tilemap_parser/runtime/collision_cache.py +0 -0
  20. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/src/tilemap_parser/runtime/object_collision.py +0 -0
  21. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/src/tilemap_parser/runtime/tile_collision.py +0 -0
  22. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/src/tilemap_parser/utils/__init__.py +0 -0
  23. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/src/tilemap_parser/utils/geometry.py +0 -0
  24. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/src/tilemap_parser.egg-info/SOURCES.txt +0 -0
  25. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/src/tilemap_parser.egg-info/dependency_links.txt +0 -0
  26. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/src/tilemap_parser.egg-info/requires.txt +0 -0
  27. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/src/tilemap_parser.egg-info/top_level.txt +0 -0
  28. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/tests/test_collision.py +0 -0
  29. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/tests/test_geometry.py +0 -0
  30. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/tests/test_map_loader.py +0 -0
  31. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/tests/test_object_collision.py +0 -0
  32. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/tests/test_render_scale.py +0 -0
  33. {tilemap_parser-3.1.8 → tilemap_parser-3.1.9}/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.8
3
+ Version: 3.1.9
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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "tilemap-parser"
7
- version = "3.1.8"
7
+ version = "3.1.9"
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"
@@ -40,6 +40,7 @@ from .map_parse import (
40
40
  ParsedProjectState,
41
41
  ParsedTile,
42
42
  ParsedTileset,
43
+ TilesetAnimation,
43
44
  parse_map_dict,
44
45
  parse_map_file,
45
46
  parse_map_json,
@@ -72,6 +73,7 @@ __all__ = [
72
73
  "ParsedTile",
73
74
  "ParsedTileset",
74
75
  "RectangleShape",
76
+ "TilesetAnimation",
75
77
  "TileCollisionData",
76
78
  "TilesetCollision",
77
79
  "parse_animation_dict",
@@ -125,12 +125,22 @@ class ParsedObject:
125
125
  properties: Optional[JsonDict] = None
126
126
 
127
127
 
128
+ @dataclass
129
+ class TilesetAnimation:
130
+ frame_count: int
131
+ frame_duration_ms: float
132
+ frame_stride: int
133
+ loop: bool = True
134
+ animation_mode: str = "default"
135
+
136
+
128
137
  @dataclass
129
138
  class ParsedTileset:
130
139
  path: str
131
140
  type: str
132
141
  properties: JsonDict = field(default_factory=dict)
133
142
  tile_properties: Dict[str, JsonDict] = field(default_factory=dict)
143
+ animation: Optional[TilesetAnimation] = None
134
144
 
135
145
 
136
146
  @dataclass
@@ -340,9 +350,21 @@ def _parse_tilesets_list(tilesets_raw: List[Any], ctx: str) -> List[ParsedTilese
340
350
  tile_props[str(k)] = _require_dict(
341
351
  v, f"{ctx}[{i}].tile_properties[{k!r}]"
342
352
  )
353
+ animation = None
354
+ animation_raw = ts_obj.get("animation")
355
+ if animation_raw is not None:
356
+ anim_obj = _require_dict(animation_raw, f"{ctx}[{i}].animation")
357
+ animation = TilesetAnimation(
358
+ frame_count=_coerce_int(anim_obj.get("frame_count"), f"{ctx}[{i}].animation.frame_count"),
359
+ frame_duration_ms=_coerce_float(anim_obj.get("frame_duration_ms"), f"{ctx}[{i}].animation.frame_duration_ms"),
360
+ frame_stride=_coerce_int(anim_obj.get("frame_stride"), f"{ctx}[{i}].animation.frame_stride"),
361
+ loop=_coerce_bool(anim_obj.get("loop", True), f"{ctx}[{i}].animation.loop"),
362
+ animation_mode=_require_str(anim_obj.get("animation_mode", "default"), f"{ctx}[{i}].animation.animation_mode"),
363
+ )
343
364
  out.append(
344
365
  ParsedTileset(
345
- path=path, type=ts_type, properties=props, tile_properties=tile_props
366
+ path=path, type=ts_type, properties=props, tile_properties=tile_props,
367
+ animation=animation,
346
368
  )
347
369
  )
348
370
  return out
@@ -198,6 +198,19 @@ class TilemapData:
198
198
  return None
199
199
  return self.get_tile_surface(tile.ttype, tile.variant)
200
200
 
201
+ def get_tileset_animation(self, ttype: int) -> Optional[dict]:
202
+ if 0 <= ttype < len(self.parsed.tilesets):
203
+ anim = self.parsed.tilesets[ttype].animation
204
+ if anim is not None:
205
+ return {
206
+ "frame_count": anim.frame_count,
207
+ "frame_duration_ms": anim.frame_duration_ms,
208
+ "frame_stride": anim.frame_stride,
209
+ "loop": anim.loop,
210
+ "animation_mode": anim.animation_mode,
211
+ }
212
+ return None
213
+
201
214
 
202
215
  def _variant_surface(
203
216
  surf: Surface,
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  from dataclasses import dataclass
4
4
  from typing import Dict, Optional, Tuple, Union
5
5
 
6
+ import pygame
6
7
  from pygame import Rect, Surface, transform
7
8
 
8
9
  from .map_loader import TilemapData
@@ -40,6 +41,17 @@ class TileLayerRenderer:
40
41
  f"got tile_size=({self._tile_w}, {self._tile_h}) render_scale={self._rs}"
41
42
  )
42
43
 
44
+ self._tileset_animations: Dict[int, dict] = {}
45
+ for ts_idx, ts in enumerate(data.parsed.tilesets):
46
+ if ts.animation is not None:
47
+ self._tileset_animations[ts_idx] = {
48
+ "frame_count": ts.animation.frame_count,
49
+ "frame_duration_ms": ts.animation.frame_duration_ms,
50
+ "frame_stride": ts.animation.frame_stride,
51
+ "loop": ts.animation.loop,
52
+ "animation_mode": ts.animation.animation_mode,
53
+ }
54
+
43
55
  def get_layer_dict(self) -> Dict[int, object]:
44
56
  return dict(self.tile_layers)
45
57
 
@@ -62,11 +74,32 @@ class TileLayerRenderer:
62
74
  self._get_cached_variant(tile.ttype, tile.variant)
63
75
  self.data = None
64
76
 
77
+ def _compute_display_variant(
78
+ self,
79
+ variant: int,
80
+ ttype: int,
81
+ x: int,
82
+ y: int,
83
+ time_ms: int,
84
+ ) -> int:
85
+ anim = self._tileset_animations.get(ttype)
86
+ if anim is None:
87
+ return variant
88
+ stride = anim["frame_stride"]
89
+ frame_count = anim["frame_count"]
90
+ frame_idx = int(time_ms / anim["frame_duration_ms"]) % frame_count
91
+ if anim.get("animation_mode") == "random_start_times":
92
+ phase = hash((x, y, ttype)) % frame_count
93
+ frame_idx = (frame_idx + phase) % frame_count
94
+ return variant + frame_idx * stride
95
+
65
96
  def render(
66
97
  self,
67
98
  target: Surface,
68
99
  camera_xy: Union[Tuple[float, float], Tuple[int, int]] = (0, 0),
69
100
  viewport_size: Optional[Tuple[int, int]] = None,
101
+ *,
102
+ current_time_ms: Optional[float] = None,
70
103
  ) -> LayerRenderStats:
71
104
  cam_x, cam_y = float(camera_xy[0]), float(camera_xy[1])
72
105
  if viewport_size is None:
@@ -79,6 +112,10 @@ class TileLayerRenderer:
79
112
  min_y = int(cam_y // self._eff_h) - 1
80
113
  max_y = int((cam_y + viewport.height) // self._eff_h) + 1
81
114
 
115
+ if current_time_ms is None:
116
+ current_time_ms = pygame.time.get_ticks()
117
+ time_ms = int(current_time_ms)
118
+
82
119
  drawn = 0
83
120
  skipped = 0
84
121
  visible_layers = 0
@@ -95,7 +132,10 @@ class TileLayerRenderer:
95
132
  if not isinstance(tile.ttype, int):
96
133
  skipped += 1
97
134
  continue
98
- cell = self._get_cached_variant(tile.ttype, tile.variant)
135
+ display_variant = self._compute_display_variant(
136
+ tile.variant, tile.ttype, x, y, time_ms
137
+ )
138
+ cell = self._get_cached_variant(tile.ttype, display_variant)
99
139
  if cell is None:
100
140
  skipped += 1
101
141
  continue
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tilemap-parser
3
- Version: 3.1.8
3
+ Version: 3.1.9
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
File without changes
File without changes
File without changes