FOV optimization for behavior TARGET triggers #303
Labels
No labels
Alpha Release Requirement
Bugfix
Demo Target
Documentation
Major Feature
Minor Feature
priority:tier1-active
priority:tier2-foundation
priority:tier3-future
priority:tier4-deferred
Refactoring & Cleanup
system:animation
system:documentation
system:grid
system:input
system:performance
system:procgen
system:python-binding
system:rendering
system:ui-hierarchy
Tiny Feature
workflow:blocked
workflow:needs-benchmark
workflow:needs-documentation
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Depends on
#301
grid.step() — turn manager for entity behaviors
john/McRogueFace
Reference
john/McRogueFace#303
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Optimize FOV computation in the turn system's TARGET trigger check. Without optimization, computing FOV for every entity every turn is prohibitively expensive on large grids. The goal is to eliminate unnecessary FOV computation via tiered pre-filtering.
Target scale
McRogueFace targets 8192×8192 grids. Naive FOV for 100 entities = 100 × 67M cells = catastrophic. Even with TCOD's radius-bounded FOV, we need to avoid calling it when unnecessary.
Optimization tiers
Tier 1 — Label check (O(1))
If
entity.target_labelis None, skip entirely. Most entities won't have triggers configured. Expected elimination: majority of entities.Tier 2 — Spatial hash proximity pre-filter (O(bucket_count))
Before computing FOV, query the spatial hash for entities with
target_labelwithinsight_radius. Check the bounding square[cell_x ± radius] × [cell_y ± radius].If no target-labeled entities exist in any overlapping spatial hash buckets, skip FOV entirely.
With 32-cell buckets and radius 10, this checks at most
ceil(20/32)² = 1bucket in the best case. This catches 100% of cases where the target is simply too far away.Tier 3 — Bounded FOV computation
TCOD's
compute_fov()already accepts a radius parameter. For radius=10, FOV touches ~314 cells regardless of grid size. This is O(radius²), not O(grid_size).Verify that TCOD's implementation actually bounds its work to the radius and doesn't iterate the full map. If it does iterate the full map, consider:
Tier 4 — Static entity FOV caching
Entities that haven't moved since last FOV computation don't need recomputation. Track a
fov_dirtyflag per entity, set when:cell_poschangestransparentproperty changes within sight_radiusTier 5 — Subgrid-aware early termination (future)
For very large grids, spatial hash buckets provide natural subgrid boundaries. If an entire subgrid has no transparent-changing cells and no target entities, its FOV contribution is known without computation.
Expected performance
With 100 NPCs on 100×100 grid, 1 player (worst case: all NPCs have
target_label = "player"):TCOD investigation needed
Before implementation, verify:
TCOD_map_compute_fov()with a radius actually bound its iteration? Or does it scan the entire map and filter?Dependencies
grid.step()— this optimization lives inside the turn processing loop)cell_pos— for spatial hash queries)Files likely affected
src/UIGrid.h/cpp— FOV computation optimizationsrc/EntityBehavior.cpp— trigger evaluation in turn processingmodules/libtcod-headless/— if TCOD modification neededgrid.step()— turn manager for entity behaviorsRoadmap context
Part of the Grid & Entity Overhaul Roadmap (
docs/GRID_ENTITY_OVERHAUL_ROADMAP.md), Phase 3d (last in behavior system, after grid.step #301 is working).Reuses the
fov_dirtyflag from #292. Requires investigation of TCOD'scompute_fov()to confirm it bounds work to O(radius^2), not O(grid_size), on large maps. If TCOD iterates the full map, may require modifying the libtcod-headless fork.