From 0417da11b98db47fd636d74bb26f284119bf852d Mon Sep 17 00:00:00 2001 From: John McCardle Date: Mon, 1 Dec 2025 21:28:59 +0000 Subject: [PATCH] Update "Entity-Management" --- Entity-Management.md | 119 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 115 insertions(+), 4 deletions(-) diff --git a/Entity-Management.md b/Entity-Management.md index dd1c740..8abaf2b 100644 --- a/Entity-Management.md +++ b/Entity-Management.md @@ -1,3 +1,6 @@ +# Entity Management +*Last modified: 2025-12-01* + # Entity Management Entities are game objects that implement behavior and live on Grids. While Grids handle rendering and mediate interactions, Entities encapsulate game logic like movement, combat, and AI. @@ -18,6 +21,7 @@ Entities are game objects that implement behavior and live on Grids. While Grids **Related Issues:** - [#115](../../issues/115) - SpatialHash for fast queries (Open) - [#117](../../issues/117) - Memory Pool for entities (Open) +- [#16](../../issues/16) - Entity knowledge contents (Open) --- @@ -28,6 +32,7 @@ Entities are game objects that: - **Have a sprite** for visual rendering - **Have grid position** (integer cell coordinates) - **Implement behavior** (movement, AI, combat, inventory) +- **Track visibility** (which cells they can see / have seen) **Key distinction:** Entities implement behavior. Grids mediate interaction between entities and render them to screen. @@ -103,6 +108,93 @@ current_grid = entity.grid # Read-only, set by collection operations --- +## Field of View & Visibility + +Entities track what they can see via `gridstate` - a per-cell record of visible and discovered states. + +### FOV Configuration + +```python +# Grid-level FOV settings +grid.fov = mcrfpy.FOV.SHADOW # Algorithm (BASIC, DIAMOND, SHADOW, etc.) +grid.fov_radius = 10 # Default view radius + +# Module-level default +mcrfpy.default_fov = mcrfpy.FOV.PERMISSIVE_2 +``` + +### Updating Visibility + +```python +# Compute FOV from entity's position and update gridstate +entity.update_visibility() + +# This also updates any ColorLayers bound via apply_perspective() +``` + +### Querying Visible Entities + +```python +# Get list of other entities this entity can see +visible_enemies = entity.visible_entities() + +# With custom FOV settings +nearby = entity.visible_entities(radius=5) +visible = entity.visible_entities(fov=mcrfpy.FOV.BASIC, radius=8) +``` + +### Fog of War with ColorLayers + +```python +# Create a ColorLayer for fog of war +fov_layer = grid.add_layer('color', z_index=-1) +fov_layer.fill((0, 0, 0, 255)) # Start black (unknown) + +# Bind to entity - layer auto-updates when entity.update_visibility() is called +fov_layer.apply_perspective( + entity=player, + visible=(0, 0, 0, 0), # Transparent when visible + discovered=(40, 40, 60, 180), # Dark overlay when discovered + unknown=(0, 0, 0, 255) # Black when never seen +) + +# Now whenever player moves: +player.x = new_x +player.y = new_y +player.update_visibility() # Automatically updates the fog layer +``` + +### One-Time FOV Draw + +```python +# Draw FOV without binding (useful for previews, spell ranges, etc.) +fov_layer.draw_fov( + source=(player.x, player.y), + radius=10, + fov=mcrfpy.FOV.SHADOW, + visible=(255, 255, 200, 64), + discovered=(100, 100, 100, 128), + unknown=(0, 0, 0, 255) +) +``` + +### Gridstate Access + +```python +# Entity's per-cell visibility memory +for state in entity.gridstate: + print(f"visible={state.visible}, discovered={state.discovered}") + +# Access specific cell state +state = entity.at(x, y) +if state.visible: + print("Entity can currently see this cell") +elif state.discovered: + print("Entity has seen this cell before") +``` + +--- + ## EntityCollection `grid.entities` is an `EntityCollection` with list-like operations: @@ -160,6 +252,9 @@ entity.pos = (new_x, new_y) # Animated movement mcrfpy.Animation("x", target_x, 0.3, "easeOutQuad").start(entity) mcrfpy.Animation("y", target_y, 0.3, "easeOutQuad").start(entity) + +# Update visibility after movement +entity.update_visibility() ``` ### Removal @@ -188,24 +283,40 @@ def transfer_entity(entity, to_grid, new_pos): ## Common Patterns -### Player Entity +### Player Entity with FOV ```python class Player: def __init__(self, grid, start_pos): self.entity = mcrfpy.Entity(pos=start_pos, sprite_index=0, name="player") grid.entities.append(self.entity) + + # Set up fog of war + self.fov_layer = grid.add_layer('color', z_index=-1) + self.fov_layer.fill((0, 0, 0, 255)) + self.fov_layer.apply_perspective( + entity=self.entity, + visible=(0, 0, 0, 0), + discovered=(30, 30, 50, 180), + unknown=(0, 0, 0, 255) + ) + self.entity.update_visibility() def move(self, dx, dy): new_x = self.entity.x + dx new_y = self.entity.y + dy - # Check walkability via grid point = self.entity.grid.at(new_x, new_y) if point and point.walkable: self.entity.pos = (new_x, new_y) + self.entity.update_visibility() # Update FOV after move return True return False + + def get_visible_enemies(self): + """Get enemies this player can currently see.""" + return [e for e in self.entity.visible_entities() + if e.name and e.name.startswith("enemy")] ``` ### Enemy Entity @@ -213,7 +324,7 @@ class Player: ```python class Enemy: def __init__(self, grid, pos, aggro_range=10): - self.entity = mcrfpy.Entity(pos=pos, sprite_index=1) + self.entity = mcrfpy.Entity(pos=pos, sprite_index=1, name="enemy") self.aggro_range = aggro_range self.health = 100 grid.entities.append(self.entity) @@ -312,4 +423,4 @@ See [[Performance-and-Profiling]] for optimization guidance. --- -*Last updated: 2025-11-29* \ No newline at end of file +*Last updated: 2025-12-01* \ No newline at end of file