mirror of
https://github.com/gongxh0901/kunpocc-behaviortree.git
synced 2025-12-27 00:58:18 +00:00
项目重构,破坏性更新
This commit is contained in:
@@ -1,61 +1,97 @@
|
||||
import { Blackboard } from "./Blackboard";
|
||||
import { BaseNode } from "./BTNode/BaseNode";
|
||||
import { createUUID } from "./header";
|
||||
import { Ticker } from "./Ticker";
|
||||
|
||||
/**
|
||||
* 行为树
|
||||
* 所有节点全部添加到树中
|
||||
*/
|
||||
export class BehaviorTree {
|
||||
/** 行为树ID @internal */
|
||||
private _id: string;
|
||||
/** 行为树跟节点 @internal */
|
||||
export class BehaviorTree<T> {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
private _root: BaseNode;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
private _blackboard: Blackboard;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
private _subject: T;
|
||||
|
||||
/**
|
||||
* 节点ID计数器,每个树实例独立管理
|
||||
* @internal
|
||||
*/
|
||||
private _nodeIdCounter: number = 0;
|
||||
|
||||
get root(): BaseNode { return this._root; }
|
||||
get blackboard() { return this._blackboard }
|
||||
get subject(): T { return this._subject; }
|
||||
|
||||
/**
|
||||
* constructor
|
||||
* @param subject 主体
|
||||
* @param root 根节点
|
||||
*/
|
||||
constructor(root: BaseNode) {
|
||||
this._id = createUUID();
|
||||
constructor(subject: T, root: BaseNode) {
|
||||
this._root = root;
|
||||
this._blackboard = new Blackboard();
|
||||
this._subject = subject;
|
||||
|
||||
// 构造时就初始化所有节点ID,避免运行时检查
|
||||
this._initializeAllNodeIds(this._root);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行
|
||||
* @param subject 主体
|
||||
* @param blackboard 黑板
|
||||
* @param ticker 更新器
|
||||
* 执行行为树
|
||||
*/
|
||||
public tick(subject: any, blackboard: Blackboard, ticker?: Ticker): void {
|
||||
ticker = ticker || new Ticker(subject, blackboard, this);
|
||||
ticker.openNodes.length = 0;
|
||||
this._root._execute(ticker);
|
||||
// 上次打开的节点
|
||||
let lastOpenNodes = (blackboard.get("openNodes", this._id) || []) as BaseNode[];
|
||||
// 当前打开的节点
|
||||
let currOpenNodes = ticker.openNodes;
|
||||
let start = 0;
|
||||
for (let i = 0; i < Math.min(lastOpenNodes.length, currOpenNodes.length); i++) {
|
||||
start = i + 1;
|
||||
if (lastOpenNodes[i] !== currOpenNodes[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 关闭不需要的节点
|
||||
for (let i = lastOpenNodes.length - 1; i >= start; i--) {
|
||||
lastOpenNodes[i]._close(ticker);
|
||||
}
|
||||
/* POPULATE BLACKBOARD */
|
||||
blackboard.set("openNodes", currOpenNodes, this._id);
|
||||
blackboard.set("nodeCount", ticker.nodeCount, this._id);
|
||||
public tick(): void {
|
||||
this._root._execute(this);
|
||||
}
|
||||
|
||||
get id(): string {
|
||||
return this._id;
|
||||
/**
|
||||
* 生成节点ID
|
||||
* 每个树实例独立管理节点ID,避免全局状态污染
|
||||
* @internal
|
||||
*/
|
||||
private _generateNodeId(): string {
|
||||
return `${++this._nodeIdCounter}`;
|
||||
}
|
||||
|
||||
get root(): BaseNode {
|
||||
return this._root;
|
||||
/**
|
||||
* 递归初始化所有节点ID
|
||||
* 在构造时一次性完成,避免运行时检查
|
||||
* @param node 要初始化的节点
|
||||
* @internal
|
||||
*/
|
||||
private _initializeAllNodeIds(node: BaseNode): void {
|
||||
// 设置当前节点ID
|
||||
node.id = this._generateNodeId();
|
||||
|
||||
// 递归设置所有子节点ID
|
||||
for (const child of node.children) {
|
||||
this._initializeAllNodeIds(child);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 完全重置行为树(核武器级别的重置)
|
||||
* 清空黑板并重置所有节点状态
|
||||
*/
|
||||
public reset(): void {
|
||||
this._blackboard.clear();
|
||||
// 重置所有节点的状态
|
||||
this._root.cleanupAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置指定记忆节点的记忆状态
|
||||
* 用于精确控制记忆节点的重置,而不影响其他状态
|
||||
* @param node 记忆节点
|
||||
*/
|
||||
public resetMemoryNode(node: BaseNode): void {
|
||||
// 通过黑板标记该节点需要重置记忆
|
||||
this._blackboard.set(`reset_memory`, true, node);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user