Page:
Entity-Management
Pages
AI-and-Pathfinding
Adding-Python-Bindings
Animation-System
Design-Proposals
Entity-Management
Grid-Entity-Lifecycle
Grid-Rendering-Pipeline
Grid-System
Grid-TCOD-Integration
Home
Input-and-Events
Issue-Roadmap
Performance-Optimization-Workflow
Performance-and-Profiling
Procedural-Generation
Proposal-Next-Gen-Grid-Entity-System
Python-Binding-Layer
Rendering-and-Visuals
Strategic-Direction
UI-Component-Hierarchy
Writing-Tests
1
Entity-Management
John McCardle edited this page 2025-10-25 22:39:01 +00:00
Entity Management
Creating, positioning, and managing game entities that live on grids.
Quick Reference
System: Grid-System
Key Types:
mcrfpy.Entity- Game entities on gridsmcrfpy.Grid- Spatial container for entitiesgrid.entities- EntityCollection
API Reference: mcrfpy.Entity
What are Entities?
Entities are game objects that:
- Live on a Grid (0 or 1 grid per entity)
- Have a sprite for rendering
- Have grid position (integer coordinates)
- Can have AI, pathfinding, field of view
- Represent players, enemies, items, etc.
Files:
src/UIEntity.h/src/UIEntity.cppsrc/UIEntityCollection.h/.cpp
Creating Entities
Basic Entity Creation
import mcrfpy
# Create grid first
grid = mcrfpy.Grid(50, 50, 16, 16)
grid.texture = mcrfpy.createTexture("tiles.png")
# Create entity at position (10, 10) with sprite 0
player = mcrfpy.Entity(10, 10, 0)
player.sprite.texture = mcrfpy.createTexture("entities.png")
# Add entity to grid
grid.entities.append(player)
# Grid is now set automatically
assert player.grid == grid
Entity Properties
# Position (grid coordinates)
player.x = 15
player.y = 20
player.pos = (15, 20) # Tuple alternative
# Sprite (what to display)
player.sprite_index = 5 # Index in texture
player.sprite.scale_x = 1.5
player.sprite.scale_y = 1.5
# Visibility
player.visible = True
player.sprite.opacity = 0.8
# Grid association
current_grid = player.grid # Read-only
Entity Lifecycle
Adding to Grid
grid.entities.append(entity)
# Automatically:
# - entity.grid = grid
# - Entity rendered with grid
# - Entity included in spatial queries
Removing from Grid
# Method 1: Direct removal
grid.entities.remove(entity)
# Method 2: Entity.die() (planned #30)
# entity.die() # Will call grid.entities.remove(entity)
# Automatically:
# - entity.grid = None
# - Entity no longer rendered
# - Entity excluded from queries
Moving Entities
# Method 1: Direct assignment
entity.x = new_x
entity.y = new_y
# Method 2: Tuple assignment
entity.pos = (new_x, new_y)
# Method 3: Animation (smooth movement)
mcrfpy.animate(entity, "x", target_x, 500, "ease_in_out_quad")
mcrfpy.animate(entity, "y", target_y, 500, "ease_in_out_quad")
Collision Detection: Manual - check grid cells before moving
Entity Collections
Iteration
# Iterate all entities on grid
for entity in grid.entities:
print(f"Entity at ({entity.x}, {entity.y})")
# Count entities
num_entities = len(grid.entities)
# Index access
first_entity = grid.entities[0]
last_entity = grid.entities[-1]
Querying
Current: O(n) iteration - no spatial indexing
# Find entities at position
def entities_at(grid, x, y):
result = []
for entity in grid.entities:
if entity.x == x and entity.y == y:
result.append(entity)
return result
# Find entities in radius
def entities_in_radius(grid, center_x, center_y, radius):
result = []
for entity in grid.entities:
dx = entity.x - center_x
dy = entity.y - center_y
if (dx*dx + dy*dy) <= radius*radius:
result.append(entity)
return result
Optimization: #115 - SpatialHash for O(1) queries
Common Patterns
Pattern 1: Player Entity
import mcrfpy
# Create player
player = mcrfpy.Entity(25, 25, 0)
player.sprite.texture = player_texture
player.sprite_index = 0
# Add to grid
game_grid.entities.append(player)
# Movement with collision
def move_player(dx, dy):
new_x = player.x + dx
new_y = player.y + dy
# Check walkable
if game_grid.walkable((new_x, new_y)):
# Check for other entities
if not entities_at(game_grid, new_x, new_y):
player.pos = (new_x, new_y)
return True
return False
# Input handling
def on_keypress(key, pressed):
if pressed:
if key == mcrfpy.Key.Up:
move_player(0, -1)
elif key == mcrfpy.Key.Down:
move_player(0, 1)
elif key == mcrfpy.Key.Left:
move_player(-1, 0)
elif key == mcrfpy.Key.Right:
move_player(1, 0)
Pattern 2: Enemy Entities
import random
class Enemy:
def __init__(self, x, y):
self.entity = mcrfpy.Entity(x, y, 1)
self.entity.sprite.texture = enemy_texture
self.health = 100
self.aggro_range = 10
def update(self, player):
# Calculate distance to player
dx = player.x - self.entity.x
dy = player.y - self.entity.y
dist = (dx*dx + dy*dy) ** 0.5
if dist < self.aggro_range:
# Chase player
self.move_toward(player.x, player.y)
else:
# Wander randomly
self.wander()
def move_toward(self, target_x, target_y):
# Simple movement (pathfinding in [[AI-and-Pathfinding]])
if target_x > self.entity.x:
self.entity.x += 1
elif target_x < self.entity.x:
self.entity.x -= 1
elif target_y > self.entity.y:
self.entity.y += 1
elif target_y < self.entity.y:
self.entity.y -= 1
def wander(self):
# Random movement
dx = random.choice([-1, 0, 1])
dy = random.choice([-1, 0, 1])
new_x = self.entity.x + dx
new_y = self.entity.y + dy
if game_grid.walkable((new_x, new_y)):
self.entity.pos = (new_x, new_y)
# Spawn enemies
enemies = []
for i in range(10):
enemy = Enemy(random.randint(0, 49), random.randint(0, 49))
game_grid.entities.append(enemy.entity)
enemies.append(enemy)
# Update all enemies
def update_enemies():
for enemy in enemies:
enemy.update(player)
mcrfpy.setTimer("enemy_ai", lambda ms: update_enemies(), 500) # Every 0.5s
Pattern 3: Item Entities
class Item:
def __init__(self, x, y, item_type):
self.entity = mcrfpy.Entity(x, y, 10 + item_type)
self.entity.sprite.texture = item_texture
self.type = item_type # 0=potion, 1=key, 2=coin, etc
self.pickupable = True
def on_pickup(self, player):
# Add to inventory
player.inventory.append(self.type)
# Remove from grid
if self.entity.grid:
self.entity.grid.entities.remove(self.entity)
# Check for item pickup
def check_pickup(player):
items_here = entities_at(game_grid, player.x, player.y)
for entity in items_here:
# Find corresponding Item object
for item in all_items:
if item.entity == entity and item.pickupable:
item.on_pickup(player)
Entity-Grid Relationship
Lifecycle
1. Entity created (not on grid)
entity.grid == None
2. Entity added to grid
grid.entities.append(entity)
→ entity.grid = grid
3. Entity removed from grid
grid.entities.remove(entity)
→ entity.grid = None
4. Entity destroyed
Python GC handles cleanup
Important: Entities can only be on 0 or 1 grids at a time.
Multiple Grids
# Move entity between grids
def transfer_entity(entity, from_grid, to_grid, new_x, new_y):
# Remove from old grid
if entity.grid:
entity.grid.entities.remove(entity)
# Update position
entity.pos = (new_x, new_y)
# Add to new grid
to_grid.entities.append(entity)
Performance Considerations
Current Limitations
Entity Iteration: O(n) for spatial queries
- Finding entities at position: Must check all entities
- Finding entities in radius: Must check all entities
- Bottleneck: 500+ entities
Workarounds:
- Limit entity count (< 200 for best performance)
- Update entities in batches
- Use timer callbacks instead of per-frame updates
Planned Optimizations
#115: SpatialHash
- O(1) entity lookup by position
- O(k) radius queries (k = nearby entities)
- Expected: 100x+ improvement
#117: Memory Pool
- Reuse entity objects instead of allocate/destroy
- Reduced memory fragmentation
- Faster spawning
#116: Dirty Flags
- Only re-render grid when entities move
- Significant improvement for static entities
Integration with Other Systems
With Pathfinding
See AI-and-Pathfinding for:
entity.path_to(x, y)- A* pathfinding- Dijkstra maps for AI
- Path following
With FOV
See AI-and-Pathfinding for:
- Per-entity field of view
grid.perspectiveproperty- Fog of war
With Animation
See Animation-System for:
- Smooth entity movement
- Sprite animation
- Visual effects
# Animate entity movement
mcrfpy.animate(entity, "x", target_x, 300, "ease_out_quad")
mcrfpy.animate(entity, "y", target_y, 300, "ease_out_quad")
Related Documentation
- Grid-System - Entity spatial container
- AI-and-Pathfinding - Entity AI and pathfinding
- Animation-System - Animating entity movement
- UI-Component-Hierarchy - Entity as UIDrawable
Tutorial: McRogueFace Does The Entire Roguelike Tutorial - Parts 2-6 cover entity management
Open Issues: