Grid System
The Grid System is McRogueFace's core spatial container for roguelike game maps. It provides tilemap rendering, entity management, FOV (field of view), and pathfinding integration with libtcod.
Quick Reference
Related Issues:
- #124 - Grid Point Animation (Tier 1 - Active)
- #123 - Grid Subgrid System (Tier 1 - Active)
- #114 - CellView API (Tier 1 - Active)
- #113 - Batch Operations for Grid (Tier 1 - Active)
- #64 - Grid-Entity-GridPointState TCOD Updates
- #50 - Grid Background Color (Closed - Implemented)
Key Files:
src/UIGrid.h/src/UIGrid.cpp- Main grid implementationsrc/UIGridPoint.h- Individual grid cell (visual layer)src/UIGridPointState.h- Per-entity perspective/knowledgesrc/UIEntity.h/src/UIEntity.cpp- Entity system (lives on grid)
API Reference:
- See mcrfpy.Grid in generated API docs
- See mcrfpy.Entity in generated API docs
Architecture Overview
Three-Layer Design
The Grid System uses a three-layer architecture for sophisticated roguelike features:
-
Visual Layer (
UIGridPoint)- What's displayed: tile sprite, colors, animations
- Shared by all viewers
- File:
src/UIGridPoint.h
-
World State Layer (
TCODMap)- Physical properties: walkable, transparent, cost
- Used for pathfinding and FOV calculations
- Integration: libtcod via
src/UIGrid.cpp
-
Perspective Layer (
UIGridPointState)- Per-entity knowledge: what each entity has seen/explored
- Enables fog of war, asymmetric information
- File:
src/UIGridPointState.h
This architecture follows proven patterns from Caves of Qud, Cogmind, and DCSS.
Grid → Entity Relationship
Entity Lifecycle:
- Entities live on exactly 0 or 1 grids
grid.entities.append(entity)setsentity.grid = gridgrid.entities.remove(entity)setsentity.grid = None- Entity removal handled automatically on grid destruction
Spatial Queries:
- Currently: Linear iteration through entity list
- Planned: SpatialHash for O(1) lookups (see #115)
Sub-Pages
- Grid-Rendering-Pipeline - How grid renders each frame
- Grid-TCOD-Integration - FOV, pathfinding, walkability
- Grid-Entity-Lifecycle - Entity creation, movement, removal
- Grid-Performance-Optimization - Dirty flags, culling, batch ops
Common Tasks
Creating a Grid
import mcrfpy
# Create 50x50 grid with 16x16 tile size
grid = mcrfpy.Grid(50, 50, 16, 16)
grid.texture = mcrfpy.createTexture("tileset.png")
grid.pos = (100, 100) # Screen position
# Add to scene
mcrfpy.sceneUI("game").append(grid)
Details: See src/UIGrid.cpp::PyInit() for constructor implementation
Setting Tile Properties
# Access individual cell
cell = grid.at((x, y))
# Visual properties
cell.tilesprite = 42 # Sprite index in texture
cell.color = mcrfpy.Color(255, 255, 255)
# World properties (TCOD integration)
grid.walkable((x, y), True) # Can entities walk here?
grid.transparent((x, y), True) # Can see through?
Implementation: src/UIGrid.cpp::walkable(), src/UIGrid.cpp::transparent()
FOV and Pathfinding
# Compute field of view from entity position
grid.compute_fov(entity.x, entity.y, radius=10)
# A* pathfinding
path = entity.path_to(target_x, target_y)
Implementation:
- FOV:
src/UIGrid.cpp::compute_fov()(TCOD integration) - Pathfinding:
src/UIEntity.cpp::path_to()(uses TCOD A*)
Performance Characteristics
Current:
- Grid rendering: O(visible_cells) - renders only viewport
- Entity rendering: O(entities) - culls out-of-bounds (see
src/UIGrid.cpp::render()) - Static grids: Inefficient - redraws unchanged cells every frame
Optimizations In Progress:
- #116: Dirty flag system - only redraw on changes
- #113: Batch operations - reduce Python/C++ boundary crossings
- #115: SpatialHash - O(1) entity spatial queries
- #123: Subgrid system - divide large grids into chunks
Profiling: Press F3 in-game to see grid render metrics (see Performance-and-Profiling)
Design Proposals
Active architectural evolution:
- Proposal-Next-Gen-Grid-Architecture - Subgrid system, tile animation
- Proposal-Next-Gen-Entity-System - Flexible entity content, multi-tile entities
Known Issues & Limitations
Current Limitations:
- No tile-level animation (planned: #124)
- Large grids (>200x200) can have rendering overhead
- Entity iteration is O(n) for spatial queries
Workarounds:
- Keep grids reasonably sized (< 100x100 for best performance)
- Use entity culling (automatically enabled in
UIGrid::render()) - Profile with F3 overlay to identify bottlenecks
Related Systems
- UI-Component-Hierarchy - Grid inherits from UIDrawable
- Animation-System - Grid properties are animatable (pos, zoom, etc)
- Performance-and-Profiling - Grid rendering instrumented with ScopedTimer
- Entity-Management - Entity use case depends on Grid system
See Also:
- Tutorial: McRogueFace Does The Entire Roguelike Tutorial
- Build Guide: CLAUDE.md in repository root