mirror of
https://gitee.com/sli97/behavior-eden-coco-plugin.git
synced 2024-12-26 11:49:07 +00:00
541 lines
26 KiB
JavaScript
541 lines
26 KiB
JavaScript
|
"use strict";
|
|||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|||
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|||
|
};
|
|||
|
var BehaviorManager_1;
|
|||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|||
|
exports.BehaviorManager = void 0;
|
|||
|
const cc_1 = require("cc");
|
|||
|
const node_1 = require("../node");
|
|||
|
const BehaviorTree_1 = require("./BehaviorTree");
|
|||
|
const utils_1 = require("./utils");
|
|||
|
const { ccclass } = cc_1._decorator;
|
|||
|
/***
|
|||
|
* 该组件会自动添加到场景上,用来驱动、管理场景中所有行为树
|
|||
|
*/
|
|||
|
let BehaviorManager = BehaviorManager_1 = class BehaviorManager extends cc_1.Component {
|
|||
|
constructor() {
|
|||
|
super(...arguments);
|
|||
|
this.behaviorTrees = [];
|
|||
|
// behavior是用户使用的组件,BehaviorTree是真正的行为树数据结构
|
|||
|
this.behaviorTreesMap = new Map();
|
|||
|
// 存储被暂停运行的行为树
|
|||
|
this.pausedBehaviorTreesMap = new Map();
|
|||
|
}
|
|||
|
restart(behaviorTree) {
|
|||
|
if (behaviorTree.behavior.logNodeChange) {
|
|||
|
console.log("restart", behaviorTree);
|
|||
|
}
|
|||
|
// 所有节点都popNode出去以后,未删除的条件重评估的compositeIndex都为-1
|
|||
|
this.removeChildConditionalReevaluate(behaviorTree, -1);
|
|||
|
this.pushNode(behaviorTree, 0, 0);
|
|||
|
}
|
|||
|
// 防止用户手动创建实例但没有设置instance
|
|||
|
onLoad() {
|
|||
|
BehaviorManager_1.instance = this;
|
|||
|
}
|
|||
|
onDestroy() {
|
|||
|
for (const behaviorTree of this.behaviorTrees) {
|
|||
|
this.disableBehavior(behaviorTree.behavior);
|
|||
|
}
|
|||
|
}
|
|||
|
/***
|
|||
|
* 不传isPause的话,默认删掉行为树
|
|||
|
*/
|
|||
|
disableBehavior(behavior, isPause = false) {
|
|||
|
const behaviorTree = this.behaviorTreesMap.get(behavior);
|
|||
|
if (!behaviorTree) {
|
|||
|
return;
|
|||
|
}
|
|||
|
if (isPause) {
|
|||
|
// 存进暂停map里
|
|||
|
this.pausedBehaviorTreesMap.set(behavior, behaviorTree);
|
|||
|
behaviorTree.behavior.status = node_1.NodeStatus.Inactive; //设置为未激活状态
|
|||
|
}
|
|||
|
else {
|
|||
|
// 如果是手动disabled的话,让剩下的节点popNode,并不断迭代这个状态作为最终行为树的状态
|
|||
|
let status = node_1.NodeStatus.Success;
|
|||
|
for (let i = behaviorTree.activeStack.length - 1; i >= 0; i--) {
|
|||
|
const curStack = behaviorTree.activeStack[i];
|
|||
|
for (let j = curStack.length - 1; j >= 0; j--) {
|
|||
|
status = this.popNode(behaviorTree, curStack[curStack.length - 1], i, status, false);
|
|||
|
}
|
|||
|
}
|
|||
|
behavior.status = status;
|
|||
|
this.removeChildConditionalReevaluate(behaviorTree, -1);
|
|||
|
behavior.emit(BehaviorTree_1.BehaviorTreeEvent.BehaviorTreeEnd);
|
|||
|
this.behaviorTreesMap.delete(behavior);
|
|||
|
}
|
|||
|
const index = this.behaviorTrees.findIndex((tree) => tree === behaviorTree);
|
|||
|
// 数组删除该树
|
|||
|
index > -1 && this.behaviorTrees.splice(index, 1);
|
|||
|
}
|
|||
|
enableBehavior(behavior) {
|
|||
|
const rootNode = behavior.behaviorSource.rootNode;
|
|||
|
if (!rootNode) {
|
|||
|
if (behavior.logNodeChange) {
|
|||
|
console.warn("该行为树没有根节点");
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
// 仅被暂停的树,从map里拿出来继续运行
|
|||
|
if (this.pausedBehaviorTreesMap.has(behavior)) {
|
|||
|
const behaviorTree = this.pausedBehaviorTreesMap.get(behavior);
|
|||
|
this.pausedBehaviorTreesMap.delete(behavior);
|
|||
|
this.behaviorTrees.push(behaviorTree);
|
|||
|
this.behaviorTreesMap.set(behavior, behaviorTree);
|
|||
|
return;
|
|||
|
}
|
|||
|
// 全新的树
|
|||
|
const behaviorTree = new BehaviorTree();
|
|||
|
behaviorTree.behavior = behavior;
|
|||
|
this.behaviorTrees.push(behaviorTree);
|
|||
|
this.behaviorTreesMap.set(behavior, behaviorTree);
|
|||
|
//填充数据结构
|
|||
|
behaviorTree.activeStack.push([]);
|
|||
|
behaviorTree.parentIndex.push(-1);
|
|||
|
behaviorTree.relativeChildIndex.push(-1);
|
|||
|
behaviorTree.parentCompositeIndex.push(-1);
|
|||
|
this.addToNodeList(behaviorTree, rootNode, { parentCompositeIndex: -1 });
|
|||
|
//根节点放入运行栈
|
|||
|
behaviorTree.behavior.emit(BehaviorTree_1.BehaviorTreeEvent.BehaviorTreeStart);
|
|||
|
behaviorTree.behavior.status = node_1.NodeStatus.Running;
|
|||
|
//根节点放入运行栈
|
|||
|
this.pushNode(behaviorTree, 0, 0);
|
|||
|
}
|
|||
|
// 数据结构填充
|
|||
|
addToNodeList(behaviorTree, node, data) {
|
|||
|
behaviorTree.nodeList.push(node);
|
|||
|
const index = behaviorTree.nodeList.length - 1;
|
|||
|
if (node instanceof node_1.ParentNode) {
|
|||
|
behaviorTree.childrenIndex.push([]);
|
|||
|
behaviorTree.childConditionalIndex.push([]);
|
|||
|
for (let i = 0; i < node.children.length; i++) {
|
|||
|
behaviorTree.parentIndex.push(index);
|
|||
|
behaviorTree.relativeChildIndex.push(i);
|
|||
|
behaviorTree.childrenIndex[index].push(behaviorTree.nodeList.length);
|
|||
|
if (node instanceof node_1.Composite) {
|
|||
|
data.parentCompositeIndex = index;
|
|||
|
}
|
|||
|
behaviorTree.parentCompositeIndex.push(data.parentCompositeIndex);
|
|||
|
this.addToNodeList(behaviorTree, node.children[i], data);
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
behaviorTree.childrenIndex.push(null);
|
|||
|
behaviorTree.childConditionalIndex.push(null);
|
|||
|
if (node instanceof node_1.Condition) {
|
|||
|
const parentCompositeIndex = behaviorTree.parentCompositeIndex[index];
|
|||
|
if (parentCompositeIndex !== -1) {
|
|||
|
behaviorTree.childConditionalIndex[parentCompositeIndex].push(index);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
update() {
|
|||
|
this.tick();
|
|||
|
}
|
|||
|
/***
|
|||
|
* 驱动所有行为树
|
|||
|
*/
|
|||
|
tick() {
|
|||
|
//遍历所有树
|
|||
|
for (const behaviorTree of this.behaviorTrees) {
|
|||
|
if (behaviorTree.behavior.logNodeChange) {
|
|||
|
console.log("tick", behaviorTree);
|
|||
|
}
|
|||
|
// 重评估条件
|
|||
|
this.reevaluateConditionalNode(behaviorTree);
|
|||
|
//遍历所有运行栈
|
|||
|
//
|
|||
|
for (let i = behaviorTree.activeStack.length - 1; i >= 0; i--) {
|
|||
|
const curStack = behaviorTree.activeStack[i];
|
|||
|
let prevIndex = -1;
|
|||
|
let prevStatus = node_1.NodeStatus.Inactive;
|
|||
|
while (prevStatus !== node_1.NodeStatus.Running && i < behaviorTree.activeStack.length && curStack.length) {
|
|||
|
const curIndex = curStack[curStack.length - 1];
|
|||
|
// 记录前后两次,防止repeater子节点状态为success时,在一个tick里重复运行
|
|||
|
if (curIndex === prevIndex) {
|
|||
|
break;
|
|||
|
}
|
|||
|
prevIndex = curIndex;
|
|||
|
// runNode需要传入prevStatus的原因是
|
|||
|
// 例如selector一个子节点是running状态,某个tick变成了success状态,子节点popNode出去
|
|||
|
// 下一个tick进来,栈顶元素是selector,此时canExecute为false,runParentNode没办法返回一个具体的状态
|
|||
|
// 此时就可以把上一个tick子节点的状态作为本次tick的selector的状态(反转节点同理)
|
|||
|
prevStatus = this.runNode(behaviorTree, curIndex, i, prevStatus);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
runNode(behaviorTree, index, stackIndex, prevStatus) {
|
|||
|
const node = behaviorTree.nodeList[index];
|
|||
|
// 保证运行的节点在栈顶
|
|||
|
this.pushNode(behaviorTree, index, stackIndex);
|
|||
|
let status = prevStatus;
|
|||
|
if (node instanceof node_1.ParentNode) {
|
|||
|
status = this.runParentNode(behaviorTree, index, stackIndex, status);
|
|||
|
// 并行节点的状态不由某个子节点状态决定,而是由多个共同决定,所以重新计算status
|
|||
|
status = node.overrideStatus(status);
|
|||
|
}
|
|||
|
else {
|
|||
|
// 执行目标事件
|
|||
|
const res1 = node.onUpdate();
|
|||
|
const [done, res2] = this.emitEvent(behaviorTree, node.data, "onUpdate");
|
|||
|
status = done ? res2 : res1;
|
|||
|
}
|
|||
|
// 非running的节点pop出去
|
|||
|
if (status !== node_1.NodeStatus.Running) {
|
|||
|
status = this.popNode(behaviorTree, index, stackIndex, status);
|
|||
|
}
|
|||
|
return status;
|
|||
|
}
|
|||
|
runParentNode(behaviorTree, index, stackIndex, status) {
|
|||
|
const node = behaviorTree.nodeList[index];
|
|||
|
//防止running状态的并行节点重复运行
|
|||
|
if (node.canRunParallelChildren() && node.overrideStatus(node_1.NodeStatus.Running) === node_1.NodeStatus.Running) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
let childStatus = node_1.NodeStatus.Inactive;
|
|||
|
let preIndex = -1;
|
|||
|
//并行节点可以存在多个running状态的子节点
|
|||
|
while (node.canExecute() && (childStatus !== node_1.NodeStatus.Running || node.canRunParallelChildren())) {
|
|||
|
const childIndex = node.index;
|
|||
|
// 并行节点创建新的运行栈
|
|||
|
if (node.canRunParallelChildren()) {
|
|||
|
behaviorTree.activeStack.push([]);
|
|||
|
stackIndex = behaviorTree.activeStack.length - 1;
|
|||
|
node.onChildStarted();
|
|||
|
}
|
|||
|
let curIndex = childIndex;
|
|||
|
// 防止repeater或untilSuccess等可以重复运行的节点,canExecute一直是true,会导致一直进入while
|
|||
|
// 所以加入curIndex和preIndex,保证不能在一次runParentNode里重复运行相同节点
|
|||
|
if (curIndex === preIndex) {
|
|||
|
status = node_1.NodeStatus.Running;
|
|||
|
break;
|
|||
|
}
|
|||
|
preIndex = curIndex;
|
|||
|
status = childStatus = this.runNode(behaviorTree, behaviorTree.childrenIndex[index][childIndex], stackIndex, status);
|
|||
|
}
|
|||
|
// 子节点有运行就返回子节点的状态,没有就返回上一次运行的状态
|
|||
|
return status;
|
|||
|
}
|
|||
|
pushNode(behaviorTree, index, stackIndex) {
|
|||
|
const stack = behaviorTree.activeStack[stackIndex];
|
|||
|
// 防止重复推入
|
|||
|
if (stack.length === 0 || stack[stack.length - 1] !== index) {
|
|||
|
stack.push(index);
|
|||
|
const node = behaviorTree.nodeList[index];
|
|||
|
if (behaviorTree.behavior.logNodeChange) {
|
|||
|
console.log("pushNode", node, "index:", index, "stackIndex:", stackIndex);
|
|||
|
}
|
|||
|
node.onStart();
|
|||
|
this.emitEvent(behaviorTree, node.data, "onStart");
|
|||
|
}
|
|||
|
}
|
|||
|
popNode(behaviorTree, index, stackIndex, status, popChildren = true) {
|
|||
|
const curStack = behaviorTree.activeStack[stackIndex];
|
|||
|
curStack.pop();
|
|||
|
const node = behaviorTree.nodeList[index];
|
|||
|
node.onEnd();
|
|||
|
this.emitEvent(behaviorTree, node.data, "onEnd");
|
|||
|
if (behaviorTree.behavior.logNodeChange) {
|
|||
|
console.log("popNode", node, "index:", index, "stackIndex:", stackIndex, "status:", status);
|
|||
|
}
|
|||
|
const parentIndex = behaviorTree.parentIndex[index];
|
|||
|
if (parentIndex !== -1) {
|
|||
|
if (node instanceof node_1.Condition) {
|
|||
|
const parentCompositeIndex = behaviorTree.parentCompositeIndex[index];
|
|||
|
if (parentCompositeIndex !== -1) {
|
|||
|
const composite = behaviorTree.nodeList[parentCompositeIndex];
|
|||
|
//自己是条件节点并且父级的中断类型存在,创建重判断实例
|
|||
|
if (composite.abortType !== node_1.AbortType.None) {
|
|||
|
// 父composite为LowerPriority时,条件重评估不希望此时执行,而是父composite popNode出去再执行
|
|||
|
const compositeIndex = composite.abortType === node_1.AbortType.LowerPriority ? -1 : parentCompositeIndex;
|
|||
|
// 防止该条件存在条件重评估对象
|
|||
|
if (behaviorTree.conditionalReevaluateMap.has(index)) {
|
|||
|
const conditionalReevaluate = behaviorTree.conditionalReevaluateMap.get(index);
|
|||
|
conditionalReevaluate.compositeIndex = compositeIndex;
|
|||
|
conditionalReevaluate.status = status;
|
|||
|
}
|
|||
|
else {
|
|||
|
const conditionalReevaluate = new ConditionalReevaluate(index, stackIndex, status, compositeIndex);
|
|||
|
if (behaviorTree.behavior.logNodeChange) {
|
|||
|
console.log("new ConditionalReevaluate", conditionalReevaluate, "index:", index, "stackIndex:", stackIndex, "compositeIndex", compositeIndex);
|
|||
|
}
|
|||
|
behaviorTree.conditionalReevaluate.push(conditionalReevaluate);
|
|||
|
behaviorTree.conditionalReevaluateMap.set(index, conditionalReevaluate);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
const parentNode = behaviorTree.nodeList[parentIndex];
|
|||
|
parentNode.onChildExecuted(status, behaviorTree.relativeChildIndex[index]);
|
|||
|
// 父节点是反转节点,修改结果
|
|||
|
if (parentNode instanceof node_1.Decorator) {
|
|||
|
status = parentNode.decorate(status);
|
|||
|
}
|
|||
|
}
|
|||
|
if (node instanceof node_1.Composite) {
|
|||
|
// 类型是Self或者None时,清空所有子条件重评估,或者popNode的节点是当前运行栈的最后一项,删除该节点管理的条件重评估
|
|||
|
if ([node_1.AbortType.Self, node_1.AbortType.None].includes(node.abortType) || !curStack.length) {
|
|||
|
this.removeChildConditionalReevaluate(behaviorTree, index);
|
|||
|
// 类型是LowerPriority或者Both,上移compositeIndex,compositeIndex为-1的条件重评估对象,LowerPriority,会因此激活
|
|||
|
}
|
|||
|
else if ([node_1.AbortType.LowerPriority, node_1.AbortType.Both].includes(node.abortType)) {
|
|||
|
for (let i = 0; i < behaviorTree.childConditionalIndex[index].length; i++) {
|
|||
|
const childConditionalIndex = behaviorTree.childConditionalIndex[index][i];
|
|||
|
if (behaviorTree.conditionalReevaluateMap.has(childConditionalIndex)) {
|
|||
|
const conditionalReevaluate = behaviorTree.conditionalReevaluateMap.get(childConditionalIndex);
|
|||
|
conditionalReevaluate.compositeIndex = behaviorTree.parentCompositeIndex[index];
|
|||
|
}
|
|||
|
}
|
|||
|
// 上移当前被移除的composite管理的所有条件重评估的compositeIndex
|
|||
|
for (let i = 0; i < behaviorTree.conditionalReevaluate.length; i++) {
|
|||
|
const conditionalReevaluate = behaviorTree.conditionalReevaluate[i];
|
|||
|
if (conditionalReevaluate.compositeIndex === index) {
|
|||
|
conditionalReevaluate.compositeIndex = behaviorTree.parentCompositeIndex[index];
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
if (popChildren) {
|
|||
|
//并行节点删除其他正在运行的子节点
|
|||
|
for (let i = behaviorTree.activeStack.length - 1; i > stackIndex; i--) {
|
|||
|
const stack = behaviorTree.activeStack[i];
|
|||
|
if (stack.length > 0 && this.isParentNode(behaviorTree, index, stack[stack.length - 1])) {
|
|||
|
let status = node_1.NodeStatus.Failure;
|
|||
|
for (let j = stack.length - 1; j >= 0; j--) {
|
|||
|
status = this.popNode(behaviorTree, stack[stack.length - 1], i, status, false);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
// 当前运行栈没有节点了
|
|||
|
if (curStack.length === 0) {
|
|||
|
// 当前运行栈就是主运行栈
|
|||
|
if (stackIndex === 0) {
|
|||
|
// 重启行为树
|
|||
|
if (behaviorTree.behavior.restartWhenComplete) {
|
|||
|
this.restart(behaviorTree);
|
|||
|
}
|
|||
|
else {
|
|||
|
this.disableBehavior(behaviorTree.behavior);
|
|||
|
//修改disableBehavior写入的status
|
|||
|
behaviorTree.behavior.status = status;
|
|||
|
}
|
|||
|
status = node_1.NodeStatus.Inactive;
|
|||
|
}
|
|||
|
else {
|
|||
|
// 删除其他空子运行栈
|
|||
|
behaviorTree.activeStack.splice(stackIndex, 1);
|
|||
|
// 返回running,退出tick的while循环
|
|||
|
status = node_1.NodeStatus.Running;
|
|||
|
}
|
|||
|
}
|
|||
|
return status;
|
|||
|
}
|
|||
|
reevaluateConditionalNode(behaviorTree) {
|
|||
|
if (behaviorTree.behavior.logNodeChange) {
|
|||
|
console.log("reevaluateConditionalNode start", behaviorTree.conditionalReevaluate);
|
|||
|
}
|
|||
|
for (let i = behaviorTree.conditionalReevaluate.length - 1; i >= 0; i--) {
|
|||
|
const { index, compositeIndex, status: prevStatus } = behaviorTree.conditionalReevaluate[i];
|
|||
|
//父组合节点索引不存在或者故意设置为-1,不进行评估
|
|||
|
if (compositeIndex === -1) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
const node = behaviorTree.nodeList[index];
|
|||
|
let status = node_1.NodeStatus.Inactive;
|
|||
|
const res1 = node.onUpdate();
|
|||
|
const [done, res2] = this.emitEvent(behaviorTree, node.data, "onUpdate");
|
|||
|
status = done ? res2 : res1;
|
|||
|
//条件一致
|
|||
|
if (status === prevStatus) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
if (behaviorTree.behavior.logNodeChange) {
|
|||
|
console.log("reevaluateConditionalNode success", behaviorTree.conditionalReevaluate[i]);
|
|||
|
}
|
|||
|
for (let j = behaviorTree.activeStack.length - 1; j >= 0; j--) {
|
|||
|
const stack = behaviorTree.activeStack[j];
|
|||
|
if (!stack.length) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
//当前节点及他到公共父节点之间所有父节点pop出去
|
|||
|
let curNodeIndex = stack[stack.length - 1];
|
|||
|
const commonParentIndex = this.findCommonParentIndex(behaviorTree, curNodeIndex, index);
|
|||
|
// 该条件重评估的compositeIndex是commonParent的父级
|
|||
|
if (this.isParentNode(behaviorTree, compositeIndex, commonParentIndex)) {
|
|||
|
// popNode可能会修改activeStack,保存一下长度,相同才执行
|
|||
|
const stackLen = behaviorTree.activeStack.length;
|
|||
|
while (curNodeIndex !== -1 &&
|
|||
|
curNodeIndex !== commonParentIndex &&
|
|||
|
behaviorTree.activeStack.length === stackLen) {
|
|||
|
this.popNode(behaviorTree, curNodeIndex, j, node_1.NodeStatus.Failure, false);
|
|||
|
curNodeIndex = behaviorTree.parentIndex[curNodeIndex];
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
//右边的包括自己的重评估条件删除掉
|
|||
|
for (let j = behaviorTree.conditionalReevaluate.length - 1; j >= i; j--) {
|
|||
|
const conditionalReevaluate = behaviorTree.conditionalReevaluate[j];
|
|||
|
if (this.isParentNode(behaviorTree, compositeIndex, conditionalReevaluate.index)) {
|
|||
|
behaviorTree.conditionalReevaluateMap.delete(conditionalReevaluate.index);
|
|||
|
behaviorTree.conditionalReevaluate.splice(j, 1);
|
|||
|
}
|
|||
|
}
|
|||
|
const compositeNode = behaviorTree.nodeList[behaviorTree.parentCompositeIndex[index]];
|
|||
|
// 遍历左侧的条件重评估对象
|
|||
|
for (let j = i - 1; j >= 0; j--) {
|
|||
|
const conditionalReevaluate = behaviorTree.conditionalReevaluate[j];
|
|||
|
if (behaviorTree.parentCompositeIndex[conditionalReevaluate.index] === behaviorTree.parentCompositeIndex[index]) {
|
|||
|
// composite节点是LowerPriority,则让这些条件停止运行
|
|||
|
if (compositeNode.abortType === node_1.AbortType.LowerPriority) {
|
|||
|
conditionalReevaluate.compositeIndex = -1;
|
|||
|
// composite节点是Both或者Self,条件重评估的compositeIndex等于parentCompositeIndex
|
|||
|
}
|
|||
|
else if ([node_1.AbortType.Both, node_1.AbortType.Self].includes(compositeNode.abortType)) {
|
|||
|
conditionalReevaluate.index = behaviorTree.parentCompositeIndex[index];
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
//当前条件节点到CommonParentNode之间所有Composite节点执行onConditionalAbort
|
|||
|
const conditionalParentIndex = [];
|
|||
|
for (let m = behaviorTree.parentIndex[index]; m != compositeIndex; m = behaviorTree.parentIndex[m]) {
|
|||
|
conditionalParentIndex.push(m);
|
|||
|
}
|
|||
|
conditionalParentIndex.push(compositeIndex);
|
|||
|
//从顶部到底部的顺序执行
|
|||
|
for (let n = conditionalParentIndex.length - 1; n >= 0; n--) {
|
|||
|
const parentTask = behaviorTree.nodeList[conditionalParentIndex[n]];
|
|||
|
if (n === 0) {
|
|||
|
parentTask.onConditionalAbort(behaviorTree.relativeChildIndex[index]);
|
|||
|
}
|
|||
|
else {
|
|||
|
parentTask.onConditionalAbort(behaviorTree.relativeChildIndex[conditionalParentIndex[n - 1]]);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
removeChildConditionalReevaluate(behaviorTree, compositeIndex) {
|
|||
|
for (let i = behaviorTree.conditionalReevaluate.length - 1; i >= 0; i--) {
|
|||
|
if (behaviorTree.conditionalReevaluate[i].compositeIndex === compositeIndex) {
|
|||
|
behaviorTree.conditionalReevaluateMap.delete(behaviorTree.conditionalReevaluate[i].index);
|
|||
|
behaviorTree.conditionalReevaluate.splice(i, 1);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
findCommonParentIndex(behaviorTree, index1, index2) {
|
|||
|
const set = new Set();
|
|||
|
let num = index1;
|
|||
|
while (num !== -1) {
|
|||
|
set.add(num);
|
|||
|
num = behaviorTree.parentIndex[num];
|
|||
|
}
|
|||
|
num = index2;
|
|||
|
while (!set.has(num)) {
|
|||
|
num = behaviorTree.parentIndex[num];
|
|||
|
}
|
|||
|
return num;
|
|||
|
}
|
|||
|
isParentNode(behaviorTree, possibleParent, possibleChild) {
|
|||
|
for (let num = possibleChild; num !== -1; num = behaviorTree.parentIndex[num]) {
|
|||
|
if (num === possibleParent) {
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
/***
|
|||
|
* 执行节点事件
|
|||
|
*/
|
|||
|
emitEvent(behaviorTree, nodeData, lifeCycle) {
|
|||
|
const dump = nodeData.event[lifeCycle];
|
|||
|
const nodeUuid = dump.node;
|
|||
|
const compUuid = dump.comp;
|
|||
|
const methodName = dump.method;
|
|||
|
const methodData = dump.data;
|
|||
|
if (!nodeUuid || !compUuid || !methodName) {
|
|||
|
return [false, null];
|
|||
|
}
|
|||
|
// 行为树组件所在cocos节点
|
|||
|
const curNode = behaviorTree.behavior.node;
|
|||
|
// 先从当前节点开始层序遍历
|
|||
|
let target = (0, utils_1.bfsCcNode)(curNode, nodeUuid);
|
|||
|
// 找不到再从scene节点开始层序遍历
|
|||
|
if (!target) {
|
|||
|
target = (0, utils_1.bfsCcNode)(cc_1.director.getScene(), nodeUuid, curNode.uuid);
|
|||
|
}
|
|||
|
if (!target) {
|
|||
|
return [false, null];
|
|||
|
}
|
|||
|
const comp = target._components.find((comp) => comp.uuid === compUuid);
|
|||
|
if (!comp) {
|
|||
|
return [false, null];
|
|||
|
}
|
|||
|
const method = comp[methodName];
|
|||
|
if (!method) {
|
|||
|
return [false, null];
|
|||
|
}
|
|||
|
const res = method.call(comp, methodData);
|
|||
|
// 用户忘记写返回值,一律返回失败
|
|||
|
const result = res !== undefined ? res : node_1.NodeStatus.Failure;
|
|||
|
return [true, result];
|
|||
|
}
|
|||
|
};
|
|||
|
BehaviorManager.instance = null;
|
|||
|
BehaviorManager = BehaviorManager_1 = __decorate([
|
|||
|
ccclass("BehaviorManager")
|
|||
|
], BehaviorManager);
|
|||
|
exports.BehaviorManager = BehaviorManager;
|
|||
|
/***
|
|||
|
* 行为树数据结构,具体执行逻辑由BehaviorManager驱动
|
|||
|
*/
|
|||
|
class BehaviorTree {
|
|||
|
constructor() {
|
|||
|
this.activeStack = [];
|
|||
|
this.nodeList = [];
|
|||
|
//当前节点的父节点
|
|||
|
this.parentIndex = [];
|
|||
|
//当前节点的子节点
|
|||
|
this.childrenIndex = [];
|
|||
|
/***
|
|||
|
* 为了实现中断
|
|||
|
*/
|
|||
|
//当前节点是父节点的第几个子节点
|
|||
|
this.relativeChildIndex = [];
|
|||
|
//当前节点的父组合节点
|
|||
|
this.parentCompositeIndex = [];
|
|||
|
//当前节点的子条件节点
|
|||
|
this.childConditionalIndex = [];
|
|||
|
//所有条件重评估
|
|||
|
this.conditionalReevaluate = [];
|
|||
|
//条件重评估id的map
|
|||
|
this.conditionalReevaluateMap = new Map();
|
|||
|
}
|
|||
|
}
|
|||
|
/***
|
|||
|
* 条件重评估数据结构
|
|||
|
* 各种情况讲解:
|
|||
|
* 1、LowerPriority:左侧的重评估条件可以打断右侧Action节点的运行,不过不是所有都能打断,当Action属于该compositeIndex所管理的子树才能打断
|
|||
|
* 因此,随着compositeIndex逐渐上移,该条件能打断的范围就会越大,当然这就需要此条件的父节点均有LowerPriority或者Both,才能让compositeIndex一直上移
|
|||
|
* 2、Self:只能打断跟自己同一Composite节点下的其他节点的运行,当该Composite被popNode时,条件也会被删除
|
|||
|
* 3、Parallel:Parallel下有多个分支都有LowerPriority的条件重评估对象:
|
|||
|
* 情况1、假设某个分支返回Running状态,此时这个分支下的compositeIndex未达到并行节点,无法管理其他分支下Action运行
|
|||
|
* 情况2:返回Success或者Failure状态,当该运行栈最后一个元素popNode出去时,此时栈为空,会删除其管理的条件重评估
|
|||
|
* 如果该条件的compositeIndex是-1,不会进入compositeIndex上移逻辑,因此也无法运行
|
|||
|
* 总结:某个并行节点下的多个并行分支,各自的条件不会干扰
|
|||
|
*/
|
|||
|
class ConditionalReevaluate {
|
|||
|
constructor(index, stackIndex, status, compositeIndex) {
|
|||
|
this.index = index;
|
|||
|
this.stackIndex = stackIndex;
|
|||
|
this.status = status;
|
|||
|
this.compositeIndex = compositeIndex;
|
|||
|
}
|
|||
|
}
|