Dirty Flag¶
Intent: Avoid unnecessary work by deferring it until the result is needed.
Acron Mapping¶
Pattern role |
Acron equivalent |
|---|---|
Primary data |
|
Derived/cached data |
World-space transform, bounding box, path cost, AI visibility data |
Dirty flag |
Boolean |
Invalidation |
Set |
Recompute |
|
Note
Acron’s scene graph already implements dirty flags internally for world-space transform propagation — you get this for free on NodePath. Apply the pattern yourself only for custom derived data that Acron doesn’t track (minimap positions, AI cost maps, UI summary strings).
How to Implement¶
Identify the expensive derived value (e.g. nav-mesh region for an entity).
Store both the cached value and a
_dirtyflag on the wrapper object.Set
_dirty = Truein every method that changes the primary data.In the getter, check
_dirty; if True, recompute and clear the flag.Optionally, defer all dirty-object recomputes to a single late-frame task (batch recalculation).
Code Sketch (Python)¶
class SceneEntity:
def __init__(self, node):
self._node = node
self._cached_region = None
self._dirty = True # start dirty to force first compute
# ── Primary data setters — always mark dirty ──────────────────
def set_pos(self, x, y, z):
self._node.setPos(x, y, z)
self._dirty = True
def set_hpr(self, h, p, r):
self._node.setHpr(h, p, r)
self._dirty = True
# ── Derived data getter — lazy recompute ──────────────────────
@property
def nav_region(self):
if self._dirty:
self._cached_region = self._compute_nav_region()
self._dirty = False
return self._cached_region
def _compute_nav_region(self):
pos = self._node.getPos(render) # world-space position
# expensive spatial lookup
return nav_mesh.region_at(pos.x, pos.y)
# Batch version: collect all dirty entities and recompute once per frame
class DirtyFlagSystem:
def __init__(self):
self._dirty_set = set()
taskMgr.add(self._flush, 'dirtyFlush', sort=45) # late in frame
def mark_dirty(self, entity):
self._dirty_set.add(entity)
def _flush(self, task):
for entity in self._dirty_set:
entity._cached_region = entity._compute_nav_region()
entity._dirty = False
self._dirty_set.clear()
return task.cont
Pitfalls¶
Forgetting to mark dirty: any path that modifies primary data without calling the wrapper’s setter will silently serve stale cache. Encapsulate all setters or use
__setattr__interception.Marking dirty too eagerly: if
_dirtyis set every frame regardless of actual change, the cache never helps. Only set it when the value actually changed.Acron scene graph already handles transforms: do not re-implement transform dirty-flags for
NodePathhierarchies — callnode.getPos(render)(world space) which Acron recalculates efficiently already. Apply this pattern to custom derived data only.