Files
esengine/packages/framework/behavior-tree/src/execution/NodeExecutor.ts

182 lines
4.7 KiB
TypeScript
Raw Normal View History

import { Entity } from '@esengine/ecs-framework';
import { TaskStatus } from '../Types/TaskStatus';
import { BehaviorNodeData, BehaviorTreeData, NodeRuntimeState } from './BehaviorTreeData';
import { BehaviorTreeRuntimeComponent } from './BehaviorTreeRuntimeComponent';
/**
*
*
*
*/
export interface NodeExecutionContext {
/** 游戏Entity行为树宿主 */
readonly entity: Entity;
/** 节点数据 */
readonly nodeData: BehaviorNodeData;
/** 节点运行时状态 */
readonly state: NodeRuntimeState;
/** 运行时组件(访问黑板等) */
readonly runtime: BehaviorTreeRuntimeComponent;
/** 行为树数据(访问子节点等) */
readonly treeData: BehaviorTreeData;
/** 当前帧增量时间 */
readonly deltaTime: number;
/** 总时间 */
readonly totalTime: number;
/** 执行子节点 */
executeChild(childId: string): TaskStatus;
}
/**
*
*
*
* NodeRuntimeState中
*/
export interface INodeExecutor {
/**
*
*
* @param context
* @returns
*/
execute(context: NodeExecutionContext): TaskStatus;
/**
*
*
*
*/
reset?(context: NodeExecutionContext): void;
}
/**
*
*/
export interface CompositeExecutionResult {
/** 节点状态 */
status: TaskStatus;
/** 要激活的子节点索引列表undefined表示激活所有 */
activateChildren?: number[];
/** 是否停止所有子节点 */
stopAllChildren?: boolean;
}
/**
*
*/
export interface ICompositeExecutor extends INodeExecutor {
/**
*
*
* @param context
* @returns
*/
executeComposite(context: NodeExecutionContext): CompositeExecutionResult;
}
/**
*
*
*
*/
export class BindingHelper {
/**
*
*
* @param context
* @param configKey
* @param defaultValue
* @returns
*/
static getValue<T = any>(
context: NodeExecutionContext,
configKey: string,
defaultValue?: T
): T {
const { nodeData, runtime } = context;
if (nodeData.bindings && nodeData.bindings[configKey]) {
const blackboardKey = nodeData.bindings[configKey];
const boundValue = runtime.getBlackboardValue<T>(blackboardKey);
return boundValue !== undefined ? boundValue : (defaultValue as T);
}
const configValue = nodeData.config[configKey];
return configValue !== undefined ? configValue : (defaultValue as T);
}
/**
*
*/
static hasBinding(context: NodeExecutionContext, configKey: string): boolean {
return !!(context.nodeData.bindings && context.nodeData.bindings[configKey]);
}
/**
*
*/
static getBindingKey(context: NodeExecutionContext, configKey: string): string | undefined {
return context.nodeData.bindings?.[configKey];
}
}
/**
*
*
*
*/
export class NodeExecutorRegistry {
private executors: Map<string, INodeExecutor> = new Map();
/**
*
*
* @param implementationType BehaviorNodeData.implementationType
* @param executor
*/
register(implementationType: string, executor: INodeExecutor): void {
if (this.executors.has(implementationType)) {
console.warn(`执行器已存在,将被覆盖: ${implementationType}`);
}
this.executors.set(implementationType, executor);
}
/**
*
*/
get(implementationType: string): INodeExecutor | undefined {
return this.executors.get(implementationType);
}
/**
*
*/
has(implementationType: string): boolean {
return this.executors.has(implementationType);
}
/**
*
*/
unregister(implementationType: string): boolean {
return this.executors.delete(implementationType);
}
/**
*
*/
clear(): void {
this.executors.clear();
}
}