From fe7b626c14d8d927c3199465c487307b2e1d5237 Mon Sep 17 00:00:00 2001 From: John McCardle Date: Tue, 2 Dec 2025 03:10:07 +0000 Subject: [PATCH] Delete page "Entity-Management.-" --- Entity-Management.-.md | 418 ----------------------------------------- 1 file changed, 418 deletions(-) delete mode 100644 Entity-Management.-.md diff --git a/Entity-Management.-.md b/Entity-Management.-.md deleted file mode 100644 index 531481f..0000000 --- a/Entity-Management.-.md +++ /dev/null @@ -1,418 +0,0 @@ -# Entity Management - -Creating, positioning, and managing game entities that live on grids. - -## Quick Reference - -**System:** [[Grid-System]] - -**Key Types:** -- `mcrfpy.Entity` - Game entities on grids -- `mcrfpy.Grid` - Spatial container for entities -- `grid.entities` - EntityCollection - -**API Reference:** [mcrfpy.Entity](../../docs/api_reference_dynamic.html#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.cpp` -- `src/UIEntityCollection.h` / `.cpp` - ---- - -## Creating Entities - -### Basic Entity Creation - -```python -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 - -```python -# 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 - -```python -grid.entities.append(entity) - -# Automatically: -# - entity.grid = grid -# - Entity rendered with grid -# - Entity included in spatial queries -``` - -### Removing from Grid - -```python -# 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 - -```python -# 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 - -```python -# 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 - -```python -# 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](../../issues/115) - SpatialHash for O(1) queries - ---- - -## Common Patterns - -### Pattern 1: Player Entity - -```python -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 - -```python -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 - -```python -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 - -```python -# 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](../../issues/115): SpatialHash** -- O(1) entity lookup by position -- O(k) radius queries (k = nearby entities) -- Expected: 100x+ improvement - -**[#117](../../issues/117): Memory Pool** -- Reuse entity objects instead of allocate/destroy -- Reduced memory fragmentation -- Faster spawning - -**[#116](../../issues/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.perspective` property -- Fog of war - -### With Animation - -See [[Animation-System]] for: -- Smooth entity movement -- Sprite animation -- Visual effects - -```python -# 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](../../roguelike_tutorial/) - Parts 2-6 cover entity management - -**Open Issues:** -- [#30](../../issues/30) - Entity.die() method -- [#115](../../issues/115) - SpatialHash for fast queries -- [#117](../../issues/117) - Memory pool for entities \ No newline at end of file