behavior-eden-coco-plugin/dist/runtime/core/BehaviorManager.js
2023-09-21 01:32:33 +08:00

541 lines
26 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"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为falserunParentNode没办法返回一个具体的状态
// 此时就可以把上一个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上移compositeIndexcompositeIndex为-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、ParallelParallel下有多个分支都有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;
}
}