feat(bt): add repeat and selector task kinds
This commit is contained in:
@@ -150,6 +150,12 @@ export class TaskRunner {
|
||||
case "random":
|
||||
this._executeRandom(entity);
|
||||
break;
|
||||
case "repeat":
|
||||
this._executeRepeat(entity);
|
||||
break;
|
||||
case "selector":
|
||||
this._executeSelector(entity);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,6 +250,56 @@ export class TaskRunner {
|
||||
// If no eligible children (all running), wait for one to finish
|
||||
}
|
||||
|
||||
private _executeRepeat(entity: Entity): void {
|
||||
const children = childrenOf(this._world, entity);
|
||||
|
||||
// Repeat expects exactly one child
|
||||
if (children.length === 0) return;
|
||||
|
||||
const child = children[0];
|
||||
|
||||
// If child reached a terminal, reset it and schedule again
|
||||
if (isTerminal(this._world, child)) {
|
||||
clearStatus(this._world, child);
|
||||
this._world.add(child, Scheduled);
|
||||
return;
|
||||
}
|
||||
|
||||
// Schedule child if not already running or scheduled
|
||||
if (
|
||||
!this._world.has(child, Running) &&
|
||||
!this._world.has(child, Scheduled)
|
||||
) {
|
||||
this._world.add(child, Scheduled);
|
||||
}
|
||||
// Repeat itself never terminates — it just keeps the child going
|
||||
}
|
||||
|
||||
private _executeSelector(entity: Entity): void {
|
||||
const children = childrenOf(this._world, entity);
|
||||
|
||||
// Find the first non-terminal child
|
||||
for (const child of children) {
|
||||
if (isTerminal(this._world, child)) {
|
||||
const status = terminalStatus(this._world, child)!;
|
||||
if (status === "succeeded") {
|
||||
// First success — selector succeeds
|
||||
this._finish(entity, Succeeded);
|
||||
return;
|
||||
}
|
||||
// failed or cancelled — continue to next child
|
||||
continue;
|
||||
}
|
||||
|
||||
// Found a child that hasn't run yet — schedule it
|
||||
this._world.add(child, Scheduled);
|
||||
return;
|
||||
}
|
||||
|
||||
// All children failed
|
||||
this._finish(entity, Failed);
|
||||
}
|
||||
|
||||
// ── Completion propagation ────────────────────────
|
||||
|
||||
private _finish(
|
||||
|
||||
+12
-2
@@ -13,12 +13,22 @@ import { defineRelationship } from "../relationship";
|
||||
* Succeeds when all children succeed; fails when any child fails.
|
||||
* - `"random"` — picks one child at random each time it's scheduled.
|
||||
* Succeeds/fails with that child's result.
|
||||
* - `"repeat"` — runs its single child. When the child finishes, resets it
|
||||
* and runs again. Never terminates on its own (only via cancel).
|
||||
* - `"selector"` — runs children left to right. Succeeds on the first
|
||||
* child that succeeds; fails only if all children fail.
|
||||
*/
|
||||
export const Task = defineComponent("task", {
|
||||
kind: "leaf" as "leaf" | "sequential" | "parallel" | "random",
|
||||
kind: "leaf" as
|
||||
| "leaf"
|
||||
| "sequential"
|
||||
| "parallel"
|
||||
| "random"
|
||||
| "repeat"
|
||||
| "selector",
|
||||
});
|
||||
|
||||
export type TaskKind = typeof Task.type["kind"];
|
||||
export type TaskKind = (typeof Task.type)["kind"];
|
||||
|
||||
// ── Status tags (zero-size — presence is the signal) ──
|
||||
/** A task that should be executed this tick. */
|
||||
|
||||
Reference in New Issue
Block a user