Update "Entity-Management"

John McCardle 2025-12-01 21:28:59 +00:00
parent d8eca08a79
commit 0417da11b9
1 changed files with 115 additions and 4 deletions

@ -1,3 +1,6 @@
# Entity Management
*Last modified: 2025-12-01*
# Entity Management # 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. 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:** **Related Issues:**
- [#115](../../issues/115) - SpatialHash for fast queries (Open) - [#115](../../issues/115) - SpatialHash for fast queries (Open)
- [#117](../../issues/117) - Memory Pool for entities (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 a sprite** for visual rendering
- **Have grid position** (integer cell coordinates) - **Have grid position** (integer cell coordinates)
- **Implement behavior** (movement, AI, combat, inventory) - **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. **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 ## EntityCollection
`grid.entities` is an `EntityCollection` with list-like operations: `grid.entities` is an `EntityCollection` with list-like operations:
@ -160,6 +252,9 @@ entity.pos = (new_x, new_y)
# Animated movement # Animated movement
mcrfpy.Animation("x", target_x, 0.3, "easeOutQuad").start(entity) mcrfpy.Animation("x", target_x, 0.3, "easeOutQuad").start(entity)
mcrfpy.Animation("y", target_y, 0.3, "easeOutQuad").start(entity) mcrfpy.Animation("y", target_y, 0.3, "easeOutQuad").start(entity)
# Update visibility after movement
entity.update_visibility()
``` ```
### Removal ### Removal
@ -188,24 +283,40 @@ def transfer_entity(entity, to_grid, new_pos):
## Common Patterns ## Common Patterns
### Player Entity ### Player Entity with FOV
```python ```python
class Player: class Player:
def __init__(self, grid, start_pos): def __init__(self, grid, start_pos):
self.entity = mcrfpy.Entity(pos=start_pos, sprite_index=0, name="player") self.entity = mcrfpy.Entity(pos=start_pos, sprite_index=0, name="player")
grid.entities.append(self.entity) 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): def move(self, dx, dy):
new_x = self.entity.x + dx new_x = self.entity.x + dx
new_y = self.entity.y + dy new_y = self.entity.y + dy
# Check walkability via grid
point = self.entity.grid.at(new_x, new_y) point = self.entity.grid.at(new_x, new_y)
if point and point.walkable: if point and point.walkable:
self.entity.pos = (new_x, new_y) self.entity.pos = (new_x, new_y)
self.entity.update_visibility() # Update FOV after move
return True return True
return False 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 ### Enemy Entity
@ -213,7 +324,7 @@ class Player:
```python ```python
class Enemy: class Enemy:
def __init__(self, grid, pos, aggro_range=10): 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.aggro_range = aggro_range
self.health = 100 self.health = 100
grid.entities.append(self.entity) grid.entities.append(self.entity)
@ -312,4 +423,4 @@ See [[Performance-and-Profiling]] for optimization guidance.
--- ---
*Last updated: 2025-11-29* *Last updated: 2025-12-01*