Refactor UIEntity::grid to shared_ptr<GridData>; add entity.texture; closes #313
UIEntity now depends on the grid DATA layer only: - GridData gains cell_width_px/cell_height_px (mirrored from the grid texture in UIGrid's 5-arg ctor; texture is write-once) so entity tile<->pixel math no longer reaches into rendering (getTexture()). - GridData gains markDirty()/markCompositeDirty(): set the flag on the UIGrid subobject AND notify owning_view, covering both render paths. UIGrid disambiguates via 'using UIDrawable::markDirty' so all pre-existing UIGrid-receiver calls resolve exactly as before. - The three Python wrappers that still need the full UIGrid (GridPoint from entity.at(), the _GridData fallback in get_grid, find_path's temp wrapper) reconstruct it via a single aliasing-downcast helper (grid_as_uigrid) that documents the never-independently-allocated GridData invariant; init/set_grid simplify (share grid_data directly). Removing the casts is deferred to #252. entity.texture (new, frozen surface +1): thin get/set over the entity's own UISprite. Entities render with their OWN texture (default_texture fallback at construction); the grid's texture only determines cell size. Setter preserves sprite_index; rejects non-Texture (TypeError), null-data Texture wrappers (ValueError), and deletion. Adversarial review fixes folded in: - set_texture/get_texture guard uninitialized Entity wrappers (RuntimeError), isinstance errors, and null-data Textures. - PyUIGridViewType tp_dealloc no longer unconditionally severs GridData::owning_view: gated on last-owner (#251 use_count pattern) plus owning-view identity. Previously ANY Grid wrapper GC while the view lived (e.g. scene.children.append(mcrfpy.Grid(...))) silently broke entity.grid -> Grid identity and data-layer dirty notification. Tests: tests/regression/issue_313_entity_grid_data_test.py (texture semantics, grid-cell-size invariance, entity.grid identity, #251 gate survival, GridPoint outliving teardown, review-fix guards, owning_view survival) + tests/unit/entity_texture_test.py. API snapshot golden re-baselined: exactly +1 surface line (Entity.texture) + writability probe flip. Docs/stubs regenerated. Native + Emscripten builds verified. Known edges recorded in docs/api-audit-2026-04.md: texture read-back is a fresh wrapper each get (no Texture __eq__); sprite_index not re-validated against a new atlas. Multi-view markDirty broadcast and pure-GridData wrappers remain deferred to #252. Addresses #314. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
16adc92995
commit
2d2c333cd7
15 changed files with 428 additions and 60 deletions
|
|
@ -653,15 +653,15 @@ class Entity:
|
|||
"""A game entity that exists on a grid with sprite rendering."""
|
||||
def __init__(self, grid_pos=None, texture=None, sprite_index=0, **kwargs) -> None: ...
|
||||
behavior_type: int # Current behavior type (int, read-only). Use set_behavior() to change.
|
||||
cell_pos: Vector # Integer logical cell position (Vector). Decoupled from draw_pos. Determines which cell this entity logically occupies for collision, pathfinding, etc.
|
||||
cell_x: Any # Integer X cell coordinate.
|
||||
cell_y: Any # Integer Y cell coordinate.
|
||||
cell_pos: Vector # Integer logical cell position (Vector). Alias for grid_pos (the canonical name).
|
||||
cell_x: Any # Integer X cell coordinate. Alias for grid_x.
|
||||
cell_y: Any # Integer Y cell coordinate. Alias for grid_y.
|
||||
default_behavior: int # Default behavior type (int, maps to Behavior enum). Entity reverts to this after DONE trigger. Default: 0 (IDLE).
|
||||
draw_pos: Vector # Fractional tile position for rendering (Vector). Use for smooth animation between grid cells.
|
||||
grid: Any # Grid this entity belongs to. Get: Returns the Grid or None. Set: Assign a Grid to move entity, or None to remove from grid.
|
||||
grid_pos: Vector # Grid position as integer cell coordinates (Vector). Alias for cell_pos.
|
||||
grid_x: Any # Grid X position as integer cell coordinate. Alias for cell_x.
|
||||
grid_y: Any # Grid Y position as integer cell coordinate. Alias for cell_y.
|
||||
grid_pos: Vector # Integer logical cell position (Vector). Canonical cell-position property; matches the 'grid_pos' constructor argument. Decoupled from draw_pos. Determines wh...
|
||||
grid_x: Any # Integer X cell coordinate. Canonical; matches grid_pos.
|
||||
grid_y: Any # Integer Y cell coordinate. Canonical; matches grid_pos.
|
||||
labels: frozenset # Set of string labels for collision/targeting (frozenset). Assign any iterable of strings to replace all labels.
|
||||
move_speed: float # Animation duration for behavior movement in seconds (float). 0 = instant. Default: 0.15.
|
||||
name: Any # Name for finding elements
|
||||
|
|
@ -677,6 +677,7 @@ class Entity:
|
|||
sprite_offset_y: Any # Y component of sprite pixel offset.
|
||||
step: Any # Step callback for grid.step() turn management. Called with (trigger, data) when behavior triggers fire. Set to None to clear.
|
||||
target_label: Any # Label to search for with TARGET trigger (str or None). Default: None.
|
||||
texture: Texture # Sprite texture atlas (Texture). Defaults to mcrfpy.default_texture when the entity is constructed without one. Setting preserves sprite_index (the index is n...
|
||||
tile_height: int # Entity height in tiles (int). Must be >= 1. Default 1.
|
||||
tile_size: Any # Entity size in tiles as (width, height) Vector. Default (1, 1).
|
||||
tile_width: int # Entity width in tiles (int). Must be >= 1. Default 1.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue