2025-09-03 10:54:07 +08:00
|
|
|
|
import { globalBlackboard, IBlackboard } from "../Blackboard";
|
|
|
|
|
|
import { Status } from "../header";
|
|
|
|
|
|
|
|
|
|
|
|
export interface IBTNode {
|
|
|
|
|
|
readonly children: IBTNode[];
|
|
|
|
|
|
/** 本节点的的黑板引用 */
|
2025-09-04 14:08:19 +08:00
|
|
|
|
local: IBlackboard;
|
2025-09-03 10:54:07 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 初始化节点
|
|
|
|
|
|
* @param root 树根节点的黑板
|
|
|
|
|
|
* @param parent 父节点的黑板
|
|
|
|
|
|
*/
|
|
|
|
|
|
_initialize(root: IBlackboard, parent: IBlackboard): void;
|
|
|
|
|
|
|
2025-09-04 15:13:24 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @internal
|
|
|
|
|
|
*/
|
2025-10-03 18:09:47 +08:00
|
|
|
|
_execute(dt: number): Status;
|
|
|
|
|
|
tick(dt: number): Status;
|
2025-09-03 10:54:07 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 优先写入自己的黑板数据, 如果没有则写入父节点的黑板数据
|
|
|
|
|
|
*/
|
|
|
|
|
|
set<T>(key: string, value: T): void;
|
|
|
|
|
|
get<T>(key: string): T;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 写入树根节点的黑板数据
|
|
|
|
|
|
*/
|
|
|
|
|
|
setRoot<T>(key: string, value: T): void;
|
|
|
|
|
|
getRoot<T>(key: string): T;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 写入全局黑板数据
|
|
|
|
|
|
*/
|
|
|
|
|
|
setGlobal<T>(key: string, value: T): void;
|
|
|
|
|
|
getGlobal<T>(key: string): T;
|
2025-09-04 14:08:19 +08:00
|
|
|
|
|
|
|
|
|
|
/** 获取关联的实体 */
|
|
|
|
|
|
getEntity<T>(): T;
|
2025-09-03 10:54:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 基础节点
|
|
|
|
|
|
* 每个节点只管理自己需要的状态
|
|
|
|
|
|
*/
|
|
|
|
|
|
export abstract class BTNode implements IBTNode {
|
|
|
|
|
|
public readonly children: IBTNode[];
|
|
|
|
|
|
|
|
|
|
|
|
/** 树根节点的黑板引用 */
|
|
|
|
|
|
protected _root!: IBlackboard;
|
2025-09-04 15:13:24 +08:00
|
|
|
|
|
2025-09-03 10:54:07 +08:00
|
|
|
|
/** 本节点的的黑板引用 可能等于 _parent */
|
|
|
|
|
|
protected _local!: IBlackboard;
|
|
|
|
|
|
|
|
|
|
|
|
constructor(children?: IBTNode[]) {
|
|
|
|
|
|
this.children = children ? [...children] : [];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public _initialize(root: IBlackboard, parent: IBlackboard): void {
|
|
|
|
|
|
this._root = root;
|
|
|
|
|
|
// 在需要的节点中重写,创建新的local
|
|
|
|
|
|
this._local = parent;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @internal
|
|
|
|
|
|
*/
|
2025-10-03 18:09:47 +08:00
|
|
|
|
public _execute(dt: number): Status {
|
2025-09-03 10:54:07 +08:00
|
|
|
|
// 首次执行时初始化
|
2025-09-04 15:13:24 +08:00
|
|
|
|
const isRunning = this._local.openNodes.get(this) || false;
|
|
|
|
|
|
if (!isRunning) {
|
|
|
|
|
|
this._local.openNodes.set(this, true);
|
2025-09-03 10:54:07 +08:00
|
|
|
|
this.open();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 执行核心逻辑
|
2025-10-03 18:09:47 +08:00
|
|
|
|
const status = this.tick(dt);
|
2025-09-03 10:54:07 +08:00
|
|
|
|
|
|
|
|
|
|
// 执行完成时清理
|
|
|
|
|
|
if (status !== Status.RUNNING) {
|
2025-09-04 15:13:24 +08:00
|
|
|
|
this._local.openNodes.delete(this);
|
2025-09-03 10:54:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
return status;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 初始化节点(首次执行时调用)
|
|
|
|
|
|
* 子类重写此方法进行状态初始化
|
|
|
|
|
|
*/
|
|
|
|
|
|
protected open(): void { }
|
|
|
|
|
|
|
2025-10-03 18:49:36 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 清理子节点的打开状态
|
|
|
|
|
|
* 一般用于装饰节点的非子节点关闭时, 用来清理子节点的打开状态
|
|
|
|
|
|
*/
|
|
|
|
|
|
protected cleanupChild(): void {
|
|
|
|
|
|
const child = this.children[0];
|
|
|
|
|
|
if (child && this._local.openNodes.has(child)) {
|
|
|
|
|
|
this._local.openNodes.delete(child);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-03 10:54:07 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 执行节点逻辑
|
|
|
|
|
|
* 子类必须实现此方法
|
|
|
|
|
|
* @returns 执行状态
|
|
|
|
|
|
*/
|
2025-10-03 18:09:47 +08:00
|
|
|
|
public abstract tick(dt: number): Status;
|
2025-09-03 10:54:07 +08:00
|
|
|
|
|
2025-09-04 14:08:19 +08:00
|
|
|
|
public getEntity<T>(): T {
|
|
|
|
|
|
return this._local.getEntity();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-03 10:54:07 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 设置获取全局黑板数据
|
|
|
|
|
|
*/
|
|
|
|
|
|
public set<T>(key: string, value: T): void {
|
|
|
|
|
|
this._local.set(key, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public get<T>(key: string): T {
|
|
|
|
|
|
return this._local.get(key);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 设置获取树根节点的黑板数据
|
|
|
|
|
|
*/
|
|
|
|
|
|
public setRoot<T>(key: string, value: T): void {
|
|
|
|
|
|
this._root.set(key, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public getRoot<T>(key: string): T {
|
|
|
|
|
|
return this._root.get(key);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 设置全局黑板数据
|
|
|
|
|
|
*/
|
|
|
|
|
|
public setGlobal<T>(key: string, value: T): void {
|
|
|
|
|
|
globalBlackboard.set(key, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public getGlobal<T>(key: string): T {
|
|
|
|
|
|
return globalBlackboard.get(key);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public get local(): IBlackboard {
|
|
|
|
|
|
return this._local;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|