tilemap-parser 3.1.7__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.
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/PKG-INFO +1 -1
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/pyproject.toml +1 -1
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/src/tilemap_parser/__init__.py +4 -0
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/src/tilemap_parser/parser/__init__.py +6 -0
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/src/tilemap_parser/parser/map_parse.py +29 -2
- tilemap_parser-3.1.9/src/tilemap_parser/parser/node_parse.py +77 -0
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/src/tilemap_parser/runtime/__init__.py +2 -0
- tilemap_parser-3.1.9/src/tilemap_parser/runtime/area_node.py +38 -0
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/src/tilemap_parser/runtime/map_loader.py +36 -0
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/src/tilemap_parser/runtime/renderer.py +41 -1
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/src/tilemap_parser.egg-info/PKG-INFO +1 -1
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/src/tilemap_parser.egg-info/SOURCES.txt +2 -0
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/LICENSE +0 -0
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/README.md +0 -0
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/setup.cfg +0 -0
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/src/tilemap_parser/parser/animation.py +0 -0
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/src/tilemap_parser/parser/collision.py +0 -0
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/src/tilemap_parser/parser/collision_loader.py +0 -0
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/src/tilemap_parser/runtime/animation_player.py +0 -0
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/src/tilemap_parser/runtime/collision_cache.py +0 -0
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/src/tilemap_parser/runtime/object_collision.py +0 -0
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/src/tilemap_parser/runtime/tile_collision.py +0 -0
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/src/tilemap_parser/utils/__init__.py +0 -0
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/src/tilemap_parser/utils/geometry.py +0 -0
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/src/tilemap_parser.egg-info/dependency_links.txt +0 -0
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/src/tilemap_parser.egg-info/requires.txt +0 -0
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/src/tilemap_parser.egg-info/top_level.txt +0 -0
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/tests/test_collision.py +0 -0
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/tests/test_geometry.py +0 -0
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/tests/test_map_loader.py +0 -0
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/tests/test_object_collision.py +0 -0
- {tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/tests/test_render_scale.py +0 -0
- {tilemap_parser-3.1.7 → 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.
|
|
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.
|
|
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"
|
|
@@ -9,6 +9,7 @@ __all__ = [
|
|
|
9
9
|
"AnimationMarker",
|
|
10
10
|
"AnimationParseError",
|
|
11
11
|
"AnimationPlayer",
|
|
12
|
+
"AreaNode",
|
|
12
13
|
"CapsuleShape",
|
|
13
14
|
"CharacterCollision",
|
|
14
15
|
"CircleShape",
|
|
@@ -32,6 +33,7 @@ __all__ = [
|
|
|
32
33
|
"ParsedLayer",
|
|
33
34
|
"ParsedMap",
|
|
34
35
|
"ParsedMeta",
|
|
36
|
+
"ParsedNode",
|
|
35
37
|
"ParsedObject",
|
|
36
38
|
"ParsedObjectArea",
|
|
37
39
|
"ParsedProjectState",
|
|
@@ -62,6 +64,8 @@ __all__ = [
|
|
|
62
64
|
"parse_map_dict",
|
|
63
65
|
"parse_map_file",
|
|
64
66
|
"parse_map_json",
|
|
67
|
+
"parse_nodes_dict",
|
|
68
|
+
"parse_nodes_file",
|
|
65
69
|
"parse_object_collision",
|
|
66
70
|
"parse_tileset_collision",
|
|
67
71
|
"polygon_vs_circle",
|
|
@@ -40,10 +40,12 @@ 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,
|
|
46
47
|
)
|
|
48
|
+
from .node_parse import ParsedNode, parse_nodes_dict, parse_nodes_file
|
|
47
49
|
|
|
48
50
|
__all__ = [
|
|
49
51
|
"AnimationClip",
|
|
@@ -60,6 +62,7 @@ __all__ = [
|
|
|
60
62
|
"ObjectCollisionData",
|
|
61
63
|
"ObjectCollisionRegionData",
|
|
62
64
|
"ParsedAutotileGroup",
|
|
65
|
+
"ParsedNode",
|
|
63
66
|
"ParsedAutotileRule",
|
|
64
67
|
"ParsedLayer",
|
|
65
68
|
"ParsedMap",
|
|
@@ -70,6 +73,7 @@ __all__ = [
|
|
|
70
73
|
"ParsedTile",
|
|
71
74
|
"ParsedTileset",
|
|
72
75
|
"RectangleShape",
|
|
76
|
+
"TilesetAnimation",
|
|
73
77
|
"TileCollisionData",
|
|
74
78
|
"TilesetCollision",
|
|
75
79
|
"parse_animation_dict",
|
|
@@ -82,6 +86,8 @@ __all__ = [
|
|
|
82
86
|
"parse_map_dict",
|
|
83
87
|
"parse_map_file",
|
|
84
88
|
"parse_map_json",
|
|
89
|
+
"parse_nodes_dict",
|
|
90
|
+
"parse_nodes_file",
|
|
85
91
|
"parse_object_collision",
|
|
86
92
|
"parse_tileset_collision",
|
|
87
93
|
]
|
|
@@ -5,7 +5,10 @@ import re
|
|
|
5
5
|
import string
|
|
6
6
|
from dataclasses import dataclass, field
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from .node_parse import ParsedNode
|
|
9
12
|
|
|
10
13
|
JsonDict = Dict[str, Any]
|
|
11
14
|
Point = Tuple[int, int]
|
|
@@ -122,12 +125,22 @@ class ParsedObject:
|
|
|
122
125
|
properties: Optional[JsonDict] = None
|
|
123
126
|
|
|
124
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
|
+
|
|
125
137
|
@dataclass
|
|
126
138
|
class ParsedTileset:
|
|
127
139
|
path: str
|
|
128
140
|
type: str
|
|
129
141
|
properties: JsonDict = field(default_factory=dict)
|
|
130
142
|
tile_properties: Dict[str, JsonDict] = field(default_factory=dict)
|
|
143
|
+
animation: Optional[TilesetAnimation] = None
|
|
131
144
|
|
|
132
145
|
|
|
133
146
|
@dataclass
|
|
@@ -187,6 +200,8 @@ class ParsedMap:
|
|
|
187
200
|
tilesets: List[ParsedTileset]
|
|
188
201
|
project_state: ParsedProjectState
|
|
189
202
|
raw: JsonDict
|
|
203
|
+
nodes: List["ParsedNode"] = field(default_factory=list)
|
|
204
|
+
node_groups: List[str] = field(default_factory=list)
|
|
190
205
|
|
|
191
206
|
|
|
192
207
|
def _parse_tile(tile_data: JsonDict, ctx: str) -> ParsedTile:
|
|
@@ -335,9 +350,21 @@ def _parse_tilesets_list(tilesets_raw: List[Any], ctx: str) -> List[ParsedTilese
|
|
|
335
350
|
tile_props[str(k)] = _require_dict(
|
|
336
351
|
v, f"{ctx}[{i}].tile_properties[{k!r}]"
|
|
337
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
|
+
)
|
|
338
364
|
out.append(
|
|
339
365
|
ParsedTileset(
|
|
340
|
-
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,
|
|
341
368
|
)
|
|
342
369
|
)
|
|
343
370
|
return out
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any, Dict, List, Optional, Union
|
|
7
|
+
|
|
8
|
+
from .map_parse import (
|
|
9
|
+
JsonDict,
|
|
10
|
+
MapParseError,
|
|
11
|
+
ParsedObjectArea,
|
|
12
|
+
_coerce_bool,
|
|
13
|
+
_coerce_float,
|
|
14
|
+
_coerce_int,
|
|
15
|
+
_optional_dict,
|
|
16
|
+
_require_dict,
|
|
17
|
+
_require_list,
|
|
18
|
+
_require_str,
|
|
19
|
+
_ctx,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class ParsedNode:
|
|
25
|
+
node_id: str
|
|
26
|
+
name: str
|
|
27
|
+
node_type: str
|
|
28
|
+
area: ParsedObjectArea
|
|
29
|
+
layer_name: str
|
|
30
|
+
properties: JsonDict = field(default_factory=dict)
|
|
31
|
+
group: Optional[str] = None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _parse_area(raw: Any, ctx: str) -> ParsedObjectArea:
|
|
35
|
+
d = _require_dict(raw, ctx)
|
|
36
|
+
return ParsedObjectArea(
|
|
37
|
+
x=_coerce_int(d.get("x"), f"{ctx}.x"),
|
|
38
|
+
y=_coerce_int(d.get("y"), f"{ctx}.y"),
|
|
39
|
+
w=_coerce_int(d.get("w"), f"{ctx}.w"),
|
|
40
|
+
h=_coerce_int(d.get("h"), f"{ctx}.h"),
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _parse_node(raw: Any, ctx: str) -> ParsedNode:
|
|
45
|
+
d = _require_dict(raw, ctx)
|
|
46
|
+
group_raw = d.get("group")
|
|
47
|
+
group = str(group_raw) if group_raw is not None else None
|
|
48
|
+
return ParsedNode(
|
|
49
|
+
node_id=_require_str(d.get("node_id"), f"{ctx}.node_id"),
|
|
50
|
+
name=_require_str(d.get("name"), f"{ctx}.name"),
|
|
51
|
+
node_type=_require_str(d.get("node_type", "area"), f"{ctx}.node_type"),
|
|
52
|
+
area=_parse_area(d.get("area"), f"{ctx}.area"),
|
|
53
|
+
layer_name=_require_str(d.get("layer_name", ""), f"{ctx}.layer_name"),
|
|
54
|
+
properties=_optional_dict(d.get("properties"), f"{ctx}.properties") or {},
|
|
55
|
+
group=group,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def parse_nodes_dict(root: JsonDict) -> List[ParsedNode]:
|
|
60
|
+
root = _require_dict(root, "root")
|
|
61
|
+
raw_nodes = _require_list(root.get("nodes", []), "root.nodes")
|
|
62
|
+
return [_parse_node(item, f"root.nodes[{i}]") for i, item in enumerate(raw_nodes)]
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def parse_nodes_file(path: Union[str, Path]) -> List[ParsedNode]:
|
|
66
|
+
p = Path(path)
|
|
67
|
+
if not p.is_file():
|
|
68
|
+
raise MapParseError(f"Not a file: {p}")
|
|
69
|
+
try:
|
|
70
|
+
text = p.read_text(encoding="utf-8")
|
|
71
|
+
except OSError as e:
|
|
72
|
+
raise MapParseError(f"Cannot read {p}: {e}") from e
|
|
73
|
+
try:
|
|
74
|
+
payload = json.loads(text)
|
|
75
|
+
except json.JSONDecodeError as e:
|
|
76
|
+
raise MapParseError(f"Invalid JSON in {p}: {e}") from e
|
|
77
|
+
return parse_nodes_dict(payload)
|
|
@@ -23,9 +23,11 @@ from .object_collision import (
|
|
|
23
23
|
check_collision,
|
|
24
24
|
)
|
|
25
25
|
from .renderer import LayerRenderStats, TileLayerRenderer
|
|
26
|
+
from .area_node import AreaNode
|
|
26
27
|
|
|
27
28
|
__all__ = [
|
|
28
29
|
"AnimationPlayer",
|
|
30
|
+
"AreaNode",
|
|
29
31
|
"CollisionCache",
|
|
30
32
|
"CollisionHit",
|
|
31
33
|
"CollisionResult",
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Optional, Tuple
|
|
4
|
+
|
|
5
|
+
from pygame import Rect
|
|
6
|
+
|
|
7
|
+
from ..parser.node_parse import ParsedNode
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AreaNode:
|
|
11
|
+
def __init__(self, parsed: ParsedNode) -> None:
|
|
12
|
+
self.node_id = parsed.node_id
|
|
13
|
+
self.name = parsed.name
|
|
14
|
+
self.node_type = parsed.node_type
|
|
15
|
+
self._rect = Rect(parsed.area.x, parsed.area.y, parsed.area.w, parsed.area.h)
|
|
16
|
+
self.layer_name = parsed.layer_name
|
|
17
|
+
self.properties = dict(parsed.properties)
|
|
18
|
+
self.group = parsed.group
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def rect(self) -> Rect:
|
|
22
|
+
return self._rect
|
|
23
|
+
|
|
24
|
+
@rect.setter
|
|
25
|
+
def rect(self, r: Rect) -> None:
|
|
26
|
+
self._rect = r
|
|
27
|
+
|
|
28
|
+
def contains_point(self, point: Tuple[float, float]) -> bool:
|
|
29
|
+
return self._rect.collidepoint(point)
|
|
30
|
+
|
|
31
|
+
def overlaps_rect(self, other: Rect) -> bool:
|
|
32
|
+
return self._rect.colliderect(other)
|
|
33
|
+
|
|
34
|
+
def __repr__(self) -> str:
|
|
35
|
+
return (
|
|
36
|
+
f"AreaNode(id={self.node_id!r}, name={self.name!r}, "
|
|
37
|
+
f"rect={self._rect}, layer={self.layer_name!r})"
|
|
38
|
+
)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import json
|
|
3
4
|
from copy import deepcopy
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
from typing import Dict, List, Optional, Tuple, Union
|
|
@@ -8,6 +9,7 @@ import pygame
|
|
|
8
9
|
from pygame import Rect, Surface
|
|
9
10
|
|
|
10
11
|
from ..parser.map_parse import MapParseError, ParsedLayer, ParsedMap, ParsedTile, parse_map_file
|
|
12
|
+
from ..parser.node_parse import parse_nodes_dict
|
|
11
13
|
|
|
12
14
|
PathLike = Union[str, Path]
|
|
13
15
|
|
|
@@ -66,6 +68,27 @@ class TilemapData:
|
|
|
66
68
|
raise MapParseError(msg) from e
|
|
67
69
|
surfaces.append(None)
|
|
68
70
|
|
|
71
|
+
nodes_name = f"{p.stem}.nodes.json"
|
|
72
|
+
nodes_candidates = [
|
|
73
|
+
map_dir / nodes_name,
|
|
74
|
+
map_dir.parent / "nodes" / nodes_name,
|
|
75
|
+
]
|
|
76
|
+
if extra_search_base is not None:
|
|
77
|
+
nodes_candidates.append(extra_search_base / "nodes" / nodes_name)
|
|
78
|
+
for nodes_path in nodes_candidates:
|
|
79
|
+
if nodes_path.is_file():
|
|
80
|
+
try:
|
|
81
|
+
nodes_text = nodes_path.read_text(encoding="utf-8")
|
|
82
|
+
nodes_raw = json.loads(nodes_text)
|
|
83
|
+
parsed.nodes = parse_nodes_dict(nodes_raw)
|
|
84
|
+
groups_raw = nodes_raw.get("groups", [])
|
|
85
|
+
if not isinstance(groups_raw, list):
|
|
86
|
+
raise MapParseError("root.groups must be a list")
|
|
87
|
+
parsed.node_groups = groups_raw
|
|
88
|
+
except (json.JSONDecodeError, OSError, MapParseError) as e:
|
|
89
|
+
warnings.append(f"Failed to load nodes: {e}")
|
|
90
|
+
break
|
|
91
|
+
|
|
69
92
|
return cls(parsed, surfaces, resolved_paths, warnings, map_path=p)
|
|
70
93
|
|
|
71
94
|
def _build_path_index(self) -> None:
|
|
@@ -175,6 +198,19 @@ class TilemapData:
|
|
|
175
198
|
return None
|
|
176
199
|
return self.get_tile_surface(tile.ttype, tile.variant)
|
|
177
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
|
+
|
|
178
214
|
|
|
179
215
|
def _variant_surface(
|
|
180
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
|
-
|
|
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.
|
|
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
|
|
@@ -12,8 +12,10 @@ src/tilemap_parser/parser/animation.py
|
|
|
12
12
|
src/tilemap_parser/parser/collision.py
|
|
13
13
|
src/tilemap_parser/parser/collision_loader.py
|
|
14
14
|
src/tilemap_parser/parser/map_parse.py
|
|
15
|
+
src/tilemap_parser/parser/node_parse.py
|
|
15
16
|
src/tilemap_parser/runtime/__init__.py
|
|
16
17
|
src/tilemap_parser/runtime/animation_player.py
|
|
18
|
+
src/tilemap_parser/runtime/area_node.py
|
|
17
19
|
src/tilemap_parser/runtime/collision_cache.py
|
|
18
20
|
src/tilemap_parser/runtime/map_loader.py
|
|
19
21
|
src/tilemap_parser/runtime/object_collision.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/src/tilemap_parser/runtime/animation_player.py
RENAMED
|
File without changes
|
|
File without changes
|
{tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/src/tilemap_parser/runtime/object_collision.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tilemap_parser-3.1.7 → tilemap_parser-3.1.9}/src/tilemap_parser.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|