添加根据数据创建行为树的方法

This commit is contained in:
gongxh
2025-09-16 18:12:33 +08:00
parent 1c5f9de608
commit d7fc1e49ae
7 changed files with 104 additions and 588 deletions

View File

@@ -64,6 +64,11 @@ export namespace BT {
maxChildren: number;
}
/**
* 注册节点名 到 节点构造函数的映射
*/
const NODE_NAME_TO_CONSTRUCTOR_MAP = new Map<string, any>();
/**
* 节点元数据存储
*/
@@ -111,6 +116,7 @@ export namespace BT {
parameters
};
NODE_METADATA_MAP.set(constructor, fullMetadata);
NODE_NAME_TO_CONSTRUCTOR_MAP.set(name, constructor);
return constructor;
};
}
@@ -131,6 +137,7 @@ export namespace BT {
parameters
};
NODE_METADATA_MAP.set(constructor, fullMetadata);
NODE_NAME_TO_CONSTRUCTOR_MAP.set(name, constructor);
return constructor;
};
}
@@ -151,6 +158,7 @@ export namespace BT {
parameters
};
NODE_METADATA_MAP.set(constructor, fullMetadata);
NODE_NAME_TO_CONSTRUCTOR_MAP.set(name, constructor);
return constructor;
};
}
@@ -171,6 +179,7 @@ export namespace BT {
parameters
};
NODE_METADATA_MAP.set(constructor, fullMetadata);
NODE_NAME_TO_CONSTRUCTOR_MAP.set(name, constructor);
return constructor;
};
}
@@ -181,6 +190,20 @@ export namespace BT {
export function getAllNodeMetadata(): Map<any, NodeMetadata> {
return new Map(NODE_METADATA_MAP);
}
/**
* 通过节点名 获取 节点构造函数
*/
export function getNodeConstructor(name: string): any {
return NODE_NAME_TO_CONSTRUCTOR_MAP.get(name);
}
/**
* 通过节点构造函数 找到节点元数据
*/
export function getNodeMetadata(ctor: any): NodeMetadata {
return NODE_METADATA_MAP.get(ctor)!;
}
}
let _global = globalThis || window || global;

View File

@@ -51,7 +51,7 @@ export class WaitTime extends LeafNode {
private _value: number = 0;
constructor(duration: number = 0) {
super();
this._max = duration * 1000;
this._max = duration;
}
protected override open(): void {
@@ -61,7 +61,7 @@ export class WaitTime extends LeafNode {
public tick(): Status {
const currTime = new Date().getTime();
if (currTime - this._value >= this._max) {
if (currTime - this._value >= this._max * 1000) {
return Status.SUCCESS;
}
return Status.RUNNING;

View File

@@ -56,7 +56,7 @@ export class LimitTime extends NumericDecorator {
*/
constructor(child: IBTNode, max: number = 1) {
super(child);
this._max = max * 1000;
this._max = max;
}
protected override open(): void {
@@ -65,7 +65,7 @@ export class LimitTime extends NumericDecorator {
public tick(): Status {
const currentTime = Date.now();
if (currentTime - this._value > this._max) {
if (currentTime - this._value > this._max * 1000) {
return Status.FAILURE;
}
return this.children[0]!._execute();

View File

@@ -0,0 +1,71 @@
/**
* @Author: Gongxh
* @Date: 2025-09-16
* @Description: 根据数据创建一颗行为树
*/
import { BehaviorTree } from "./BehaviorTree";
import { BT } from "./BT";
import { IBTNode } from "./BTNode/BTNode";
interface INodeConfig {
id: string,
className: string,
parameters: Record<string, any>,
children: string[]
}
/**
* 根据节点配置递归创建节点
* @param info 节点配置
* @param nodeMap 所有节点配置的映射表
* @returns 创建的节点实例
*/
function createNodeRecursively(info: INodeConfig, nodeMap: Map<string, INodeConfig>): IBTNode {
// 获取节点构造函数
const ctor = BT.getNodeConstructor(info.className);
if (!ctor) {
throw new Error(`未找到节点【${info.className}】的构造函数`);
}
// 递归创建子节点
const childNodes: IBTNode[] = [];
for (const childId of info.children || []) {
const childInfo = nodeMap.get(childId);
if (!childInfo) {
throw new Error(`未找到子节点【${childId}】,行为树配置导出信息错误`);
}
const childNode = createNodeRecursively(childInfo, nodeMap);
childNodes.push(childNode);
}
// 创建节点实例
let btnode: IBTNode;
const metadata = BT.getNodeMetadata(ctor);
if (metadata.type === BT.Type.Action || metadata.type === BT.Type.Condition) {
btnode = new ctor();
} else if (metadata.type === BT.Type.Decorator) {
btnode = new ctor(childNodes[0]!);
} else {
btnode = new ctor(...childNodes);
}
// 设置节点参数
for (const key in info.parameters) {
(btnode as any)[key] = info.parameters[key];
}
return btnode;
}
export function createBehaviorTree<T>(config: INodeConfig[], entity: T): BehaviorTree<T> {
// 验证配置
if (!config || !Array.isArray(config) || config.length === 0) {
throw new Error("Config is empty or invalid");
}
// 创建配置映射表
const nodeMap = new Map<string, INodeConfig>();
for (const info of config) {
nodeMap.set(info.id, info);
}
return new BehaviorTree(entity, createNodeRecursively(config[0]!, nodeMap));
}

View File

@@ -2,4 +2,4 @@ export enum Status {
FAILURE,
SUCCESS,
RUNNING,
}
}