Skip to content

Commit

Permalink
Added Race node
Browse files Browse the repository at this point in the history
  • Loading branch information
Nikolas Howard committed Mar 11, 2024
1 parent e504634 commit 3b21c3b
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 69 deletions.
23 changes: 7 additions & 16 deletions dist/bundle.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions dist/bundle.js.map

Large diffs are not rendered by default.

23 changes: 7 additions & 16 deletions dist/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions dist/index.js.map

Large diffs are not rendered by default.

26 changes: 26 additions & 0 deletions dist/nodes/composite/Race.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import Composite from "./Composite";
import Node from "../Node";
import { Agent } from "../../Agent";
import Attribute from "../../attributes/Attribute";
import { BehaviourTreeOptions } from "../../BehaviourTreeOptions";
/**
* A RACE node.
* The child nodes are executed concurrently until one succeeds or all fail.
*/
export default class Race extends Composite {
/**
* @param attributes The node attributes.
* @param children The child nodes.
*/
constructor(attributes: Attribute[], children: Node[]);
/**
* Called when the node is being updated.
* @param agent The agent.
* @param options The behaviour tree options object.
*/
protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void;
/**
* Gets the name of the node.
*/
getName: () => string;
}
49 changes: 16 additions & 33 deletions src/nodes/composite/Parallel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,44 +24,17 @@ export default class Parallel extends Composite {
* @param options The behaviour tree options object.
*/
protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {
// Keep a count of the number of succeeded child nodes.
let succeededCount = 0;

let hasChildFailed = false;

// Iterate over all of the children of this node.
// Iterate over all of the children of this node, updating any that aren't in a settled state.
for (const child of this.children) {
// If the child has never been updated or is running then we will need to update it now.
if (child.getState() === State.READY || child.getState() === State.RUNNING) {
// Update the child of this node.
child.update(agent, options);
}

// If the current child has a state of 'SUCCEEDED' then we should move on to the next child.
if (child.getState() === State.SUCCEEDED) {
// The child node has succeeded, keep track of this to determine if all children have.
succeededCount++;

// The child node succeeded, but we have not finished checking every child node yet.
continue;
}

// If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.
if (child.getState() === State.FAILED) {
hasChildFailed = true;

// There is no need to check the rest of the children.
break;
}

// The node should be in the 'RUNNING' state.
if (child.getState() !== State.RUNNING) {
// The child node was not in an expected state.
throw new Error("child node was not in an expected state.");
}
}

if (hasChildFailed) {
// If any of our child nodes have failed then this node has also failed.
if (this.children.find((child) => child.is(State.FAILED))) {
// This node is a 'FAILED' node.
this.setState(State.FAILED);

Expand All @@ -71,10 +44,20 @@ export default class Parallel extends Composite {
child.abort(agent);
}
}
} else {
// If all children have succeeded then this node has also succeeded, otherwise it is still running.
this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);

return;
}

// A parallel node will move into the succeeded state if all child nodes move into the succeeded state.
if (this.children.every((child) => child.is(State.SUCCEEDED))) {
// This node is a 'SUCCEEDED' node.
this.setState(State.SUCCEEDED);

return;
}

// If we didn't move to a succeeded or failed state then this node is still running.
this.setState(State.RUNNING);
}

/**
Expand Down
67 changes: 67 additions & 0 deletions src/nodes/composite/Race.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import Composite from "./Composite";
import State from "../../State";
import Node from "../Node";
import { Agent } from "../../Agent";
import Attribute from "../../attributes/Attribute";
import { BehaviourTreeOptions } from "../../BehaviourTreeOptions";

/**
* A RACE node.
* The child nodes are executed concurrently until one succeeds or all fail.
*/
export default class Race extends Composite {
/**
* @param attributes The node attributes.
* @param children The child nodes.
*/
constructor(attributes: Attribute[], children: Node[]) {
super("race", attributes, children);
}

/**
* Called when the node is being updated.
* @param agent The agent.
* @param options The behaviour tree options object.
*/
protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {
// Iterate over all of the children of this node, updating any that aren't in a settled state.
for (const child of this.children) {
// If the child has never been updated or is running then we will need to update it now.
if (child.getState() === State.READY || child.getState() === State.RUNNING) {
// Update the child of this node.
child.update(agent, options);
}
}

// If any of our child nodes have succeeded then this node has also succeeded
if (this.children.find((child) => child.is(State.SUCCEEDED))) {
// This node is a 'SUCCEEDED' node.
this.setState(State.SUCCEEDED);

// Abort every running child.
for (const child of this.children) {
if (child.getState() === State.RUNNING) {
child.abort(agent);
}
}

return;
}

// A race node will move into the failed state if all child nodes move into the failed state as none can succeed.
if (this.children.every((child) => child.is(State.FAILED))) {
// This node is a 'FAILED' node.
this.setState(State.FAILED);

return;
}

// If we didn't move to a succeeded or failed state then this node is still running.
this.setState(State.RUNNING);
}

/**
* Gets the name of the node.
*/
getName = () => "RACE";
}

0 comments on commit 3b21c3b

Please sign in to comment.