feat(bt): implement subtree status clearing in TaskRunner
Introduce `clearSubtree` to recursively reset status for an entity and all its descendants. This ensures that when a task reaches a terminal state, its entire branch is properly reset. Also refactor the Tetris example to use a sequential task node within the behavior tree.
This commit is contained in:
parent
c3c24d2350
commit
efa92be5ab
|
|
@ -55,6 +55,9 @@ world.add(game, TickTimer);
|
|||
// Create blessed UI
|
||||
const ui = createUI();
|
||||
|
||||
// Spawn the first piece
|
||||
spawnPiece();
|
||||
|
||||
// ── Command handlers ─────────────────────────────────
|
||||
const commands = new CommandQueue(world);
|
||||
|
||||
|
|
@ -186,6 +189,7 @@ const runner = new TaskRunner(world);
|
|||
|
||||
// Build the BT structure:
|
||||
// root (repeat)
|
||||
// └── seq (sequential)
|
||||
// ├── handleInput (leaf)
|
||||
// ├── gravityTick (leaf)
|
||||
// └── render (leaf)
|
||||
|
|
@ -193,17 +197,21 @@ const runner = new TaskRunner(world);
|
|||
const root = world.spawn();
|
||||
world.add(root, Task, { kind: "repeat" });
|
||||
|
||||
const seq = world.spawn();
|
||||
world.add(seq, Task, { kind: "sequential" });
|
||||
world.relate(seq, ChildOf, root);
|
||||
|
||||
const handleInputTask = world.spawn();
|
||||
world.add(handleInputTask, Task, { kind: "leaf" });
|
||||
world.relate(handleInputTask, ChildOf, root);
|
||||
world.relate(handleInputTask, ChildOf, seq);
|
||||
|
||||
const gravityTask = world.spawn();
|
||||
world.add(gravityTask, Task, { kind: "leaf" });
|
||||
world.relate(gravityTask, ChildOf, root);
|
||||
world.relate(gravityTask, ChildOf, seq);
|
||||
|
||||
const renderTask = world.spawn();
|
||||
world.add(renderTask, Task, { kind: "leaf" });
|
||||
world.relate(renderTask, ChildOf, root);
|
||||
world.relate(renderTask, ChildOf, seq);
|
||||
|
||||
// ── Leaf handlers ────────────────────────────────────
|
||||
runner.onLeaf = (_w, entity) => {
|
||||
|
|
|
|||
|
|
@ -44,6 +44,14 @@ function clearStatus(world: World, entity: Entity): void {
|
|||
if (world.has(entity, Running)) world.remove(entity, Running);
|
||||
}
|
||||
|
||||
/** Recursively clear status from an entity and all its descendants. */
|
||||
function clearSubtree(world: World, entity: Entity): void {
|
||||
clearStatus(world, entity);
|
||||
for (const child of childrenOf(world, entity)) {
|
||||
clearSubtree(world, child);
|
||||
}
|
||||
}
|
||||
|
||||
function childrenOf(world: World, parent: Entity): Entity[] {
|
||||
return world.getRelatedTo(parent, ChildOf);
|
||||
}
|
||||
|
|
@ -258,9 +266,9 @@ export class TaskRunner {
|
|||
|
||||
const child = children[0];
|
||||
|
||||
// If child reached a terminal, reset it and schedule again
|
||||
// If child reached a terminal, reset the entire subtree and schedule again
|
||||
if (isTerminal(this._world, child)) {
|
||||
clearStatus(this._world, child);
|
||||
clearSubtree(this._world, child);
|
||||
this._world.add(child, Scheduled);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue