@esengine/ai
Version:
用于Laya、Cocos Creator等JavaScript游戏引擎的高性能AI系统库:行为树、实用AI和有限状态机
8,761 lines • 298 kB
JavaScript
/**
* @esengine/ai v2.0.25
* 高性能TypeScript AI系统库 - 行为树、实用AI和有限状态机
*
* @author yhh
* @license MIT
*/
'use strict';
/**
* 高性能伪随机数生成器
* 使用xorshift128算法,比原生Math.random()更快且质量更好
*
* @example
* ```typescript
* // 设置种子(可选,默认使用当前时间)
* Random.setSeed(12345);
*
* // 生成0-1之间的随机数
* const value = Random.value();
*
* // 生成指定范围的随机数
* const rangeValue = Random.range(10, 20);
*
* // 生成随机整数
* const intValue = Random.integer(1, 100);
*
* // 随机布尔值
* const bool = Random.boolean();
*
* // 带概率的布尔值
* const probBool = Random.chance(0.7); // 70%概率返回true
* ```
*/
class Random {
/**
* 设置随机数种子
* @param seed 种子值,如果不提供则使用当前时间
*/
static setSeed(seed) {
if (seed === undefined) {
seed = Date.now();
}
// 使用种子初始化四个状态变量
this._x = seed >>> 0;
this._y = (seed * 1812433253 + 1) >>> 0;
this._z = (this._y * 1812433253 + 1) >>> 0;
this._w = (this._z * 1812433253 + 1) >>> 0;
// 确保所有状态变量都非零
if (this._x === 0)
this._x = 1;
if (this._y === 0)
this._y = 1;
if (this._z === 0)
this._z = 1;
if (this._w === 0)
this._w = 1;
this._initialized = true;
// 预热生成器
for (let i = 0; i < 10; i++) {
this.next();
}
}
/**
* 生成下一个32位无符号整数(内部使用)
* 使用xorshift128算法
*/
static next() {
if (!this._initialized) {
this.setSeed();
}
const t = this._x ^ (this._x << 11);
this._x = this._y;
this._y = this._z;
this._z = this._w;
this._w = (this._w ^ (this._w >>> 19)) ^ (t ^ (t >>> 8));
return this._w >>> 0; // 确保返回无符号32位整数
}
/**
* 生成0到1之间的随机浮点数(不包括1)
* @returns 0 <= value < 1的随机数
*/
static value() {
return this.next() / 0x100000000; // 2^32
}
/**
* 生成指定范围内的随机浮点数
* @param min 最小值(包含)
* @param max 最大值(不包含)
* @returns min <= value < max的随机数
*/
static range(min = 0, max = 1) {
if (min >= max) {
throw new Error(`最小值(${min})必须小于最大值(${max})`);
}
return min + (max - min) * this.value();
}
/**
* 生成指定范围内的随机整数
* @param min 最小值(包含)
* @param max 最大值(包含)
* @returns min <= value <= max的随机整数
*/
static integer(min, max) {
if (!Number.isInteger(min) || !Number.isInteger(max)) {
throw new Error('最小值和最大值必须是整数');
}
if (min > max) {
throw new Error(`最小值(${min})必须小于等于最大值(${max})`);
}
return Math.floor(this.range(min, max + 1));
}
/**
* 生成随机布尔值
* @returns 随机的true或false
*/
static boolean() {
return this.value() < 0.5;
}
/**
* 根据概率生成布尔值
* @param probability 返回true的概率(0-1之间)
* @returns 根据概率返回的布尔值
*/
static chance(probability) {
if (probability < 0 || probability > 1) {
throw new Error(`概率值必须在0-1之间,当前值: ${probability}`);
}
return this.value() < probability;
}
/**
* 从数组中随机选择一个元素
* @param array 要选择的数组
* @returns 随机选中的元素
*/
static choice(array) {
if (array.length === 0) {
throw new Error('数组不能为空');
}
const index = this.integer(0, array.length - 1);
return array[index]; // 使用非空断言,因为我们已经检查了数组长度
}
/**
* 从数组中随机选择多个不重复的元素
* @param array 要选择的数组
* @param count 选择的数量
* @returns 随机选中的元素数组
*/
static sample(array, count) {
if (count < 0 || count > array.length) {
throw new Error(`选择数量(${count})必须在0-${array.length}之间`);
}
if (count === 0) {
return [];
}
if (count === array.length) {
return [...array];
}
// 对于小的选择数量,使用Set避免重复
if (count <= array.length / 2) {
const result = [];
const indices = new Set();
while (result.length < count) {
const index = this.integer(0, array.length - 1);
if (!indices.has(index)) {
indices.add(index);
result.push(array[index]);
}
}
return result;
}
else {
// 对于大的选择数量,使用Fisher-Yates洗牌算法的部分版本
const shuffled = [...array];
for (let i = 0; i < count; i++) {
const j = this.integer(i, shuffled.length - 1);
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
}
return shuffled.slice(0, count);
}
}
/**
* 生成符合正态分布的随机数(Box-Muller变换)
* @param mean 均值
* @param standardDeviation 标准差
* @returns 符合正态分布的随机数
*/
static gaussian(mean = 0, standardDeviation = 1) {
// 使用Box-Muller变换生成正态分布随机数
const u1 = this.value();
const u2 = this.value();
const z0 = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
return z0 * standardDeviation + mean;
}
/**
* 获取当前随机数生成器的状态(用于保存/恢复)
* @returns 生成器状态对象
*/
static getState() {
if (!this._initialized) {
this.setSeed();
}
return {
x: this._x,
y: this._y,
z: this._z,
w: this._w
};
}
/**
* 恢复随机数生成器的状态
* @param state 要恢复的状态对象
*/
static setState(state) {
this._x = state.x;
this._y = state.y;
this._z = state.z;
this._w = state.w;
this._initialized = true;
}
}
Random._x = 123456789;
Random._y = 362436069;
Random._z = 521288629;
Random._w = 88675123;
Random._initialized = false;
/**
* 数组扩展器和高效数据结构工具
* 提供栈、队列等数据结构的高效实现
*/
class ArrayExt {
/**
* 将数组打乱顺序(Fisher-Yates洗牌算法)
* 时间复杂度: O(n),空间复杂度: O(1)
*
* @param list 要打乱的数组
* @throws {Error} 当数组为null或undefined时抛出错误
*/
static shuffle(list) {
if (!list) {
throw new Error('数组不能为null或undefined');
}
// 优化:从后往前遍历,减少一次减法运算
for (let i = list.length - 1; i > 0; i--) {
const j = Random.integer(0, i);
// 使用解构赋值进行交换,更简洁
[list[i], list[j]] = [list[j], list[i]];
}
}
/**
* 取出数组第一个项(不移除)
* @param list 目标数组
* @returns 第一个元素
* @throws {Error} 当数组为空时抛出错误
*/
static peek(list) {
if (list.length === 0) {
throw new Error('无法从空数组中获取元素');
}
return list[0];
}
/**
* 向数组头部添加一个项
* @param list 目标数组
* @param item 要添加的项
*/
static unshift(list, item) {
list.unshift(item);
}
/**
* 移除数组第一个项并返回它
* @param list 目标数组
* @returns 移除的元素,如果数组为空则返回undefined
*/
static pop(list) {
return list.shift();
}
/**
* 向数组尾部添加一个项
* @param list 目标数组
* @param item 要添加的项
*/
static append(list, item) {
list.push(item);
}
/**
* 移除数组最后一个项并返回它
* @param list 目标数组
* @returns 移除的元素,如果数组为空则返回undefined
*/
static removeLast(list) {
return list.pop();
}
/**
* 检查数组是否为空
* @param list 目标数组
* @returns 是否为空
*/
static isEmpty(list) {
return list.length === 0;
}
/**
* 获取数组大小
* @param list 目标数组
* @returns 数组长度
*/
static size(list) {
return list.length;
}
/**
* 清空数组
* @param list 目标数组
*/
static clear(list) {
list.length = 0;
}
}
/**
* 高效的双端队列实现
* 使用环形缓冲区,避免数组头部插入的性能问题
*
* @template T 队列中元素的类型
*
* @example
* ```typescript
* const deque = new Deque<number>(32);
* deque.push(1);
* deque.unshift(0);
* console.log(deque.peekFirst()); // 0
* console.log(deque.peekLast()); // 1
* ```
*/
class Deque {
/**
* 创建双端队列
* @param initialCapacity 初始容量,必须大于0,默认16
*/
constructor(initialCapacity = 16) {
this._head = 0;
this._tail = 0;
this._size = 0;
if (initialCapacity <= 0) {
throw new Error('初始容量必须大于0');
}
this._capacity = Math.max(initialCapacity, 4);
this._buffer = new Array(this._capacity);
}
/**
* 向队列头部添加元素
* @param item 要添加的元素
*/
unshift(item) {
if (this._size === this._capacity) {
this._resize();
}
this._head = (this._head - 1 + this._capacity) % this._capacity;
this._buffer[this._head] = item;
this._size++;
}
/**
* 向队列尾部添加元素
* @param item 要添加的元素
*/
push(item) {
if (this._size === this._capacity) {
this._resize();
}
this._buffer[this._tail] = item;
this._tail = (this._tail + 1) % this._capacity;
this._size++;
}
/**
* 从队列头部移除元素
* @returns 移除的元素,如果队列为空则返回undefined
*/
shift() {
if (this._size === 0) {
return undefined;
}
const item = this._buffer[this._head];
this._buffer[this._head] = undefined;
this._head = (this._head + 1) % this._capacity;
this._size--;
return item;
}
/**
* 从队列尾部移除元素
* @returns 移除的元素,如果队列为空则返回undefined
*/
pop() {
if (this._size === 0) {
return undefined;
}
this._tail = (this._tail - 1 + this._capacity) % this._capacity;
const item = this._buffer[this._tail];
this._buffer[this._tail] = undefined;
this._size--;
return item;
}
/**
* 查看队列头部元素(不移除)
* @returns 头部元素,如果队列为空则返回undefined
*/
peekFirst() {
return this._size > 0 ? this._buffer[this._head] : undefined;
}
/**
* 查看队列尾部元素(不移除)
* @returns 尾部元素,如果队列为空则返回undefined
*/
peekLast() {
if (this._size === 0) {
return undefined;
}
const lastIndex = (this._tail - 1 + this._capacity) % this._capacity;
return this._buffer[lastIndex];
}
/**
* 获取队列大小
*/
get size() {
return this._size;
}
/**
* 检查队列是否为空
*/
get isEmpty() {
return this._size === 0;
}
/**
* 清空队列
*/
clear() {
for (let i = 0; i < this._capacity; i++) {
this._buffer[i] = undefined;
}
this._head = 0;
this._tail = 0;
this._size = 0;
}
/**
* 扩容队列(内部使用)
* 当队列满时自动调用,容量翻倍
*/
_resize() {
const newCapacity = this._capacity * 2;
const newBuffer = new Array(newCapacity);
// 复制现有元素到新缓冲区
for (let i = 0; i < this._size; i++) {
newBuffer[i] = this._buffer[(this._head + i) % this._capacity];
}
this._buffer = newBuffer;
this._head = 0;
this._tail = this._size;
this._capacity = newCapacity;
}
/**
* 将队列转换为数组
* @returns 包含队列所有元素的数组(从头到尾的顺序)
*/
toArray() {
const result = [];
for (let i = 0; i < this._size; i++) {
const item = this._buffer[(this._head + i) % this._capacity];
if (item !== undefined) {
result.push(item);
}
}
return result;
}
}
/**
* 高性能断言工具类
*
* @description
* 提供类型安全的断言方法,支持开发和生产环境的不同行为。
* 在生产环境中可以禁用断言以提高性能。
*
* @example
* ```typescript
* // 基本断言
* Assert.isTrue(player.health > 0, '玩家血量必须大于0');
* Assert.isNotNull(gameObject, '游戏对象不能为空');
*
* // 类型安全的断言
* const value: unknown = getData();
* Assert.isNumber(value, '数据必须是数字');
* // 现在 value 的类型被缩窄为 number
*
* // 配置断言行为
* Assert.setEnabled(false); // 在生产环境中禁用
* ```
*/
class Assert {
/**
* 设置是否启用断言
* @param enabled 是否启用
*/
static setEnabled(enabled) {
this._enabled = enabled;
}
/**
* 设置断言失败时的行为
* @param throwOnFailure 是否抛出异常,false则仅记录到控制台
*/
static setThrowOnFailure(throwOnFailure) {
this._throwOnFailure = throwOnFailure;
}
/**
* 断言失败处理
* @param message 错误消息
* @param args 附加参数
*/
static fail(message, ...args) {
const errorMessage = message || '断言失败';
if (this._throwOnFailure) {
throw new Error(errorMessage);
}
else {
console.assert(false, errorMessage, ...args);
throw new Error(errorMessage); // 总是抛出错误,因为这是fail方法
}
}
/**
* 断言条件为真
* @param condition 要检查的条件
* @param message 失败时的错误消息
* @param args 附加参数
*/
static isTrue(condition, message, ...args) {
if (!this._enabled)
return;
if (!condition) {
this.fail(message || '条件必须为真', ...args);
}
}
/**
* 断言条件为假
* @param condition 要检查的条件
* @param message 失败时的错误消息
* @param args 附加参数
*/
static isFalse(condition, message, ...args) {
if (!this._enabled)
return;
if (condition) {
this.fail(message || '条件必须为假', ...args);
}
}
/**
* 断言对象不为null或undefined
* @param obj 要检查的对象
* @param message 失败时的错误消息
* @param args 附加参数
*/
static isNotNull(obj, message, ...args) {
if (!this._enabled)
return;
if (obj == null) {
this.fail(message || '对象不能为null或undefined', ...args);
}
}
/**
* 断言对象为null或undefined
* @param obj 要检查的对象
* @param message 失败时的错误消息
* @param args 附加参数
*/
static isNull(obj, message, ...args) {
if (!this._enabled)
return;
if (obj != null) {
this.fail(message || '对象必须为null或undefined', ...args);
}
}
/**
* 断言值为数字类型
* @param value 要检查的值
* @param message 失败时的错误消息
* @param args 附加参数
*/
static isNumber(value, message, ...args) {
if (!this._enabled)
return;
if (typeof value !== 'number' || isNaN(value)) {
this.fail(message || '值必须是有效数字', ...args);
}
}
/**
* 断言值为字符串类型
* @param value 要检查的值
* @param message 失败时的错误消息
* @param args 附加参数
*/
static isString(value, message, ...args) {
if (!this._enabled)
return;
if (typeof value !== 'string') {
this.fail(message || '值必须是字符串', ...args);
}
}
/**
* 断言值为布尔类型
* @param value 要检查的值
* @param message 失败时的错误消息
* @param args 附加参数
*/
static isBoolean(value, message, ...args) {
if (!this._enabled)
return;
if (typeof value !== 'boolean') {
this.fail(message || '值必须是布尔值', ...args);
}
}
/**
* 断言值为函数类型
* @param value 要检查的值
* @param message 失败时的错误消息
* @param args 附加参数
*/
static isFunction(value, message, ...args) {
if (!this._enabled)
return;
if (typeof value !== 'function') {
this.fail(message || '值必须是函数', ...args);
}
}
/**
* 断言值为对象类型(非null)
* @param value 要检查的值
* @param message 失败时的错误消息
* @param args 附加参数
*/
static isObject(value, message, ...args) {
if (!this._enabled)
return;
if (typeof value !== 'object' || value === null) {
this.fail(message || '值必须是对象', ...args);
}
}
/**
* 断言数组不为空
* @param array 要检查的数组
* @param message 失败时的错误消息
* @param args 附加参数
*/
static isNotEmpty(array, message, ...args) {
if (!this._enabled)
return;
this.isNotNull(array, message, ...args);
if (array.length === 0) {
this.fail(message || '数组不能为空', ...args);
}
}
/**
* 断言字符串不为空
* @param str 要检查的字符串
* @param message 失败时的错误消息
* @param args 附加参数
*/
static isNotEmptyString(str, message, ...args) {
if (!this._enabled)
return;
this.isNotNull(str, message, ...args);
if (str.trim().length === 0) {
this.fail(message || '字符串不能为空', ...args);
}
}
/**
* 断言数值在指定范围内
* @param value 要检查的数值
* @param min 最小值(包含)
* @param max 最大值(包含)
* @param message 失败时的错误消息
* @param args 附加参数
*/
static inRange(value, min, max, message, ...args) {
if (!this._enabled)
return;
this.isNumber(value, message, ...args);
if (value < min || value > max) {
this.fail(message || `值必须在 ${min} 到 ${max} 之间`, ...args);
}
}
/**
* 断言值是指定类型的实例
* @param value 要检查的值
* @param constructor 构造函数
* @param message 失败时的错误消息
* @param args 附加参数
*/
static isInstanceOf(value, constructor, message, ...args) {
if (!this._enabled)
return;
if (!(value instanceof constructor)) {
this.fail(message || `值必须是 ${constructor.name} 的实例`, ...args);
}
}
/**
* 断言数组包含指定元素
* @param array 要检查的数组
* @param element 要查找的元素
* @param message 失败时的错误消息
* @param args 附加参数
*/
static contains(array, element, message, ...args) {
if (!this._enabled)
return;
this.isNotNull(array, message, ...args);
if (!array.includes(element)) {
this.fail(message || '数组必须包含指定元素', ...args);
}
}
/**
* 获取当前断言配置
* @returns 配置对象
*/
static getConfig() {
return {
enabled: this._enabled,
throwOnFailure: this._throwOnFailure
};
}
}
/** 是否启用断言检查 */
Assert._enabled = true;
/** 是否在断言失败时抛出异常而不是仅记录 */
Assert._throwOnFailure = false;
/**
* 日志级别枚举
*/
exports.LogLevel = void 0;
(function (LogLevel) {
/** 调试信息 */
LogLevel[LogLevel["Debug"] = 0] = "Debug";
/** 一般信息 */
LogLevel[LogLevel["Info"] = 1] = "Info";
/** 警告信息 */
LogLevel[LogLevel["Warn"] = 2] = "Warn";
/** 错误信息 */
LogLevel[LogLevel["Error"] = 3] = "Error";
/** 关闭日志 */
LogLevel[LogLevel["None"] = 4] = "None";
})(exports.LogLevel || (exports.LogLevel = {}));
/**
* 高性能日志系统
*
* @description
* 提供分级日志记录功能,支持性能优化模式。
* 在性能模式下,会跳过不必要的字符串格式化和时间戳计算。
* 支持批量输出和延迟日志记录。
*
* @example
* ```typescript
* // 基本使用
* Logger.info('游戏开始');
* Logger.warn('玩家血量低', { health: 10 });
* Logger.error('网络连接失败', error);
*
* // 配置日志系统
* Logger.configure({
* minLevel: LogLevel.Warn,
* enableTimestamp: true,
* performanceMode: false,
* batchMode: true,
* batchSize: 50
* });
*
* // 性能敏感的代码中
* Logger.setPerformanceMode(true);
* ```
*/
class Logger {
/**
* 配置日志系统
* @param config 日志配置
*/
static configure(config) {
this._config = { ...this._config, ...config };
// 配置批量模式
if (config.batchMode !== undefined) {
this._batchConfig.enabled = config.batchMode;
}
if (config.batchSize !== undefined) {
this._batchConfig.maxSize = Math.max(1, config.batchSize);
}
if (config.batchFlushInterval !== undefined) {
this._batchConfig.flushInterval = Math.max(100, config.batchFlushInterval);
}
// 初始化性能模式
this._initializePerformanceMode();
}
/**
* 初始化性能模式
*/
static _initializePerformanceMode() {
if (this._config.performanceMode) {
// 在性能模式下,使用最简化的日志函数
this._fastLog = (message, data) => {
if (data !== undefined) {
console.log(message, data);
}
else {
console.log(message);
}
};
}
else {
this._fastLog = null;
}
}
/**
* 设置最小日志级别
* @param level 最小日志级别
*/
static setMinLevel(level) {
this._config.minLevel = level;
}
/**
* 设置性能模式
* @param enabled 是否启用性能模式
*/
static setPerformanceMode(enabled) {
this._config.performanceMode = enabled;
this._initializePerformanceMode();
}
/**
* 启用批量模式
* @param enabled 是否启用
* @param maxSize 批量大小
* @param flushInterval 刷新间隔(毫秒)
*/
static setBatchMode(enabled, maxSize = 50, flushInterval = 1000) {
this._batchConfig.enabled = enabled;
this._batchConfig.maxSize = Math.max(1, maxSize);
this._batchConfig.flushInterval = Math.max(100, flushInterval);
if (!enabled) {
this.flushLogs(); // 禁用时立即刷新所有日志
}
}
/**
* 记录调试信息
* @param message 消息
* @param data 附加数据
*/
static debug(message, data) {
this._log(exports.LogLevel.Debug, message, data);
}
/**
* 记录一般信息
* @param message 消息
* @param data 附加数据
*/
static info(message, data) {
this._log(exports.LogLevel.Info, message, data);
}
/**
* 记录警告信息
* @param message 消息
* @param data 附加数据
*/
static warn(message, data) {
this._log(exports.LogLevel.Warn, message, data);
}
/**
* 记录错误信息
* @param message 消息
* @param error 错误对象或附加数据
*/
static error(message, error) {
this._log(exports.LogLevel.Error, message, error);
}
/**
* 内部日志记录方法
* @param level 日志级别
* @param message 消息
* @param data 附加数据
*/
static _log(level, message, data) {
// 检查日志级别
if (level < this._config.minLevel || this._config.minLevel === exports.LogLevel.None) {
return;
}
if (this._config.performanceMode && this._fastLog) {
// 超高性能模式:跳过所有格式化
this._fastLog(message, data);
return;
}
if (this._batchConfig.enabled) {
// 批量模式:添加到缓冲区
this._addToBatch(level, message, data);
}
else if (this._config.performanceMode) {
// 性能模式:简化输出
this._performanceLog(level, message, data);
}
else {
// 标准模式:完整格式化
this._standardLog(level, message, data);
}
}
/**
* 添加日志到批量缓冲区
*/
static _addToBatch(level, message, data) {
const entry = {
level,
message,
data,
timestamp: Date.now(),
prefix: this._config.prefix
};
this._logBuffer.push(entry);
// 检查是否需要刷新
const now = Date.now();
const shouldFlushBySize = this._logBuffer.length >= this._batchConfig.maxSize;
const shouldFlushByTime = (now - this._batchConfig.lastFlushTime) >= this._batchConfig.flushInterval;
if (shouldFlushBySize || shouldFlushByTime) {
this.flushLogs();
}
}
/**
* 刷新批量日志
*/
static flushLogs() {
if (this._logBuffer.length === 0) {
return;
}
// 批量输出所有日志
for (const entry of this._logBuffer) {
if (this._config.performanceMode) {
this._performanceLogEntry(entry);
}
else {
this._standardLogEntry(entry);
}
}
// 清空缓冲区
this._logBuffer.length = 0;
this._batchConfig.lastFlushTime = Date.now();
}
/**
* 性能模式输出日志条目
*/
static _performanceLogEntry(entry) {
const levelName = this._levelNames[entry.level];
const prefix = entry.prefix ? `[${entry.prefix}] ` : '';
if (entry.data !== undefined) {
console.log(`${prefix}[${levelName}] ${entry.message}`, entry.data);
}
else {
console.log(`${prefix}[${levelName}] ${entry.message}`);
}
}
/**
* 标准模式输出日志条目
*/
static _standardLogEntry(entry) {
const timestamp = this._config.enableTimestamp ? this._formatTimestamp(entry.timestamp) : '';
const levelName = this._levelNames[entry.level];
const prefix = entry.prefix ? `[${entry.prefix}] ` : '';
const style = this._levelStyles[entry.level];
let logMessage = `${prefix}${timestamp}[${levelName}] ${entry.message}`;
const consoleMethod = this._getConsoleMethod(entry.level);
if (entry.data !== undefined) {
if (style && typeof console.log === 'function') {
consoleMethod(`%c${logMessage}`, style, entry.data);
}
else {
consoleMethod(logMessage, entry.data);
}
}
else {
if (style && typeof console.log === 'function') {
consoleMethod(`%c${logMessage}`, style);
}
else {
consoleMethod(logMessage);
}
}
// 错误级别且启用堆栈跟踪
if (entry.level === exports.LogLevel.Error && this._config.enableStackTrace && entry.data instanceof Error) {
console.trace(entry.data);
}
}
/**
* 格式化时间戳
*/
static _formatTimestamp(timestamp) {
const date = new Date(timestamp);
const hours = date.getHours().toString().padStart(2, '0');
const minutes = date.getMinutes().toString().padStart(2, '0');
const seconds = date.getSeconds().toString().padStart(2, '0');
const milliseconds = date.getMilliseconds().toString().padStart(3, '0');
return `[${hours}:${minutes}:${seconds}.${milliseconds}] `;
}
/**
* 性能模式日志输出
* @param level 日志级别
* @param message 消息
* @param data 附加数据
*/
static _performanceLog(level, message, data) {
const levelName = this._levelNames[level];
const prefix = this._config.prefix ? `[${this._config.prefix}] ` : '';
if (data !== undefined) {
console.log(`${prefix}[${levelName}] ${message}`, data);
}
else {
console.log(`${prefix}[${levelName}] ${message}`);
}
}
/**
* 标准模式日志输出
* @param level 日志级别
* @param message 消息
* @param data 附加数据
*/
static _standardLog(level, message, data) {
const timestamp = this._config.enableTimestamp ? this._getTimestamp() : '';
const levelName = this._levelNames[level];
const prefix = this._config.prefix ? `[${this._config.prefix}] ` : '';
const style = this._levelStyles[level];
let logMessage = `${prefix}${timestamp}[${levelName}] ${message}`;
// 根据日志级别选择合适的console方法
const consoleMethod = this._getConsoleMethod(level);
if (data !== undefined) {
if (style && typeof console.log === 'function') {
consoleMethod(`%c${logMessage}`, style, data);
}
else {
consoleMethod(logMessage, data);
}
}
else {
if (style && typeof console.log === 'function') {
consoleMethod(`%c${logMessage}`, style);
}
else {
consoleMethod(logMessage);
}
}
// 错误级别且启用堆栈跟踪
if (level === exports.LogLevel.Error && this._config.enableStackTrace && data instanceof Error) {
console.trace(data);
}
}
/**
* 获取时间戳字符串
* @returns 格式化的时间戳
*/
static _getTimestamp() {
const now = new Date();
const hours = now.getHours().toString().padStart(2, '0');
const minutes = now.getMinutes().toString().padStart(2, '0');
const seconds = now.getSeconds().toString().padStart(2, '0');
const milliseconds = now.getMilliseconds().toString().padStart(3, '0');
return `[${hours}:${minutes}:${seconds}.${milliseconds}] `;
}
/**
* 根据日志级别获取对应的console方法
* @param level 日志级别
* @returns console方法
*/
static _getConsoleMethod(level) {
switch (level) {
case exports.LogLevel.Debug:
return console.debug || console.log;
case exports.LogLevel.Info:
return console.info || console.log;
case exports.LogLevel.Warn:
return console.warn || console.log;
case exports.LogLevel.Error:
return console.error || console.log;
default:
return console.log;
}
}
/**
* 获取当前配置
* @returns 当前日志配置的副本
*/
static getConfig() {
return { ...this._config };
}
/**
* 创建带前缀的日志器
* @param prefix 前缀
* @returns 新的日志器实例
*/
static createPrefixed(prefix) {
return new PrefixedLogger(prefix);
}
}
Logger._config = {
minLevel: exports.LogLevel.Debug,
enableTimestamp: true,
enableStackTrace: true,
performanceMode: false,
prefix: ''
};
/** 批量日志缓冲区 */
Logger._logBuffer = [];
/** 批量模式配置 */
Logger._batchConfig = {
enabled: false,
maxSize: 50,
flushInterval: 1000, // 1秒
lastFlushTime: 0
};
/** 性能模式下的简化日志函数 */
Logger._fastLog = null;
/** 日志级别名称映射 */
Logger._levelNames = {
[exports.LogLevel.Debug]: 'DEBUG',
[exports.LogLevel.Info]: 'INFO',
[exports.LogLevel.Warn]: 'WARN',
[exports.LogLevel.Error]: 'ERROR',
[exports.LogLevel.None]: 'NONE'
};
/** 日志级别样式映射(用于浏览器控制台) */
Logger._levelStyles = {
[exports.LogLevel.Debug]: 'color: #888',
[exports.LogLevel.Info]: 'color: #007acc',
[exports.LogLevel.Warn]: 'color: #ff8c00',
[exports.LogLevel.Error]: 'color: #ff4444; font-weight: bold',
[exports.LogLevel.None]: ''
};
/**
* 带前缀的日志器
* 用于为特定模块或组件创建专用的日志器
*/
class PrefixedLogger {
constructor(_prefix) {
this._prefix = _prefix;
}
debug(message, data) {
Logger.debug(`[${this._prefix}] ${message}`, data);
}
info(message, data) {
Logger.info(`[${this._prefix}] ${message}`, data);
}
warn(message, data) {
Logger.warn(`[${this._prefix}] ${message}`, data);
}
error(message, error) {
Logger.error(`[${this._prefix}] ${message}`, error);
}
}
/**
* 全局时间管理器
*
* @description
* 提供高性能的时间管理功能,减少重复的时间计算开销。
* 使用时间池化技术,在每帧开始时统一计算时间,避免多次调用performance.now()。
*
* @example
* ```typescript
* // 在游戏主循环开始时更新时间
* TimeManager.updateFrame();
*
* // 获取当前时间(无额外计算开销)
* const currentTime = TimeManager.getCurrentTime();
* const deltaTime = TimeManager.getDeltaTime();
*
* // 配置时间管理器
* TimeManager.configure({
* maxDeltaTime: 0.1,
* timeScale: 1.0,
* useHighPrecision: true
* });
* ```
*/
class TimeManager {
/**
* 配置时间管理器
* @param config 配置选项
*/
static configure(config) {
if (config.maxDeltaTime !== undefined) {
this._maxDeltaTime = Math.max(0.001, config.maxDeltaTime);
}
if (config.timeScale !== undefined) {
this._timeScale = Math.max(0, config.timeScale);
}
if (config.useHighPrecision !== undefined) {
this._useHighPrecision = config.useHighPrecision;
}
}
/**
* 初始化时间管理器
*/
static initialize() {
if (this._initialized) {
return;
}
const now = this._getSystemTime();
this._startTime = now;
this._currentTime = 0;
this._lastTime = 0;
this._deltaTime = 0;
this._unscaledDeltaTime = 0;
this._frameCount = 0;
this._initialized = true;
}
/**
* 更新帧时间(应在每帧开始时调用)
* @param externalDeltaTime 可选的外部提供的时间差
*/
static updateFrame(externalDeltaTime) {
if (!this._initialized) {
this.initialize();
}
this._frameCount++;
if (externalDeltaTime !== undefined) {
// 使用外部提供的时间差
this._unscaledDeltaTime = Math.max(0, externalDeltaTime);
}
else {
// 计算时间差
const systemTime = this._getSystemTime();
const currentSystemTime = (systemTime - this._startTime) / 1000;
if (this._frameCount === 1) {
// 第一帧,设置初始时间
this._lastTime = currentSystemTime;
this._unscaledDeltaTime = 0;
}
else {
this._unscaledDeltaTime = currentSystemTime - this._lastTime;
}
}
// 限制最大时间差,防止时间跳跃
this._unscaledDeltaTime = Math.min(this._unscaledDeltaTime, this._maxDeltaTime);
// 应用时间缩放
this._deltaTime = this._unscaledDeltaTime * this._timeScale;
// 更新当前时间
this._lastTime = this._currentTime;
this._currentTime += this._deltaTime;
// 触发时间更新回调
this._triggerUpdateCallbacks();
}
/**
* 获取系统时间(毫秒)
*/
static _getSystemTime() {
return this._useHighPrecision ? performance.now() : Date.now();
}
/**
* 触发时间更新回调
*/
static _triggerUpdateCallbacks() {
for (let i = 0; i < this._updateCallbacks.length; i++) {
try {
this._updateCallbacks[i](this._deltaTime);
}
catch (error) {
console.error('时间更新回调执行失败:', error);
}
}
}
/**
* 获取当前时间(秒)
* @returns 从初始化开始的累计时间
*/
static getCurrentTime() {
return this._currentTime;
}
/**
* 获取帧间时间差(秒)
* @returns 当前帧与上一帧的时间差
*/
static getDeltaTime() {
return this._deltaTime;
}
/**
* 获取未缩放的帧间时间差(秒)
* @returns 未应用时间缩放的帧间时间差
*/
static getUnscaledDeltaTime() {
return this._unscaledDeltaTime;
}
/**
* 获取时间缩放比例
*/
static getTimeScale() {
return this._timeScale;
}
/**
* 设置时间缩放比例
* @param scale 缩放比例,0表示暂停,1表示正常速度
*/
static setTimeScale(scale) {
this._timeScale = Math.max(0, scale);
}
/**
* 获取帧计数
*/
static getFrameCount() {
return this._frameCount;
}
/**
* 获取平均帧率
*/
static getAverageFPS() {
if (this._currentTime <= 0) {
return 0;
}
return this._frameCount / this._currentTime;
}
/**
* 获取当前帧率
*/
static getCurrentFPS() {
if (this._deltaTime <= 0) {
return 0;
}
return 1 / this._unscaledDeltaTime;
}
/**
* 添加时间更新回调
* @param callback 回调函数
*/
static addUpdateCallback(callback) {
if (this._updateCallbacks.indexOf(callback) === -1) {
this._updateCallbacks.push(callback);
}
}
/**
* 移除时间更新回调
* @param callback 要移除的回调函数
*/
static removeUpdateCallback(callback) {
const index = this._updateCallbacks.indexOf(callback);
if (index !== -1) {
this._updateCallbacks.splice(index, 1);
}
}
/**
* 清除所有时间更新回调
*/
static clearUpdateCallbacks() {
this._updateCallbacks.length = 0;
}
/**
* 重置时间管理器
*/
static reset() {
this._initialized = false;
this._frameCount = 0;
this._currentTime = 0;
this._lastTime = 0;
this._deltaTime = 0;
this._unscaledDeltaTime = 0;
this.clearUpdateCallbacks();
}
/**
* 获取时间管理器统计信息
*/
static getStats() {
return {
currentTime: this._currentTime,
deltaTime: this._deltaTime,
unscaledDeltaTime: this._unscaledDeltaTime,
timeScale: this._timeScale,
frameCount: this._frameCount,
averageFPS: this.getAverageFPS(),
currentFPS: this.getCurrentFPS(),
maxDeltaTime: this._maxDeltaTime,
useHighPrecision: this._useHighPrecision
};
}
}
/** 当前时间(秒) */
TimeManager._currentTime = 0;
/** 上一帧时间(秒) */
TimeManager._lastTime = 0;
/** 帧间时间差(秒) */
TimeManager._deltaTime = 0;
/** 未缩放的帧间时间差(秒) */
TimeManager._unscaledDeltaTime = 0;
/** 时间缩放比例 */
TimeManager._timeScale = 1.0;
/** 最大允许的帧间时间差(防止时间跳跃) */
TimeManager._maxDeltaTime = 0.1;
/** 是否使用高精度时间 */
TimeManager._useHighPrecision = true;
/** 是否已初始化 */
TimeManager._initialized = false;
/** 帧计数器 */
TimeManager._frameCount = 0;
/** 启动时间 */
TimeManager._startTime = 0;
/** 时间更新回调列表 */
TimeManager._updateCallbacks = [];
/**
* 错误处理级别枚举
*/
exports.ErrorLevel = void 0;
(function (ErrorLevel) {
/** 开发模式 - 严格检查,抛出所有错误 */
ErrorLevel[ErrorLevel["Development"] = 0] = "Development";
/** 测试模式 - 记录错误但不中断执行 */
ErrorLevel[ErrorLevel["Testing"] = 1] = "Testing";
/** 生产模式 - 最小化错误处理,优先性能 */
ErrorLevel[ErrorLevel["Production"] = 2] = "Production";
/** 静默模式 - 完全禁用错误处理 */
ErrorLevel[ErrorLevel["Silent"] = 3] = "Silent";
})(exports.ErrorLevel || (exports.ErrorLevel = {}));
/**
* 高性能错误处理系统
*
* @description
* 提供可配置的错误处理策略,支持开发和生产环境的不同行为。
* 在生产环境中可以完全禁用错误检查以提高性能。
*
* @example
* ```typescript
* // 配置错误处理器
* ErrorHandler.configure({
* level: ErrorLevel.Development,
* enableAssertions: true,
* enableTypeChecking: true
* });
*
* // 使用断言
* ErrorHandler.assert(player.health > 0, '玩家血量必须大于0');
*
* // 类型检查
* ErrorHandler.checkType(value, 'number', '值必须是数字');
*
* // 性能监控
* const result = ErrorHandler.monitor('expensiveFunction', () => {
* return expensiveOperation();
* });
* ```
*/
class ErrorHandler {
/**
* 配置错误处理器
* @param config 配置选项
*/
static configure(config) {
this._config = { ...this._config, ...config };
}
/**
* 设置错误处理级别
* @param level 错误处理级别
*/
static setLevel(level) {
this._config.level = level;
// 根据级别自动调整其他配置
switch (level) {
case exports.ErrorLevel.Development:
this._config.enableAssertions = true;
this._config.enableTypeChecking = true;
break;
case exports.ErrorLevel.Testing:
this._config.enableAssertions = true;
this._config.enableTypeChecking = false;
break;
case exports.ErrorLevel.Production:
this._config.enableAssertions = false;
this._config.enableTypeChecking = false;
break;
case exports.ErrorLevel.Silent:
this._config.enableAssertions = false;
this._config.enableTypeChecking = false;
this._config.enablePerformanceMonitoring = false;
break;
}
}
/**
* 断言检查
* @param condition 条件
* @param message 错误消息
* @param context 上下文信息
*/
static assert(condition, message, context) {
if (!this._config.enableAssertions || this._config.level === exports.ErrorLevel.Silent) {
return;
}
this._errorStats.totalAssertions++;
if (!condition) {
const error = new Error(`断言失败: ${message}`);
this._handleError(error, context);
}
}
/**
* 类型检查
* @param value 要检查的值
* @param expectedType 期望的类型
* @param message 错误消息
* @param context 上下文信息
*/
static checkType(value, expectedType, message, context) {
if (!this._config.enableTypeChecking || this._config.level === exports.ErrorLevel.Silent) {
return;
}
this._errorStats.totalTypeChecks++;
const actualType = typeof value;
if (actualType !== expectedType) {
const errorMessage = message || `类型检查失败: 期望 ${expectedType}, 实际 ${actualType}`;
const error = new Error(errorMessage);
this._handleError(error, context);
}
}
/**
* 非空检查
* @param value 要检查的值
* @param message 错误消息
* @param context 上下文信息
*/
static checkNotNull(value, message, context) {
if (!this._config.enableTypeChecking || this._config.level === exports.ErrorLevel.Silent) {
return;
}
this._errorStats.totalTypeChecks++;
if (value == null) {
const errorMessage = message || '值不能为null或undefined';
const error = new Error(errorMessage);
this._handleError(error, context);
}
}
/**
* 范围检查
* @param value 要检查的值
* @param min 最小值
* @param max 最大值
* @param message 错误消息
* @param context 上下文信息
*/
static checkRange(value, min, max, message, context) {
if (!this._config.enableAssertions || this._config.level === exports.ErrorLevel.Silent) {
return;
}
this._errorStats.totalAssertions++;
if (value < min || value > max) {
const errorMessage = message || `值 ${value} 超出范围 [${min}, ${max}]`;
const error = new Error(errorMessage);
this._handleError(error, context);
}
}
/**
* 数组边界检查
* @param array 数组
* @param index 索引
* @param message 错误消息
* @param context 上下文信息
*/
static checkArrayBounds(array, index, message, context) {
if (!this._config.enableAssertions || this._config.level === exports.ErrorLevel.Silent) {
return;
}
this._errorStats.totalAssertions++;
if (index < 0 || index >= array.length) {
const errorMessage = message || `数组索引 ${index} 超出边界 [0, ${array.length - 1}]`;
const error = new Error(errorMessage);
this._handleError(error, context);
}
}
/**
* 性能监控装饰器
* @param name 函数名称
* @param fn 要监控的函数
* @returns 函数执行结果
*/
static monitor(name, fn) {
if (!this._config.enablePerformanceMonitoring || this._config.level === exports.ErrorLevel.Silent) {
return fn();
}
const startTime = performance.now();
try {
const result = fn();
const endTime = performance.now();
this._recordPerformance(name, endTime - startTime);
return result;
}
catch (error) {
const endTime = performance.now();
this._recordPerformance(name, endTime - startTime);
throw error;
}
}
/**
* 异步性能监控
* @param name 函数名称
* @param fn 要监控的异步函数
* @returns Promise结果
*/
static async monitorAsync(name, fn) {
if (!this._config.enablePerformanceMonitoring || this._config.level === exports.ErrorLevel.Silent) {
return fn();
}
const startTime = performance.now();
try {
const result = await fn();
const endTime = performance.now();
this._recordPerformance(name, endTime - startTime);
return result;
}
catch (error) {
const endTime = performance.now();
this._recordPerformance(name, endTime - startTime);
throw error;
}
}
/**
* 记录性能数据
*/
static _recordPerformance(name, executionTime) {
let data = this._performanceData.get(name);
if (!data) {
data = {
functionName: name,
executionTime: 0,
callCount: 0,
averageTime: 0,
maxTime: 0,
minTime: Infinity
};
this._performanceData.set(name, data);
}
data.callCount++;
data.executionTime += executionTime;
data.averageTime = data.executionTime / data.callCount;
data.maxTime = Math.max(data.maxTime, executionTime);
data.minTime = Math.min(data.minTime, executionTime);
}
/**
* 处理错误
*/
static _handleError(error, context) {
this._errorStats.totalErrors++;
// 调用错误回调
if (this._config.onError) {
try {
this._config.onError(error, context);
}
catch (callbackError) {
console.error('错误回调执行失败:', callbackError);
}
}
// 根据错误级别决定行为
switch (this._config.level) {
case exports.ErrorLevel.Development:
throw error; // 开发模式:抛出错误
case exports.ErrorLevel.Testing:
console.error('错误:', error.message, context);
throw error; // 测试模式:记录并抛出
case exports.ErrorLevel.Production:
console.warn('错误:', error.message);
throw error; // 生产模式:警告并抛出
case exports.ErrorLevel.Silent:
// 静默模式:什么都不做
break;
}
throw error; // 默认行为
}
/**
* 发出警告
* @param message 警告消息
* @param context 上下文信息
*/
static warn(message, context) {
if (this._config.level === exports.ErrorLevel.Silent) {
return;
}
this._errorStats.totalWarnings++;
// 调用警告回调
if (this._config.onWarning) {
try {
this._config.onWarning(message, context);
}
catch (callbackError) {
console.error('警告回调执行失败:', callbackError);
}
}
// 根据错误级别决定输出方式
switch (this._config.level) {
case exports.ErrorLevel.Development:
case exports.ErrorLevel.Testing:
console.warn('警告:', message, context);
break;
case exports.ErrorLevel.Production:
console.warn('警告:', message);
break;
}
}
/**
* 获取性能统计信息
*/
static getPerformanceStats() {
return new Map(this._performanceData);
}
/**
* 获取错误统计信息
*/
static getErrorStats() {
return { ...this._errorStats };
}
/**
* 重置统计信息
*/
static resetStats() {
this._performanceData.clear();
this._errorStats = {
totalErrors: 0,
totalWarnings: 0,
totalAssertions: 0,
totalTypeChecks: 0
};
}
/**
* 获取当前配置
*/
static getConfig() {
return { ...this._config };
}
/**
* 创建带错误处理的函数包装器
* @param fn 原函数
* @param name 函数名称
* @param enableMonitoring 是否启用性能监控
* @returns 包装后的函数
*/
static wrap(fn, name, enableMonitoring = false) {
return (...args) => {
try {
if (enableMonitoring) {
return this.monitor(name, () => fn(...args));
}
else {
return fn(...args);
}
}
catch (error) {
this._handleError(error instanceof Error ? error : new Error(String(error)), { args, functionName: name });
}
};
}
}
ErrorHandler._config = {
level: exports.ErrorLevel.Development,
enableAssertions: true,
enableTypeChecking: true,
enablePerformanceMonitoring: false
};
/** 性能监控数据 */
ErrorHandler._performanceData = new Map();
/** 错误统计 */
ErrorHandler._errorStats = {
totalErrors: 0,
totalWarnings: 0,
totalAssertions: 0,
totalTypeChecks: 0
};
/**
* 错误处理装饰器工厂
* @param options 装饰器选项
*/
function errorHandler(options = {}) {
return function (target, propertyKey, descriptor) {
const originalMethod = descriptor.value;
const methodName = options.name || `${target.constructor.name}.${propertyKey}`;
descriptor.value = function (...args) {
// 类型检查
if (options.enableTypeChecking) {
for (let i = 0; i < args.length; i++) {
if (args[i] == null) {
ErrorHandler.warn(`方法 ${methodName} 的第 ${i + 1} 个参数为null或undefined`);
}
}
}
// 执行方法
if (options.enableMonitoring) {
return ErrorHandler.monitor(methodName, () => originalMethod.apply(this, args));
}
else {
try {
return originalMethod.apply(this, args);
}
catch (error) {
const errorInstance = error instanceof Error ? error : new Error(String(error));
ErrorHandler.warn(`方法 ${methodName} 执行失败`, { error: errorInstance, args, instance: this });
throw errorInstance;
}
}
};
return descriptor;
};
}
/**
* 高性能事件管理器
*
* @description
* 提供带自动清理机制的事件管理系统,防止内存泄漏。
* 支持弱引用、优先级、一次性监听器等高级功能。
*
* @example
* ```typescript
* const eventManager = new EventManager({
* enableAutoCleanup: true,
* cleanupInterval: 30000, // 30秒清理一次
* maxListeners: 1000
* });
*
* // 添加监听器
* const listenerId = eventManager.on('playerDeath', (data) => {
* console.log('玩家死亡:', data);
* });
*
* // 添加弱引用监听器(自动清理)
* eventManager.onWeak('gameUpdate', callback, gameObject);
*
* // 触发事件
* eventManager.emit('playerDeath', { playerId: 123 });
*
* // 移除监听器
* eventManager.off('playerDeath', listenerId);
* ```
*/
class EventManager {
/**
* 创建事件管理器
* @param config 配置选项
*/
constructor(config = {}) {
this._listeners = new Map();
this._cleanupTimer = null;
this._nextListenerId = 1;
this._config = {
enableAutoCleanup: config.enableAutoCleanup ?? true,
cleanupInterval: config.cleanupInterval ?? 30000, // 30秒
maxListeners: config.maxListeners ?? 1000,
listenerExpirationTime: config.listenerExpirationTime ?? 300000, // 5分钟
enablePerformanceMonitoring: config.enablePerformanceMonitoring ?? false
};
this._stats = {
totalListeners: 0,
activeListeners: 0,
totalEvents: 0,
averageEventTime: 0,
lastCleanupTime: Date.now()
};
// 启动自动清理
if (this._config.enableAutoCleanup) {
this._startAutoCleanup();
}
}
/**
* 添加事件监听器
* @param eventName 事件名称
* @param callback 回调函数
* @param options 监听器选项
* @returns 监听器ID
*/
on(eventName, callback, options = {}) {
const listenerId = this._generateListenerId();
const listener = {
callback,
id: listenerId,
createdAt: Date.now(),
lastCalledAt: 0,
callCount: 0,
once: options.once ?? false,
priority: options.priority ?? 0,
weak: options.weak ?? false,
owner: options.owner || undefined
};
// 检查监听器数量限制
if (this._stats.totalListeners >= this._config.maxListeners) {
console.warn(`事件监听器数量已达到上限 ${this._config.maxListeners}`);
this._performCleanup(); // 尝试清理
if (this._stats.totalListeners >= this._config.maxListeners) {
throw new Error('无法添加更多事件监听器,已达到上限');
}
}
// 添加到监听器列表
if (!this._listeners.has(eventName)) {
this._listeners.set(eventName, []);
}
const listeners = this._listeners.get(eventName);
listeners.push(listener);
// 按优先级排序(高优先级在前)
listeners.sort((a, b) => b.priority - a.priority);
this._stats.totalListeners++;
this._updateActiveListeners();
return listenerId;
}
/**
* 添加弱引用监听器(自动清理)
* @param eventName 事件名称
* @param callback 回调函数
* @param owner 拥有者对象
* @param options 其他选项
* @returns 监听器ID
*/
onWeak(eventName, callback, owner, options = {}) {
return this.on(eventName, callback, {
...options,
weak: true,
owner
});
}
/**
* 添加一次性监听器
* @param eventName 事件名称
* @param callback 回调函数
* @param options 其他选项
* @returns 监听器ID
*/
once(eventName, callback, options = {}) {
return this.on(eventName, callback, {
...options,
once: true
});
}
/**
* 移除事件监听器
* @param eventName 事件名称
* @param listenerId 监听器ID
* @returns 是否成功移除
*/
off(eventName, listenerId) {
const listeners = this._listeners.get(eventName);
if (!listeners) {
return false;
}
const index = listeners.findIndex(listener => listener.id === listenerId);
if (index === -1) {
return false;
}
listeners.splice(index, 1);
this._stats.totalListeners--;
// 如果没有监听器了,删除事件
if (listeners.length === 0) {
this._listeners.delete(eventName);
}
this._updateActiveListeners();
return true;
}
/**
* 移除所有指定事件的监听器
* @param eventName 事件名称
* @returns 移除的监听器数量
*/
offAll(eventName) {
const listeners = this._listeners.get(eventName);
if (!listeners) {
return 0;
}
const count = listeners.length;
this._listeners.delete(eventName);
this._stats.totalListeners -= count;
this._updateActiveListeners();
return count;
}
/**
* 移除拥有者的所有监听器
* @param owner 拥有者对象
* @returns 移除的监听器数量
*/
offByOwner(owner) {
let removedCount = 0;
for (const [eventName, listeners] of this._listeners) {
for (let i = listeners.length - 1; i >= 0; i--) {
const listener = listeners[i];
if (listener.owner === owner) {
listeners.splice(i, 1);
removedCount++;
this._stats.totalListeners--;
}
}
// 如果没有监听器了,删除事件
if (listeners.length === 0) {
this._listeners.delete(eventName);
}
}
this._updateActiveListeners();
return removedCount;
}
/**
* 触发事件
* @param eventName 事件名称
* @param data 事件数据
* @returns 成功调用的监听器数量
*/
emit(eventName, data) {
const listeners = this._listeners.get(eventName);
if (!listeners || listeners.length === 0) {
return 0;
}
const startTime = this._config.enablePerformanceMonitoring ? performance.now() : 0;
let successCount = 0;
const toRemove = [];
// 执行监听器
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i];
// 检查弱引用是否还有效(简化版本)
if (listener.weak && listener.owner) ;
try {
listener.callback(data);
listener.lastCalledAt = Date.now();
listener.callCount++;
successCount++;
// 如果是一次性监听器,标记为移除
if (listener.once) {
toRemove.push(i);
}
}
catch (error) {
console.error(`事件监听器执行失败 (${eventName}):`, error);
}
}
// 移除标记的监听器(从后往前移除,避免索引问题)
for (let i = toRemove.length - 1; i >= 0; i--) {
const index = toRemove[i];
listeners.splice(index, 1);
this._stats.totalListeners--;
}
// 如果没有监听器了,删除事件
if (listeners.length === 0) {
this._listeners.delete(eventName);
}
// 更新统计信息
this._stats.totalEvents++;
if (this._config.enablePerformanceMonitoring && startTime > 0) {
const executionTime = performance.now() - startTime;
this._updateAverageEventTime(executionTime);
}
this._updateActiveListeners();
return successCount;
}
/**
* 检查是否有指定事件的监听器
* @param eventName 事件名称
* @returns 是否有监听器
*/
hasListeners(eventName) {
const listeners = this._listeners.get(eventName);
return listeners ? listeners.length > 0 : false;
}
/**
* 获取指定事件的监听器数量
* @param eventName 事件名称
* @returns 监听器数量
*/
getListenerCount(eventName) {
const listeners = this._listeners.get(eventName);
return listeners ? listeners.length : 0;
}
/**
* 获取所有事件名称
* @returns 事件名称数组
*/
getEventNames() {
return Array.from(this._listeners.keys());
}
/**
* 执行清理操作
* @param force 是否强制清理所有监听器
* @returns 清理的监听器数量
*/
cleanup(force = false) {
return this._performCleanup(force);
}
/**
* 启动自动清理
*/
_startAutoCleanup() {
if (this._cleanupTimer) {
return;
}
this._cleanupTimer = window.setInterval(() => {
this._performCleanup();
}, this._config.cleanupInterval);
}
/**
* 停止自动清理
*/
_stopAutoCleanup() {
if (this._cleanupTimer) {
clearInterval(this._cleanupTimer);
this._cleanupTimer = null;
}
}
/**
* 执行清理操作
*/
_performCleanup(force = false) {
const now = Date.now();
let removedCount = 0;
for (const [eventName, listeners] of this._listeners) {
for (let i = listeners.length - 1; i >= 0; i--) {
const listener = listeners[i];
let shouldRemove = force;
if (!shouldRemove) {
// 检查弱引用(简化版本)
if (listener.weak && listener.owner) ;
// 检查过期时间
if (!shouldRemove && this._config.listenerExpirationTime > 0) {
const age = now - listener.createdAt;
const timeSinceLastCall = now - listener.lastCalledAt;
if (age > this._config.listenerExpirationTime &&
timeSinceLastCall > this._config.listenerExpirationTime) {
shouldRemove = true;
}
}
}
if (shouldRemove) {
listeners.splice(i, 1);
removedCount++;
this._stats.totalListeners--;
}
}
// 如果没有监听器了,删除事件
if (listeners.length === 0) {
this._listeners.delete(eventName);
}
}
this._stats.lastCleanupTime = now;
this._updateActiveListeners();
return removedCount;
}
/**
* 生成监听器ID
*/
_generateListenerId() {
return `listener_${this._nextListenerId++}_${Date.now()}`;
}
/**
* 更新活跃监听器数量
*/
_updateActiveListeners() {
this._stats.activeListeners = this._stats.totalListeners;
}
/**
* 更新平均事件处理时间
*/
_updateAverageEventTime(executionTime) {
if (this._stats.totalEvents === 1) {
this._stats.averageEventTime = executionTime;
}
else {
this._stats.averageEventTime =
(this._stats.averageEventTime * (this._stats.totalEvents - 1) + executionTime) / this._stats.totalEvents;
}
}
/**
* 获取统计信息
*/
getStats() {
return { ...this._stats };
}
/**
* 重置统计信息
*/
resetStats() {
this._stats = {
totalListeners: this._stats.totalListeners, // 保留当前监听器数量
activeListeners: this._stats.activeListeners,
totalEvents: 0,
averageEventTime: 0,
lastCleanupTime: Date.now()
};
}
/**
* 获取配置信息
*/
getConfig() {
return { ...this._config };
}
/**
* 销毁事件管理器
*/
destroy() {
this._stopAutoCleanup();
this._listeners.clear();
this._stats.totalListeners = 0;
this._stats.activeListeners = 0;
}
}
/**
* 高性能运行时类型检查工具
*
* @description
* 提供全面的运行时类型检查和类型守卫功能,替代不安全的类型断言。
* 支持基础类型、复合类型、自定义验证器等。
*
* @example
* ```typescript
* // 基础类型检查
* if (TypeGuards.isString(value)) {
* // value 现在是 string 类型
* console.log(value.toUpperCase());
* }
*
* // 复合类型检查
* const result = TypeGuards.checkObject(data, {
* name: TypeGuards.validators.string,
* age: TypeGuards.validators.number,
* email: TypeGuards.validators.optional(TypeGuards.validators.string)
* });
*
* // 数组类型检查
* if (TypeGuards.isArrayOf(value, TypeGuards.isNumber)) {
* // value 现在是 number[] 类型
* const sum = value.reduce((a, b) => a + b, 0);
* }
*
* // 自定义验证器
* const isPositiveNumber = TypeGuards.createValidator<number>(
* (value): value is number => typeof value === 'number' && value > 0,
* 'PositiveNumber'
* );
* ```
*/
class TypeGuards {
// ===== 基础类型守卫 =====
/**
* 检查是否为字符串
*/
static isString(value) {
return typeof value === 'string';
}
/**
* 检查是否为数字
*/
static isNumber(value) {
return typeof value === 'number' && !isNaN(value);
}
/**
* 检查是否为布尔值
*/
static isBoolean(value) {
return typeof value === 'boolean';
}
/**
* 检查是否为函数
*/
static isFunction(value) {
return typeof value === 'function';
}
/**
* 检查是否为对象(非null)
*/
static isObject(value) {
return typeof value === 'object' && value !== null;
}
/**
* 检查是否为数组
*/
static isArray(value) {
return Array.isArray(value);
}
/**
* 检查是否为null或undefined
*/
static isNullish(value) {
return value == null;
}
/**
* 检查是否不为null或undefined
*/
static isNotNull(value) {
return value != null;
}
// ===== 复合类型守卫 =====
/**
* 检查是否为指定类型的数组
*/
static isArrayOf(value, itemGuard) {
return Array.isArray(value) && value.every(itemGuard);
}
/**
* 检查是否为字符串数组
*/
static isStringArray(value) {
return this.isArrayOf(value, this.isString);
}
/**
* 检查是否为数字数组
*/
static isNumberArray(value) {
return this.isArrayOf(value, this.isNumber);
}
/**
* 检查是否为指定类的实例
*/
static isInstanceOf(value, constructor) {
return value instanceof constructor;
}
/**
* 检查对象是否具有指定的属性
*/
static hasProperty(value, property) {
return this.isObject(value) && property in value;
}
/**
* 检查对象是否具有指定类型的属性
*/
static hasPropertyOfType(value, property, typeGuard) {
return this.hasProperty(value, property) &&
typeGuard(value[property]);
}
// ===== 高级类型检查 =====
/**
* 创建自定义验证器
*/
static createValidator(guard, typeName, errorMessage) {
return {
validate: guard,
typeName,
errorMessage: errorMessage || `Expected ${typeName}`
};
}
/**
* 检查对象结构
*/
static checkObject(value, schema) {
if (!this.isObject(value)) {
return {
success: false,
value: value,
error: 'Value is not an object',
expectedType: 'object',
actualType: typeof value
};
}
const obj = value;
const result = {};
for (const [key, validator] of Object.entries(schema)) {
const propValue = obj[key];
if (!validator.validate(propValue)) {
return {
success: false,
value: value,
error: `Property '${key}' ${validator.errorMessage || `is not of type ${validator.typeName}`}`,
expectedType: validator.typeName,
actualType: typeof propValue
};
}
result[key] = propValue;
}
return {
success: true,
value: result
};
}
/**
* 安全类型转换
*/
static safeCast(value, validator) {
if (validator.validate(value)) {
return {
success: true,
value
};
}
return {
success: false,
value: value,
error: validator.errorMessage || `Value is not of type ${validator.typeName}`,
expectedType: validator.typeName,
actualType: typeof value
};
}
/**
* 断言类型(开发模式下抛出错误)
*/
static assertType(value, validator, message) {
if (!validator.validate(value)) {
const error = message ||
validator.errorMessage ||
`Type assertion failed: expected ${validator.typeName}, got ${typeof value}`;
throw new TypeError(error);
}
}
/**
* 尝试类型转换
*/
static tryConvert(value, converter, validator) {
try {
const converted = converter(value);
if (validator.validate(converted)) {
return {
success: true,
value: converted
};
}
return {
success: false,
value: converted,
error: `Conversion result is not of type ${validator.typeName}`,
expectedType: validator.typeName,
actualType: typeof converted
};
}
catch (error) {
return {
success: false,
value: value,
error: `Conversion failed: ${error instanceof Error ? error.message : String(error)}`,
expectedType: validator.typeName,
actualType: typeof value
};
}
}
// ===== 常用转换器 =====
/**
* 字符串转数字
*/
static stringToNumber(value) {
return this.tryConvert(value, (v) => {
if (typeof v === 'string') {
const num = Number(v);
if (isNaN(num)) {
throw new Error('Invalid number format');
}
return num;
}
throw new Error('Value is not a string');
}, this.validators.number);
}
/**
* 任意值转字符串
*/
static toString(value) {
return this.tryConvert(value, (v) => String(v), this.validators.string);
}
/**
* 任意值转布尔值
*/
static toBoolean(value) {
return this.tryConvert(value, (v) => Boolean(v), this.validators.boolean);
}
// ===== 范围检查 =====
/**
* 检查数字是否在指定范围内
*/
static isInRange(value, min, max, inclusive = true) {
if (!this.isNumber(value)) {
return false;
}
return inclusive ?
(value >= min && value <= max) :
(value > min && value < max);
}
/**
* 检查字符串长度是否在指定范围内
*/
static isStringLengthInRange(value, minLength, maxLength) {
return this.isString(value) &&
value.length >= minLength &&
value.length <= maxLength;
}
/**
* 检查数组长度是否在指定范围内
*/
static isArrayLengthInRange(value, minLength, maxLength) {
return this.isArray(value) &&
value.length >= minLength &&
value.length <= maxLength;
}
// ===== 模式匹配 =====
/**
* 检查字符串是否匹配正则表达式
*/
static matchesPattern(value, pattern) {
return this.isString(value) && pattern.test(value);
}
/**
* 检查是否为有效的电子邮件地址
*/
static isEmail(value) {
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return this.matchesPattern(value, emailPattern);
}
/**
* 检查是否为有效的URL
*/
static isUrl(value) {
if (!this.isString(value)) {
return false;
}
try {
new URL(value);
return true;
}
catch {
return false;
}
}
/**
* 检查是否为有效的UUID
*/
static isUuid(value) {
const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
return this.matchesPattern(value, uuidPattern);
}
}
/** 内置验证器 */
TypeGuards.validators = {
/** 字符串验证器 */
string: TypeGuards.createValidator((value) => typeof value === 'string', 'string'),
/** 数字验证器 */
number: TypeGuards.createValidator((value) => typeof value === 'number' && !isNaN(value), 'number'),
/** 布尔值验证器 */
boolean: TypeGuards.createValidator((value) => typeof value === 'boolean', 'boolean'),
/** 函数验证器 */
function: TypeGuards.createValidator((value) => typeof value === 'function', 'function'),
/** 对象验证器 */
object: TypeGuards.createValidator((value) => typeof value === 'object' && value !== null, 'object'),
/** 数组验证器 */
array: TypeGuards.createValidator((value) => Array.isArray(value), 'array'),
/** 非空验证器 */
notNull: TypeGuards.createValidator((value) => value != null, 'not null'),
/** 整数验证器 */
integer: TypeGuards.createValidator((value) => typeof value === 'number' && Number.isInteger(value), 'integer'),
/** 正数验证器 */
positiveNumber: TypeGuards.createValidator((value) => typeof value === 'number' && value > 0, 'positive number'),
/** 非负数验证器 */
nonNegativeNumber: TypeGuards.createValidator((value) => typeof value === 'number' && value >= 0, 'non-negative number'),
/** 非空字符串验证器 */
nonEmptyString: TypeGuards.createValidator((value) => typeof value === 'string' && value.trim().length > 0, 'non-empty string'),
/** 可选验证器工厂 */
optional: (validator) => ({
validate: (value) => value === undefined || validator.validate(value),
typeName: `${validator.typeName} | undefined`,
errorMessage: `Expected ${validator.typeName} or undefined`
}),
/** 可空验证器工厂 */
nullable: (validator) => ({
validate: (value) => value === null || validator.validate(value),
typeName: `${validator.typeName} | null`,
errorMessage: `Expected ${validator.typeName} or null`
}),
/** 联合类型验证器工厂 */
union: (...validators) => ({
validate: (value) => validators.some(v => v.validate(value)),
typeName: validators.map(v => v.typeName).join(' | '),
errorMessage: `Expected one of: ${validators.map(v => v.typeName).join(', ')}`
})
};
/**
* 行为树节点的执行状态枚举
*
* @description 定义了行为树中每个节点可能的执行状态
*/
exports.TaskStatus = void 0;
(function (TaskStatus) {
/**
* 无效状态 - 节点尚未执行或已被重置
*/
TaskStatus[TaskStatus["Invalid"] = 0] = "Invalid";
/**
* 成功状态 - 节点执行完成且成功
*/
TaskStatus[TaskStatus["Success"] = 1] = "Success";
/**
* 失败状态 - 节点执行完成但失败
*/
TaskStatus[TaskStatus["Failure"] = 2] = "Failure";
/**
* 运行中状态 - 节点正在执行,需要在下一帧继续
*/
TaskStatus[TaskStatus["Running"] = 3] = "Running";
})(exports.TaskStatus || (exports.TaskStatus = {}));
/**
* 行为树节点的抽象基类
*
* @description 所有行为树节点的基类,定义了节点的生命周期和基本行为
* @template T 上下文对象类型,通常包含游戏状态、AI数据等
*
* @example
* ```typescript
* class CustomAction<GameContext> extends Behavior<GameContext> {
* update(context: GameContext): TaskStatus {
* // 执行自定义逻辑
* return TaskStatus.Success;
* }
* }
* ```
*/
class Behavior {
constructor() {
/**
* 当前节点的执行状态
* @default TaskStatus.Invalid
*/
this.status = exports.TaskStatus.Invalid;
}
/**
* 重置节点状态为无效
*
* @description 使该节点的状态无效,复合节点可以重写此方法来同时重置子节点
*/
invalidate() {
this.status = exports.TaskStatus.Invalid;
}
/**
* 节点开始执行时的回调
*
* @description 在节点首次执行或状态从Invalid变为其他状态时调用
* 用于初始化变量、重置状态等准备工作
*/
onStart() { }
/**
* 节点执行结束时的回调
*
* @description 当节点状态变为Success或Failure时调用
* 用于清理资源、记录结果等收尾工作
*/
onEnd() { }
/**
* 节点执行的主要入口点
*
* @description 处理节点的完整执行流程,包括生命周期管理
* 1. 如果状态为Invalid,调用onStart()
* 2. 调用update()执行核心逻辑
* 3. 如果状态不为Running,调用onEnd()
*
* @param context 执行上下文
* @returns 执行后的状态
*/
tick(context) {
if (this.status == exports.TaskStatus.Invalid)
this.onStart();
this.status = this.update(context);
if (this.status != exports.TaskStatus.Running)
this.onEnd();
return this.status;
}
}
/**
* 黑板变量类型枚举
*/
exports.BlackboardValueType = void 0;
(function (BlackboardValueType) {
BlackboardValueType["String"] = "string";
BlackboardValueType["Number"] = "number";
BlackboardValueType["Boolean"] = "boolean";
BlackboardValueType["Vector2"] = "vector2";
BlackboardValueType["Vector3"] = "vector3";
BlackboardValueType["Object"] = "object";
BlackboardValueType["Array"] = "array";
})(exports.BlackboardValueType || (exports.BlackboardValueType = {}));
/**
* 行为树黑板系统
*
* @description
* 提供类型安全的变量存储和访问机制,支持:
* - 类型化变量定义和访问
* - 变量监听和回调
* - 序列化和反序列化
* - 实时调试和编辑
*
* @example
* ```typescript
* // 创建黑板实例
* const blackboard = new Blackboard();
*
* // 定义变量
* blackboard.defineVariable('playerHealth', BlackboardValueType.Number, 100, {
* description: '玩家生命值',
* min: 0,
* max: 100
* });
*
* // 设置和获取值
* blackboard.setValue('playerHealth', 80);
* const health = blackboard.getValue<number>('playerHealth');
*
* // 监听变量变化
* blackboard.addListener('playerHealth', (newVal, oldVal) => {
* console.log(`玩家生命值从 ${oldVal} 变为 ${newVal}`);
* });
* ```
*/
class Blackboard {
constructor() {
/** 变量定义存储 */
this._variables = new Map();
/** 变量监听器存储 */
this._listeners = new Map();
/** 监听器计数器 */
this._listenerIdCounter = 0;
/** 变量修改历史 */
this._history = [];
/** 是否启用历史记录 */
this.enableHistory = false;
}
/**
* 定义一个黑板变量
*
* @param name 变量名
* @param type 变量类型
* @param defaultValue 默认值
* @param options 额外选项
*/
defineVariable(name, type, defaultValue, options = {}) {
if (!name || typeof name !== 'string') {
throw new Error('变量名必须是非空字符串');
}
if (this._variables.has(name)) {
console.warn(`黑板变量 "${name}" 已存在,将被重新定义`);
}
// 验证默认值类型
if (!this._validateValueType(defaultValue, type)) {
throw new Error(`默认值类型与变量类型 "${type}" 不匹配`);
}
const variable = {
name,
type,
value: this._cloneValue(defaultValue),
defaultValue: this._cloneValue(defaultValue),
description: options.description || '',
readonly: options.readonly || false,
group: options.group || 'Default',
min: options.min,
max: options.max,
options: options.options ? [...options.options] : undefined
};
this._variables.set(name, variable);
}
/**
* 设置变量值
*
* @param name 变量名
* @param value 新值
* @param force 是否强制设置(忽略只读限制)
*/
setValue(name, value, force = false) {
const variable = this._variables.get(name);
if (!variable) {
console.warn(`尝试设置不存在的黑板变量 "${name}"`);
return false;
}
if (variable.readonly && !force) {
console.warn(`尝试修改只读黑板变量 "${name}"`);
return false;
}
// 类型验证
if (!this._validateValueType(value, variable.type)) {
console.error(`设置的值类型与变量 "${name}" 的类型 "${variable.type}" 不匹配`);
return false;
}
// 数值范围验证
if (variable.type === exports.BlackboardValueType.Number && typeof value === 'number') {
if (variable.min !== undefined && value < variable.min) {
console.warn(`变量 "${name}" 的值 ${value} 小于最小值 ${variable.min}`);
return false;
}
if (variable.max !== undefined && value > variable.max) {
console.warn(`变量 "${name}" 的值 ${value} 大于最大值 ${variable.max}`);
return false;
}
}
// 可选值验证
if (variable.options && !variable.options.includes(value)) {
console.warn(`变量 "${name}" 的值不在允许的选项中`);
return false;
}
const oldValue = this._cloneValue(variable.value);
const newValue = this._cloneValue(value);
// 更新值
variable.value = newValue;
// 记录历史
if (this.enableHistory) {
this._history.push({
variableName: name,
oldValue,
newValue,
timestamp: Date.now()
});
}
// 触发监听器
this._notifyListeners(name, newValue, oldValue);
return true;
}
/**
* 获取变量值
*
* @param name 变量名
* @param defaultValue 变量不存在时的默认返回值
* @returns 变量值
*/
getValue(name, defaultValue) {
const variable = this._variables.get(name);
if (!variable) {
if (defaultValue !== undefined) {
return defaultValue;
}
console.warn(`尝试获取不存在的黑板变量 "${name}"`);
return undefined;
}
return this._cloneValue(variable.value);
}
/**
* 检查变量是否存在
*/
hasVariable(name) {
return this._variables.has(name);
}
/**
* 获取变量定义
*/
getVariableDefinition(name) {
const variable = this._variables.get(name);
return variable ? { ...variable } : undefined;
}
/**
* 获取所有变量名称
*/
getVariableNames() {
return Array.from(this._variables.keys());
}
/**
* 按分组获取变量
*/
getVariablesByGroup(group) {
return Array.from(this._variables.values())
.filter(v => v.group === group)
.map(v => ({ ...v }));
}
/**
* 获取所有分组
*/
getGroups() {
const groups = new Set();
this._variables.forEach(variable => {
groups.add(variable.group || 'Default');
});
return Array.from(groups).sort();
}
/**
* 重置变量到默认值
*/
resetVariable(name) {
const variable = this._variables.get(name);
if (!variable) {
return false;
}
return this.setValue(name, variable.defaultValue, true);
}
/**
* 重置所有变量到默认值
*/
resetAll() {
this._variables.forEach((variable, name) => {
this.setValue(name, variable.defaultValue, true);
});
}
/**
* 删除变量
*/
removeVariable(name) {
if (!this._variables.has(name)) {
return false;
}
this._variables.delete(name);
this._listeners.delete(name);
return true;
}
/**
* 添加变量监听器
*/
addListener(variableName, callback) {
const id = `listener_${this._listenerIdCounter++}`;
const listener = {
variableName,
callback,
id
};
if (!this._listeners.has(variableName)) {
this._listeners.set(variableName, []);
}
this._listeners.get(variableName).push(listener);
return id;
}
/**
* 移除监听器
*/
removeListener(listenerId) {
for (const [variableName, listeners] of this._listeners.entries()) {
const index = listeners.findIndex(l => l.id === listenerId);
if (index !== -1) {
listeners.splice(index, 1);
if (listeners.length === 0) {
this._listeners.delete(variableName);
}
return true;
}
}
return false;
}
/**
* 序列化黑板数据
*/
serialize() {
const data = {
variables: Array.from(this._variables.entries()).map(([name, variable]) => ({
name,
type: variable.type,
value: variable.value,
defaultValue: variable.defaultValue,
description: variable.description,
readonly: variable.readonly,
group: variable.group,
min: variable.min,
max: variable.max,
options: variable.options
}))
};
return JSON.stringify(data, null, 2);
}
/**
* 从序列化数据恢复黑板
*/
deserialize(data) {
try {
const parsed = JSON.parse(data);
if (!parsed.variables || !Array.isArray(parsed.variables)) {
throw new Error('无效的黑板数据格式');
}
// 清空现有数据
this._variables.clear();
this._listeners.clear();
// 恢复变量定义
for (const varData of parsed.variables) {
this.defineVariable(varData.name, varData.type, varData.defaultValue, {
description: varData.description,
readonly: varData.readonly,
group: varData.group,
min: varData.min,
max: varData.max,
options: varData.options
});
// 设置当前值
this.setValue(varData.name, varData.value, true);
}
return true;
}
catch (error) {
console.error('反序列化黑板数据失败:', error);
return false;
}
}
/**
* 获取修改历史
*/
getHistory() {
return [...this._history];
}
/**
* 清空历史记录
*/
clearHistory() {
this._history.length = 0;
}
/**
* 验证值类型
*/
_validateValueType(value, type) {
switch (type) {
case exports.BlackboardValueType.String:
return typeof value === 'string';
case exports.BlackboardValueType.Number:
return typeof value === 'number' && !isNaN(value);
case exports.BlackboardValueType.Boolean:
return typeof value === 'boolean';
case exports.BlackboardValueType.Vector2:
return this._isVector2(value);
case exports.BlackboardValueType.Vector3:
return this._isVector3(value);
case exports.BlackboardValueType.Object:
return typeof value === 'object' && value !== null && !Array.isArray(value);
case exports.BlackboardValueType.Array:
return Array.isArray(value);
default:
return true;
}
}
/**
* 检查是否为Vector2
*/
_isVector2(value) {
return typeof value === 'object' &&
value !== null &&
typeof value.x === 'number' &&
typeof value.y === 'number';
}
/**
* 检查是否为Vector3
*/
_isVector3(value) {
return typeof value === 'object' &&
value !== null &&
typeof value.x === 'number' &&
typeof value.y === 'number' &&
typeof value.z === 'number';
}
/**
* 深拷贝值
*/
_cloneValue(value) {
if (value === null || typeof value !== 'object') {
return value;
}
if (Array.isArray(value)) {
return value.map(item => this._cloneValue(item));
}
const cloned = {};
for (const key in value) {
if (value.hasOwnProperty(key)) {
cloned[key] = this._cloneValue(value[key]);
}
}
return cloned;
}
/**
* 通知监听器
*/
_notifyListeners(variableName, newValue, oldValue) {
const listeners = this._listeners.get(variableName);
if (listeners) {
listeners.forEach(listener => {
try {
listener.callback(newValue, oldValue);
}
catch (error) {
console.error(`黑板监听器回调执行失败:`, error);
}
});
}
}
}
/**
* 行为树控制器
*
* @description 管理行为树的执行,支持定时更新和上下文管理
* @template T 上下文对象类型
*
* @example
* ```typescript
* // 创建游戏AI的行为树
* interface GameContext {
* player: Player;
* enemies: Enemy[];
* gameTime: number;
* }
*
* const context: GameContext = { ... };
* const rootNode = new Selector(...);
* const behaviorTree = new BehaviorTree(context, rootNode, 0.1); // 每100ms更新一次
*
* // 在游戏循环中调用
* behaviorTree.tick();
* ```
*/
class BehaviorTree {
/**
* 创建行为树实例
*
* @param context 执行上下文对象
* @param rootNode 根节点
* @param updatePeriod 更新周期,0表示每帧更新
* @param performanceMode 是否启用性能优化模式,默认false
* @param blackboard 可选的黑板实例,如果不提供将自动创建
* @throws {Error} 当context或rootNode为null时抛出错误
*/
constructor(context, rootNode, updatePeriod = 0.2, performanceMode = false, blackboard) {
/** 上次更新的时间戳(秒) */
this._lastTime = 0;
/** 是否启用性能优化模式 */
this._performanceMode = false;
/** 性能统计信息 */
this._stats = {
totalTicks: 0,
totalExecutionTime: 0,
averageExecutionTime: 0,
lastExecutionTime: 0
};
if (context == null) {
throw new Error('上下文不能为null或undefined');
}
if (rootNode == null) {
throw new Error('根节点不能为null或undefined');
}
if (updatePeriod < 0) {
throw new Error('更新周期不能为负数');
}
this._context = context;
this._root = rootNode;
this.updatePeriod = this._elapsedTime = updatePeriod;
this._performanceMode = performanceMode;
this._lastTime = this._getCurrentTime();
this._blackboard = blackboard || new Blackboard();
// 将黑板注入到上下文中
this._context.blackboard = this._blackboard;
}
/**
* 获取当前时间(秒)
* 优先使用全局时间管理器,回退到本地时间计算
*/
_getCurrentTime() {
// 优先使用全局时间管理器
try {
return TimeManager.getCurrentTime();
}
catch {
// 回退到本地时间计算
if (this._performanceMode) {
return Date.now() / 1000;
}
else {
return performance.now() / 1000;
}
}
}
/**
* 更新行为树
*
* @description
* 根据updatePeriod设置决定是否执行根节点:
* - updatePeriod > 0:按时间间隔更新
* - updatePeriod <= 0:每次调用都更新
*
* 通常在游戏主循环中每帧调用此方法
*
* @param deltaTime 可选的时间差值(秒),如果提供则使用此值而不是计算
*/
tick(deltaTime) {
const startTime = this._performanceMode ? 0 : this._getCurrentTime();
try {
if (this.updatePeriod > 0) {
let actualDeltaTime;
if (deltaTime !== undefined) {
// 使用提供的deltaTime,避免时间计算开销
actualDeltaTime = deltaTime;
}
else {
// 优先使用全局时间管理器的deltaTime
try {
actualDeltaTime = TimeManager.getDeltaTime();
if (actualDeltaTime <= 0) {
// 如果全局时间管理器未初始化,回退到本地计算
const currentTime = this._getCurrentTime();
actualDeltaTime = currentTime - this._lastTime;
this._lastTime = currentTime;
}
}
catch {
// 回退到本地时间计算
const currentTime = this._getCurrentTime();
actualDeltaTime = currentTime - this._lastTime;
this._lastTime = currentTime;
}
}
// 验证deltaTime的有效性
if (actualDeltaTime < 0 || !isFinite(actualDeltaTime)) {
ErrorHandler.warn('BehaviorTree: 无效的deltaTime值,跳过此次更新', { deltaTime: actualDeltaTime });
return;
}
// 防止异常大的时间跳跃
actualDeltaTime = Math.min(actualDeltaTime, 1.0);
this._elapsedTime -= actualDeltaTime;
if (this._elapsedTime <= 0) {
// 处理可能的时间累积,确保稳定的更新频率
while (this._elapsedTime <= 0) {
this._elapsedTime += this.updatePeriod;
}
this._executeRoot();
}
}
else {
// 每帧更新模式
this._executeRoot();
}
}
catch (error) {
ErrorHandler.warn('行为树更新时发生错误', { error, context: this._context });
}
finally {
// 更新性能统计
if (!this._performanceMode && startTime > 0) {
const executionTime = this._getCurrentTime() - startTime;
this._updateStats(executionTime);
}
}
}
/**
* 执行根节点
*/
_executeRoot() {
this._root.tick(this._context);
this._stats.totalTicks++;
}
/**
* 更新性能统计信息
* @param executionTime 执行时间
*/
_updateStats(executionTime) {
this._stats.lastExecutionTime = executionTime;
this._stats.totalExecutionTime += executionTime;
this._stats.averageExecutionTime = this._stats.totalExecutionTime / this._stats.totalTicks;
}
/**
* 获取当前上下文
* @returns 执行上下文对象
*/
getContext() {
return this._context;
}
/**
* 获取黑板实例
* @returns 黑板实例
*/
getBlackboard() {
return this._blackboard;
}
/**
* 更新上下文
* @param context 新的上下文对象
* @throws {Error} 当context为null时抛出错误
*/
setContext(context) {
if (context == null) {
throw new Error('上下文不能为null或undefined');
}
this._context = context;
// 确保新上下文中也包含黑板引用
this._context.blackboard = this._blackboard;
}
/**
* 获取根节点
* @returns 根节点实例
*/
getRoot() {
return this._root;
}
/**
* 设置新的根节点
* @param rootNode 新的根节点
* @throws {Error} 当rootNode为null时抛出错误
*/
setRoot(rootNode) {
if (rootNode == null) {
throw new Error('根节点不能为null或undefined');
}
this._root = rootNode;
}
/**
* 强制重置整个行为树
* @description 将根节点及其所有子节点重置为Invalid状态
*/
reset() {
try {
this._root.invalidate();
this._elapsedTime = this.updatePeriod;
this._lastTime = this._getCurrentTime();
}
catch (error) {
console.error('重置行为树时发生错误:', error);
}
}
/**
* 设置性能模式
* @param enabled 是否启用性能模式
*/
setPerformanceMode(enabled) {
this._performanceMode = enabled;
if (enabled) {
console.log('行为树性能模式已启用:使用较低精度的时间计算以提高性能');
}
}
/**
* 获取性能统计信息
* @returns 性能统计对象
*/
getStats() {
return { ...this._stats };
}
/**
* 重置性能统计信息
*/
resetStats() {
this._stats = {
totalTicks: 0,
totalExecutionTime: 0,
averageExecutionTime: 0,
lastExecutionTime: 0
};
}
/**
* 检查行为树是否处于活动状态
* @returns 是否有待处理的更新
*/
isActive() {
return this.updatePeriod <= 0 || this._elapsedTime <= 0;
}
/**
* 获取到下次更新的剩余时间
* @returns 剩余时间(秒),如果是每帧更新模式则返回0
*/
getTimeToNextUpdate() {
return this.updatePeriod > 0 ? Math.max(this._elapsedTime, 0) : 0;
}
}
var AbortTypes;
(function (AbortTypes) {
/**
* 没有中止类型。即使其他条件更改了状态,当前操作也将始终运行
*/
AbortTypes[AbortTypes["None"] = 0] = "None";
/**
* 如果一个更重要的有条件的任务改变了状态,它可以发出一个中止指令,使低优先级的任务停止运行,并将控制权转回高优先级的分支。
* 这种类型应该被设置在作为讨论中的复合体的子体的复合体上。
* 父复合体将检查它的子体,看它们是否有LowerPriority中止。
*/
AbortTypes[AbortTypes["LowerPriority"] = 1] = "LowerPriority";
/**
* 只有当它们都是复合体的子任务时,条件任务才能中止一个行动任务。
* 这个AbortType只影响它所设置的实际的Composite,不像LowerPriority会影响其父Composite。
*/
AbortTypes[AbortTypes["Self"] = 2] = "Self";
/**
* 检查LowerPriority和Self aborts
*/
AbortTypes[AbortTypes["Both"] = 3] = "Both";
})(AbortTypes || (AbortTypes = {}));
class AbortTypesExt {
static has(self, check) {
return (self & check) == check;
}
}
function isIConditional(obj) {
return obj && obj.discriminator === 'IConditional';
}
/**
* 检查节点是否为条件装饰器
* @param node 要检查的节点
* @returns 如果是条件装饰器则返回true
*/
function isConditionalDecorator(node) {
return isIConditional(node) &&
'abortType' in node &&
'executeConditional' in node &&
typeof node.executeConditional === 'function';
}
/**
* 复合节点基类
*
* 所有复合节点(如Sequence、Selector等)都必须继承此类。
* 提供子节点管理和中止类型处理的基础功能。
*
* @template T 上下文类型
* @abstract
*/
class Composite extends Behavior {
constructor() {
super(...arguments);
/** 中止类型,决定节点在何种情况下会被中止*/
this.abortType = AbortTypes.None;
/** 子节点数组*/
this._children = new Array();
/** 是否存在低优先级条件中止 */
this._hasLowerPriorityConditionalAbort = false;
/** 当前执行的子节点索引 */
this._currentChildIndex = 0;
}
/**
* 使节点及其所有子节点无效
*
* 重写父类方法,递归使所有子节点无效
*/
invalidate() {
super.invalidate();
const childrenLength = this._children.length;
for (let i = 0; i < childrenLength; i++) {
this._children[i].invalidate();
}
}
/**
* 节点开始执行时的初始化
*
* 检查是否存在低优先级条件中止,并重置当前子节点索引
*/
onStart() {
// 检查子节点中是否存在低优先级条件中止
this._hasLowerPriorityConditionalAbort = this.hasLowerPriorityConditionalAbortInChildren();
this._currentChildIndex = 0;
}
/**
* 节点执行结束时的清理
*
* 使所有子节点无效,为下一次执行做准备
*/
onEnd() {
// 使所有子节点无效,为下一帧做准备
const childrenLength = this._children.length;
for (let i = 0; i < childrenLength; i++) {
this._children[i].invalidate();
}
}
/**
* 检查子节点中是否存在低优先级条件中止
*
* 遍历所有子节点,查找设置了LowerPriority中止类型的节点
*
* @returns 如果存在低优先级条件中止则返回true,否则返回false
* @private
*/
hasLowerPriorityConditionalAbortInChildren() {
for (let i = 0; i < this._children.length; i++) {
const child = this._children[i];
// 检查条件装饰器的中止类型
if (isConditionalDecorator(child) && AbortTypesExt.has(child.abortType, AbortTypes.LowerPriority)) {
return true;
}
// 检查复合节点的中止类型
const composite = child;
if (composite != null && AbortTypesExt.has(composite.abortType, AbortTypes.LowerPriority)) {
// 确保第一个子节点是条件节点
if (composite.isFirstChildConditional())
return true;
}
}
return false;
}
/**
* 添加子节点
*
* @param child 要添加的子节点
*/
addChild(child) {
this._children.push(child);
}
/**
* 检查第一个子节点是否为条件节点
*
* 用于处理条件性中止逻辑
*
* @returns 如果第一个子节点是条件节点则返回true,否则返回false
*/
isFirstChildConditional() {
return isIConditional(this._children[0]);
}
/**
* 更新自中止条件节点
*
* 检查当前索引之前的条件节点状态变化,支持自中止功能。
* 当条件节点状态不符合预期时,会重置当前索引并使后续子节点无效。
*
* @param context 执行上下文
* @param statusCheck 期望的状态值
* @protected
*/
updateSelfAbortConditional(context, statusCheck) {
// 检查当前索引之前的条件节点
for (let i = 0; i < this._currentChildIndex; i++) {
const child = this._children[i];
if (!isIConditional(child)) {
continue;
}
const status = this.updateConditionalNode(context, child);
if (status !== statusCheck) {
this._currentChildIndex = i;
// 中止时使后续子节点无效
const childrenLength = this._children.length;
for (let j = i; j < childrenLength; j++) {
this._children[j].invalidate();
}
break;
}
}
}
/**
* 更新低优先级中止条件节点
*
* 检查具有低优先级中止类型的组合节点,当其条件节点状态发生变化时
* 执行中止操作。
*
* @param context 执行上下文
* @param statusCheck 期望的状态值
* @protected
*/
updateLowerPriorityAbortConditional(context, statusCheck) {
// 检查当前索引之前的低优先级任务
for (let i = 0; i < this._currentChildIndex; i++) {
const child = this._children[i];
// 检查是否为条件装饰器或设置了LowerPriority中止类型的复合节点
if (isConditionalDecorator(child) && AbortTypesExt.has(child.abortType, AbortTypes.LowerPriority)) {
// 对于条件装饰器,检查条件本身而不是装饰器的整体状态
const conditionStatus = child.executeConditional(context, true); // 强制更新条件
// 对于选择器:当高优先级条件变为Success时,应该中止低优先级任务
// 对于序列器:当高优先级条件变为Failure时,应该中止低优先级任务
const shouldAbort = (statusCheck === exports.TaskStatus.Failure) ? (conditionStatus === exports.TaskStatus.Success) : (conditionStatus === exports.TaskStatus.Failure);
if (shouldAbort) {
// 条件满足,需要中止当前执行,回到这个节点
this._currentChildIndex = i;
// 中止时使后续子节点无效
const childrenLength = this._children.length;
for (let j = i + 1; j < childrenLength; j++) {
this._children[j].invalidate();
}
break;
}
}
else {
// 检查是否为设置了LowerPriority的复合节点
const composite = child;
if (composite && AbortTypesExt.has(composite.abortType, AbortTypes.LowerPriority)) {
// 获取复合节点的第一个子节点作为条件
const firstChild = composite._children[0];
if (firstChild && isIConditional(firstChild)) {
const status = this.updateConditionalNode(context, firstChild);
// 对于选择器:当高优先级条件变为Success时,应该中止低优先级任务
// 对于序列器:当高优先级条件变为Failure时,应该中止低优先级任务
const shouldAbort = (statusCheck === exports.TaskStatus.Failure) ? (status === exports.TaskStatus.Success) : (status === exports.TaskStatus.Failure);
if (shouldAbort) {
this._currentChildIndex = i;
// 中止时使后续子节点无效
const childrenLength = this._children.length;
for (let j = i + 1; j < childrenLength; j++) {
this._children[j].invalidate();
}
break;
}
}
}
}
}
}
/**
* 更新条件节点状态
*
* 辅助方法,用于获取条件节点或条件装饰器的任务状态
*
* @param context 执行上下文
* @param node 要更新的节点
* @returns 节点的执行状态
* @private
*/
updateConditionalNode(context, node) {
// 直接调用节点的update方法获取状态
return node.update(context);
}
}
class Decorator extends Behavior {
invalidate() {
super.invalidate();
this.child?.invalidate();
}
}
/**
* 执行函数动作包装器
*
* @description
* 包装一个函数以便可以作为行为树节点使用,避免为简单逻辑创建子类。
* 适合快速原型开发和简单的行为逻辑。
*
* @template T 上下文类型
*
* @example
* ```typescript
* // 创建简单的执行动作
* const moveAction = new ExecuteAction<GameContext>((context) => {
* context.player.move();
* return TaskStatus.Success;
* });
*
* // 带条件的执行动作
* const attackAction = new ExecuteAction<GameContext>((context) => {
* if (context.enemy.isInRange()) {
* context.player.attack();
* return TaskStatus.Success;
* }
* return TaskStatus.Failure;
* });
* ```
*/
class ExecuteAction extends Behavior {
/**
* 创建执行动作
* @param action 要执行的函数,不能为null
* @param options 配置选项
* @throws {Error} 当action为null或undefined时抛出错误
*/
constructor(action, options = {}) {
super();
if (action == null) {
throw new Error('动作函数不能为null或undefined');
}
if (typeof action !== 'function') {
throw new Error('动作必须是一个函数');
}
this._action = action;
this._enableErrorHandling = options.enableErrorHandling ?? true;
this._name = options.name;
}
/**
* 执行包装的函数
* @param context 执行上下文
* @returns 执行结果状态
*/
update(context) {
if (this._enableErrorHandling) {
try {
const result = this._action(context);
// 验证返回值是否为有效的TaskStatus
if (!this.isValidTaskStatus(result)) {
console.error(`ExecuteAction ${this._name || ''}: 动作函数返回了无效的TaskStatus: ${result}`);
return exports.TaskStatus.Failure;
}
return result;
}
catch (error) {
const actionName = this._name ? `"${this._name}"` : '';
console.error(`ExecuteAction ${actionName} 执行时发生错误:`, error);
return exports.TaskStatus.Failure;
}
}
else {
// 高性能模式:跳过错误处理
return this._action(context);
}
}
/**
* 验证TaskStatus是否有效
* @param status 要验证的状态
* @returns 是否为有效状态
*/
isValidTaskStatus(status) {
return status === exports.TaskStatus.Success ||
status === exports.TaskStatus.Failure ||
status === exports.TaskStatus.Running;
}
/**
* 获取动作名称
* @returns 动作名称或函数名
*/
getName() {
return this._name || this._action.name || 'Anonymous Action';
}
/**
* 创建一个始终成功的执行动作
* @param action 要执行的无返回值函数
* @param name 动作名称
* @returns 新的ExecuteAction实例
*/
static createAlwaysSuccess(action, name) {
return new ExecuteAction((context) => {
action(context);
return exports.TaskStatus.Success;
}, { name: name || 'Always Success Action' });
}
/**
* 创建一个条件执行动作
* @param predicate 条件函数
* @param name 动作名称
* @returns 新的ExecuteAction实例
*/
static createConditional(predicate, name) {
return new ExecuteAction((context) => {
return predicate(context) ? exports.TaskStatus.Success : exports.TaskStatus.Failure;
}, { name: name || 'Conditional Action' });
}
}
/**
* 执行动作条件包装器
*
* @description
* 包装一个ExecuteAction,使其可以作为条件节点使用。
* 适用于需要将简单的函数逻辑用作条件判断的场景。
*
* @template T 上下文类型
*
* @example
* ```typescript
* // 创建一个检查玩家血量的条件
* const healthCheck = new ExecuteActionConditional<GameContext>((context) => {
* return context.player.health > 50 ? TaskStatus.Success : TaskStatus.Failure;
* }, { name: 'HealthCheck' });
*
* // 创建一个检查敌人距离的条件
* const enemyInRange = ExecuteActionConditional.createPredicate<GameContext>(
* (context) => context.getClosestEnemy()?.distance < 10,
* 'EnemyInRange'
* );
* ```
*/
class ExecuteActionConditional extends ExecuteAction {
/**
* 创建执行动作条件
* @param action 条件判断函数,应返回Success或Failure
* @param options 配置选项
*/
constructor(action, options = {}) {
super(action, options);
/** 条件节点标识符 */
this.discriminator = "IConditional";
}
/**
* 创建基于布尔值的条件
* @param predicate 返回布尔值的判断函数
* @param name 条件名称
* @returns 新的ExecuteActionConditional实例
*/
static createPredicate(predicate, name) {
return new ExecuteActionConditional((context) => {
return predicate(context) ? exports.TaskStatus.Success : exports.TaskStatus.Failure;
}, { name: name || 'Predicate Condition' });
}
/**
* 创建数值比较条件
* @param getValue 获取数值的函数
* @param threshold 阈值
* @param comparison 比较类型
* @param name 条件名称
* @returns 新的ExecuteActionConditional实例
*/
static createNumericComparison(getValue, threshold, comparison, name) {
const compareFunctions = {
greater: (value, threshold) => value > threshold,
less: (value, threshold) => value < threshold,
equal: (value, threshold) => Math.abs(value - threshold) < Number.EPSILON,
greaterEqual: (value, threshold) => value >= threshold,
lessEqual: (value, threshold) => value <= threshold
};
const compareFunc = compareFunctions[comparison];
const conditionName = name || `Numeric ${comparison} ${threshold}`;
return new ExecuteActionConditional((context) => {
try {
const value = getValue(context);
if (typeof value !== 'number' || isNaN(value)) {
console.warn(`${conditionName}: getValue返回了无效的数值: ${value}`);
return exports.TaskStatus.Failure;
}
return compareFunc(value, threshold) ? exports.TaskStatus.Success : exports.TaskStatus.Failure;
}
catch (error) {
console.error(`${conditionName}: 获取数值时发生错误:`, error);
return exports.TaskStatus.Failure;
}
}, { name: conditionName });
}
/**
* 创建属性存在检查条件
* @param getProperty 获取属性的函数
* @param name 条件名称
* @returns 新的ExecuteActionConditional实例
*/
static createPropertyExists(getProperty, name) {
return new ExecuteActionConditional((context) => {
try {
const property = getProperty(context);
return (property != null) ? exports.TaskStatus.Success : exports.TaskStatus.Failure;
}
catch (error) {
console.error(`${name || 'Property Check'}: 检查属性时发生错误:`, error);
return exports.TaskStatus.Failure;
}
}, { name: name || 'Property Exists Check' });
}
/**
* 创建组合条件(AND逻辑)
* @param conditions 条件函数数组
* @param name 条件名称
* @returns 新的ExecuteActionConditional实例
*/
static createAnd(conditions, name) {
return new ExecuteActionConditional((context) => {
for (const condition of conditions) {
if (!condition(context)) {
return exports.TaskStatus.Failure;
}
}
return exports.TaskStatus.Success;
}, { name: name || 'AND Condition' });
}
/**
* 创建组合条件(OR逻辑)
* @param conditions 条件函数数组
* @param name 条件名称
* @returns 新的ExecuteActionConditional实例
*/
static createOr(conditions, name) {
return new ExecuteActionConditional((context) => {
for (const condition of conditions) {
if (condition(context)) {
return exports.TaskStatus.Success;
}
}
return exports.TaskStatus.Failure;
}, { name: name || 'OR Condition' });
}
}
/**
* 黑板比较操作符
*/
var CompareOperator;
(function (CompareOperator) {
CompareOperator["Equal"] = "equal";
CompareOperator["NotEqual"] = "notEqual";
CompareOperator["Greater"] = "greater";
CompareOperator["GreaterOrEqual"] = "greaterOrEqual";
CompareOperator["Less"] = "less";
CompareOperator["LessOrEqual"] = "lessOrEqual";
CompareOperator["Contains"] = "contains";
CompareOperator["NotContains"] = "notContains";
})(CompareOperator || (CompareOperator = {}));
/**
* 黑板值比较条件
*
* @description 比较黑板变量与指定值或另一个黑板变量
*
* @example
* ```typescript
* // 检查玩家生命值是否大于50
* const healthCheck = new BlackboardValueComparison<GameContext>(
* 'playerHealth',
* CompareOperator.Greater,
* 50
* );
*
* // 比较两个黑板变量
* const compareVars = new BlackboardValueComparison<GameContext>(
* 'playerHealth',
* CompareOperator.Greater,
* null,
* 'enemyHealth'
* );
* ```
*/
class BlackboardValueComparison {
constructor(variableName, operator, compareValue = null, compareVariable) {
this.discriminator = 'IConditional';
this.variableName = variableName;
this.operator = operator;
this.compareValue = compareValue;
this.compareVariable = compareVariable;
}
/**
* 检查条件是否满足
*/
update(context) {
const blackboard = context.blackboard;
if (!blackboard || !(blackboard instanceof Blackboard)) {
console.warn('BlackboardValueComparison: 上下文中未找到Blackboard实例');
return exports.TaskStatus.Failure;
}
if (!blackboard.hasVariable(this.variableName)) {
console.warn(`BlackboardValueComparison: 变量 "${this.variableName}" 不存在`);
return exports.TaskStatus.Failure;
}
const leftValue = blackboard.getValue(this.variableName);
let rightValue;
if (this.compareVariable) {
if (!blackboard.hasVariable(this.compareVariable)) {
console.warn(`BlackboardValueComparison: 比较变量 "${this.compareVariable}" 不存在`);
return exports.TaskStatus.Failure;
}
rightValue = blackboard.getValue(this.compareVariable);
}
else {
rightValue = this.compareValue;
}
const result = this._performComparison(leftValue, rightValue, this.operator);
return result ? exports.TaskStatus.Success : exports.TaskStatus.Failure;
}
/**
* 执行比较操作
*/
_performComparison(left, right, operator) {
switch (operator) {
case CompareOperator.Equal:
return left === right;
case CompareOperator.NotEqual:
return left !== right;
case CompareOperator.Greater:
return typeof left === 'number' && typeof right === 'number' && left > right;
case CompareOperator.GreaterOrEqual:
return typeof left === 'number' && typeof right === 'number' && left >= right;
case CompareOperator.Less:
return typeof left === 'number' && typeof right === 'number' && left < right;
case CompareOperator.LessOrEqual:
return typeof left === 'number' && typeof right === 'number' && left <= right;
case CompareOperator.Contains:
if (typeof left === 'string' && typeof right === 'string') {
return left.includes(right);
}
if (Array.isArray(left)) {
return left.includes(right);
}
return false;
case CompareOperator.NotContains:
if (typeof left === 'string' && typeof right === 'string') {
return !left.includes(right);
}
if (Array.isArray(left)) {
return !left.includes(right);
}
return true;
default:
return false;
}
}
}
/**
* 黑板变量存在性检查
*
* @description 检查指定的黑板变量是否存在且不为null/undefined
*/
class BlackboardVariableExists {
constructor(variableName, invert = false) {
this.discriminator = 'IConditional';
this.variableName = variableName;
this.invert = invert;
}
update(context) {
const blackboard = context.blackboard;
if (!blackboard || !(blackboard instanceof Blackboard)) {
console.warn('BlackboardVariableExists: 上下文中未找到Blackboard实例');
return this.invert ? exports.TaskStatus.Success : exports.TaskStatus.Failure;
}
const exists = blackboard.hasVariable(this.variableName);
const value = exists ? blackboard.getValue(this.variableName) : undefined;
const isValid = exists && value !== null && value !== undefined;
const result = this.invert ? !isValid : isValid;
return result ? exports.TaskStatus.Success : exports.TaskStatus.Failure;
}
}
/**
* 黑板变量类型检查
*
* @description 检查黑板变量是否为指定类型
*/
class BlackboardVariableTypeCheck {
constructor(variableName, expectedType) {
this.discriminator = 'IConditional';
this.variableName = variableName;
this.expectedType = expectedType;
}
update(context) {
const blackboard = context.blackboard;
if (!blackboard || !(blackboard instanceof Blackboard)) {
console.warn('BlackboardVariableTypeCheck: 上下文中未找到Blackboard实例');
return exports.TaskStatus.Failure;
}
const variableDefinition = blackboard.getVariableDefinition(this.variableName);
if (!variableDefinition) {
return exports.TaskStatus.Failure;
}
const result = variableDefinition.type === this.expectedType;
return result ? exports.TaskStatus.Success : exports.TaskStatus.Failure;
}
}
/**
* 黑板变量范围检查
*
* @description 检查数值型黑板变量是否在指定范围内
*/
class BlackboardVariableRangeCheck {
constructor(variableName, minValue, maxValue) {
this.discriminator = 'IConditional';
this.variableName = variableName;
this.minValue = minValue;
this.maxValue = maxValue;
}
update(context) {
const blackboard = context.blackboard;
if (!blackboard || !(blackboard instanceof Blackboard)) {
console.warn('BlackboardVariableRangeCheck: 上下文中未找到Blackboard实例');
return exports.TaskStatus.Failure;
}
if (!blackboard.hasVariable(this.variableName)) {
return exports.TaskStatus.Failure;
}
const value = blackboard.getValue(this.variableName);
if (typeof value !== 'number') {
return exports.TaskStatus.Failure;
}
const result = value >= this.minValue && value <= this.maxValue;
return result ? exports.TaskStatus.Success : exports.TaskStatus.Failure;
}
}
/**
* 条件处理器工厂类
* @description 专门负责创建各种类型的条件节点,保持代码整洁和可维护性
*/
class ConditionFactory {
/**
* 从条件配置创建条件节点
* @param condition 条件配置
* @param nodeProperties 父节点的属性(用于条件装饰器)
* @param context 执行上下文
* @returns 条件节点实例
*/
static createCondition(condition, nodeProperties = {}, context) {
if (!condition) {
return new ExecuteActionConditional(() => exports.TaskStatus.Success);
}
switch (condition.type) {
case 'blackboard-value-comparison':
return ConditionFactory.createBlackboardComparison(nodeProperties);
case 'condition-custom':
return ConditionFactory.createCustomCondition(condition.properties || nodeProperties);
case 'event-condition':
return ConditionFactory.createEventCondition(condition.properties || nodeProperties, context);
default:
console.warn(`未知的条件类型: ${condition.type},使用默认成功条件`);
return new ExecuteActionConditional(() => exports.TaskStatus.Success);
}
}
/**
* 创建黑板值比较条件
* @param properties 节点属性
* @returns 黑板比较条件实例
*/
static createBlackboardComparison(properties) {
// 提取嵌套的属性值
const variableName = ConditionFactory.extractNestedValue(properties.variableName) || 'variable';
const operator = ConditionFactory.extractNestedValue(properties.operator) || 'equal';
const compareValue = ConditionFactory.extractNestedValue(properties.compareValue);
const compareVariable = ConditionFactory.extractNestedValue(properties.compareVariable);
// 映射操作符字符串到枚举
const operatorEnum = ConditionFactory.mapOperatorToEnum(operator);
// 处理黑板变量引用(如 "{{variableName}}")
const cleanVariableName = ConditionFactory.cleanVariableName(variableName);
const cleanCompareVariable = compareVariable ? ConditionFactory.cleanVariableName(compareVariable) : undefined;
// 处理类型转换 - 特别是布尔值的字符串表示
let processedCompareValue = compareValue;
if (typeof compareValue === 'string') {
// 如果比较值是字符串,尝试转换为对应的类型
if (compareValue.toLowerCase() === 'true') {
processedCompareValue = true;
}
else if (compareValue.toLowerCase() === 'false') {
processedCompareValue = false;
}
else if (!isNaN(Number(compareValue)) && compareValue.trim() !== '') {
// 如果是数字字符串,转换为数字
processedCompareValue = Number(compareValue);
}
}
return new BlackboardValueComparison(cleanVariableName, operatorEnum, processedCompareValue, cleanCompareVariable);
}
/**
* 创建自定义条件
* @param properties 条件属性
* @returns 自定义条件实例
*/
static createCustomCondition(properties = {}) {
const conditionCodeConfig = properties.conditionCode;
const conditionCode = typeof conditionCodeConfig === 'string' ? conditionCodeConfig :
(typeof conditionCodeConfig === 'object' && conditionCodeConfig && 'value' in conditionCodeConfig ?
String(conditionCodeConfig.value) : undefined);
if (conditionCode && typeof conditionCode === 'string') {
try {
const condFunc = new Function('context', `
try {
return (${conditionCode})(context);
} catch (error) {
console.error('自定义条件函数执行错误:', error);
return false;
}
`);
return new ExecuteActionConditional((ctx) => {
try {
const result = condFunc(ctx);
return result ? exports.TaskStatus.Success : exports.TaskStatus.Failure;
}
catch (error) {
console.error('自定义条件函数执行失败:', error);
return exports.TaskStatus.Failure;
}
});
}
catch (error) {
console.warn('解析自定义条件函数失败:', error);
}
}
return new ExecuteActionConditional(() => exports.TaskStatus.Failure);
}
/**
* 创建事件条件
* @param properties 条件属性
* @param context 执行上下文
* @returns 事件条件实例
*/
static createEventCondition(properties = {}, context) {
const eventName = ConditionFactory.extractNestedValue(properties.eventName);
if (!eventName || typeof eventName !== 'string') {
console.warn('[event-condition] 缺少有效的 eventName 属性');
return new ExecuteActionConditional(() => exports.TaskStatus.Failure);
}
return new ExecuteActionConditional((ctx) => {
try {
// 从上下文中获取事件注册表
const eventRegistry = ctx.eventRegistry;
if (!eventRegistry) {
console.warn(`[event-condition] 未找到事件注册表,请在执行上下文中提供 eventRegistry`);
return exports.TaskStatus.Failure;
}
// 获取条件处理器
const checker = eventRegistry.getConditionHandler ?
eventRegistry.getConditionHandler(eventName) :
eventRegistry.handlers?.get(eventName);
if (!checker) {
console.warn(`[event-condition] 未找到条件处理器: ${eventName}`);
return exports.TaskStatus.Failure;
}
// 解析参数
let parameters = {};
const parametersValue = ConditionFactory.extractNestedValue(properties.parameters);
if (parametersValue) {
if (typeof parametersValue === 'string') {
try {
parameters = JSON.parse(parametersValue);
}
catch (e) {
console.warn(`[event-condition] 参数解析失败: ${parametersValue}`);
}
}
else {
parameters = parametersValue;
}
// 支持黑板变量替换
const blackboard = ctx.blackboard;
if (blackboard) {
parameters = ConditionFactory.replaceBlackboardVariables(parameters, blackboard);
}
}
// 执行条件检查
const result = checker(ctx, parameters);
// 处理异步结果
if (result instanceof Promise) {
console.warn(`[event-condition] 条件 ${eventName} 返回Promise,条件节点不支持异步操作`);
return exports.TaskStatus.Failure;
}
return result ? exports.TaskStatus.Success : exports.TaskStatus.Failure;
}
catch (error) {
console.error(`[event-condition] 条件 ${eventName} 检查失败:`, error);
return exports.TaskStatus.Failure;
}
});
}
/**
* 映射操作符字符串到枚举
* @param operator 操作符字符串
* @returns 操作符枚举值
*/
static mapOperatorToEnum(operator) {
switch (operator.toLowerCase()) {
case 'equal': return CompareOperator.Equal;
case 'notequal':
case 'not_equal': return CompareOperator.NotEqual;
case 'greater': return CompareOperator.Greater;
case 'greaterorequal':
case 'greater_or_equal': return CompareOperator.GreaterOrEqual;
case 'less': return CompareOperator.Less;
case 'lessorequal':
case 'less_or_equal': return CompareOperator.LessOrEqual;
case 'contains': return CompareOperator.Contains;
case 'notcontains':
case 'not_contains': return CompareOperator.NotContains;
default: return CompareOperator.Equal;
}
}
/**
* 清理变量名,移除黑板变量引用语法
* @param variableName 原始变量名
* @returns 清理后的变量名
*/
static cleanVariableName(variableName) {
if (typeof variableName !== 'string') {
return String(variableName);
}
return variableName.replace(/^\{\{|\}\}$/g, '');
}
/**
* 提取嵌套属性值
* @description 处理编辑器生成的嵌套属性结构
* @param prop 属性配置对象或直接值
* @returns 提取的值
*/
static extractNestedValue(prop) {
if (prop === null || prop === undefined) {
return prop;
}
// 如果是简单值,直接返回
if (typeof prop !== 'object') {
return prop;
}
// 如果有value属性,递归提取
if ('value' in prop) {
return ConditionFactory.extractNestedValue(prop.value);
}
return prop;
}
/**
* 替换黑板变量引用
* @param obj 要处理的对象
* @param blackboard 黑板实例
* @returns 处理后的对象
*/
static replaceBlackboardVariables(obj, blackboard) {
if (typeof obj === 'string') {
// 匹配 {{variableName}} 格式的变量引用
return obj.replace(/\{\{([^}]+)\}\}/g, (match, variableName) => {
const value = blackboard.get ? blackboard.get(variableName) : blackboard[variableName];
return value !== undefined ? value : match;
});
}
else if (Array.isArray(obj)) {
return obj.map(item => ConditionFactory.replaceBlackboardVariables(item, blackboard));
}
else if (obj && typeof obj === 'object') {
const result = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
result[key] = ConditionFactory.replaceBlackboardVariables(obj[key], blackboard);
}
}
return result;
}
return obj;
}
}
/**
* 简单的任务,它将输出指定的文本并返回成功。 它可以用于调试。
*/
class LogAction extends Behavior {
constructor(text) {
super();
/** 是否输出error还是log */
this.isError = false;
this.text = text;
}
update(_context) {
if (this.isError)
console.error(this.text);
else
console.log(this.text);
return exports.TaskStatus.Success;
}
}
/**
* 类型守卫:检查对象是否包含时间信息
* @param obj 要检查的对象
* @returns 是否为时间上下文对象
*/
function hasTimeContext(obj) {
return obj != null &&
typeof obj === 'object' &&
'deltaTime' in obj &&
typeof obj.deltaTime === 'number';
}
/**
* 等待指定时间的行为节点
*
* @description
* 在指定时间内返回Running状态,时间到达后返回Success状态。
* 支持外部时间管理以提高性能。
*
* @template T 上下文类型
*
* @example
* ```typescript
* // 基本用法
* const waitAction = new WaitAction<any>(2.0); // 等待2秒
*
* // 使用外部时间管理
* interface GameContext extends ITimeContext {
* player: Player;
* deltaTime: number;
* }
* const waitAction = new WaitAction<GameContext>(1.5, true);
* ```
*/
class WaitAction extends Behavior {
/**
* 创建等待动作
* @param waitTime 等待时间(秒),必须大于0
* @param useExternalTime 是否使用外部时间管理,默认false
* @throws {Error} 当waitTime小于等于0时抛出错误
*/
constructor(waitTime, useExternalTime = false) {
super();
/** 已等待的时间(秒) */
this._elapsedTime = 0;
/** 是否使用外部时间管理 */
this._useExternalTime = false;
/** 上次更新的时间戳(用于内部时间计算) */
this._lastUpdateTime = 0;
if (waitTime <= 0) {
throw new Error('等待时间必须大于0');
}
this.waitTime = waitTime;
this._useExternalTime = useExternalTime;
}
onStart() {
this._elapsedTime = 0;
this._lastUpdateTime = performance.now() / 1000;
}
/**
* 更新等待状态
* @param context 上下文对象,如果包含deltaTime属性则使用外部时间
* @returns 当前执行状态
*/
update(context) {
let deltaTime;
if (this._useExternalTime && hasTimeContext(context)) {
// 使用外部提供的deltaTime
deltaTime = context.deltaTime;
// 验证deltaTime的有效性
if (deltaTime < 0 || !isFinite(deltaTime)) {
console.warn('WaitAction: 无效的deltaTime值,回退到内部时间计算');
deltaTime = this._calculateInternalDeltaTime();
}
}
else {
// 使用内部时间计算
deltaTime = this._calculateInternalDeltaTime();
}
this._elapsedTime += deltaTime;
if (this._elapsedTime >= this.waitTime) {
return exports.TaskStatus.Success;
}
return exports.TaskStatus.Running;
}
/**
* 计算内部时间差
* @returns 时间差(秒)
*/
_calculateInternalDeltaTime() {
const currentTime = performance.now() / 1000;
const deltaTime = currentTime - this._lastUpdateTime;
this._lastUpdateTime = currentTime;
// 防止异常大的时间跳跃(比如页面失焦后恢复)
return Math.min(deltaTime, 0.1); // 最大100ms
}
/**
* 获取等待进度(0-1)
* @returns 当前进度百分比
*/
getProgress() {
return Math.min(this._elapsedTime / this.waitTime, 1.0);
}
/**
* 获取剩余等待时间
* @returns 剩余时间(秒)
*/
getRemainingTime() {
return Math.max(this.waitTime - this._elapsedTime, 0);
}
/**
* 设置新的等待时间
* @param newWaitTime 新的等待时间(秒)
* @param resetProgress 是否重置当前进度,默认false
* @throws {Error} 当newWaitTime小于等于0时抛出错误
*/
setWaitTime(newWaitTime, resetProgress = false) {
if (newWaitTime <= 0) {
throw new Error('等待时间必须大于0');
}
this.waitTime = newWaitTime;
if (resetProgress) {
this._elapsedTime = 0;
this._lastUpdateTime = performance.now() / 1000;
}
}
/**
* 检查是否已完成等待
* @returns 是否已完成
*/
isCompleted() {
return this._elapsedTime >= this.waitTime;
}
}
/**
* 作为子项运行整个BehaviorTree并返回成功
*/
class BehaviorTreeReference extends Behavior {
constructor(tree) {
super();
this._childTree = tree;
}
update(_context) {
this._childTree.tick();
return exports.TaskStatus.Success;
}
}
/**
* 装饰器,只有在满足条件的情况下才会运行其子程序。
* 默认情况下,该条件将在每一次执行中被重新评估
*/
class ConditionalDecorator extends Decorator {
constructor(conditional, shouldReevalute = true, abortType = AbortTypes.None) {
super();
this.discriminator = "IConditional";
/** 中止类型,决定节点在何种情况下会被中止 */
this.abortType = AbortTypes.None;
this._conditionalStatus = exports.TaskStatus.Invalid;
if (!isIConditional(conditional)) {
throw new Error("conditional 必须继承 IConditional");
}
this._conditional = conditional;
this._shouldReevaluate = shouldReevalute;
this.abortType = abortType;
}
invalidate() {
super.invalidate();
this._conditionalStatus = exports.TaskStatus.Invalid;
}
onStart() {
this._conditionalStatus = exports.TaskStatus.Invalid;
}
update(context) {
if (!this.child) {
throw new Error("child不能为空");
}
// 如果子节点正在运行且shouldReevaluate为false,直接继续执行子节点
if (!this._shouldReevaluate && this.child.status === exports.TaskStatus.Running) {
return this.child.tick(context);
}
// 否则正常评估条件
this._conditionalStatus = this.executeConditional(context);
if (this._conditionalStatus == exports.TaskStatus.Success) {
const childStatus = this.child.tick(context);
return childStatus;
}
return exports.TaskStatus.Failure;
}
/**
* 在shouldReevaluate标志之后执行条件,或者用一个选项来强制更新。
* 终止将强制更新,以确保他们在条件变化时得到适当的数据。
*/
executeConditional(context, forceUpdate = false) {
if (forceUpdate || this._shouldReevaluate || this._conditionalStatus == exports.TaskStatus.Invalid)
this._conditionalStatus = this._conditional.update(context);
return this._conditionalStatus;
}
}
/**
* 将总是返回失败,除了当子任务正在运行时
*/
class AlwaysFail extends Decorator {
update(context) {
if (!this.child) {
throw new Error("child必须不能为空");
}
let status = this.child.update(context);
if (status == exports.TaskStatus.Running)
return exports.TaskStatus.Running;
return exports.TaskStatus.Failure;
}
}
/**
* 将总是返回成功,除了当子任务正在运行时
*/
class AlwaysSucceed extends Decorator {
update(context) {
if (!this.child) {
throw new Error("child必须不能为空");
}
let status = this.child.update(context);
if (status == exports.TaskStatus.Running)
return exports.TaskStatus.Running;
return exports.TaskStatus.Success;
}
}
/**
* 反转结果的子节点
*/
class Inverter extends Decorator {
update(context) {
if (!this.child) {
throw new Error("child必须不能为空");
}
let status = this.child.tick(context);
if (status == exports.TaskStatus.Success)
return exports.TaskStatus.Failure;
if (status == exports.TaskStatus.Failure)
return exports.TaskStatus.Success;
return exports.TaskStatus.Running;
}
}
/**
* 重复执行装饰器
*
* @description
* 重复执行其子节点,直到达到指定次数或条件满足。
* 支持无限重复、失败时停止等多种模式。
*
* @template T 上下文类型
*
* @example
* ```typescript
* // 重复3次
* const repeater = new Repeater<GameContext>(3);
* repeater.child = new AttackAction();
*
* // 无限重复,失败时停止
* const infiniteRepeater = new Repeater<GameContext>(-1, true);
*
* // 重复直到成功
* const untilSuccess = Repeater.createUntilSuccess<GameContext>();
* ```
*/
class Repeater extends Decorator {
/**
* 创建重复装饰器
* @param count 重复次数,-1表示无限重复,必须是整数
* @param endOnFailure 子节点失败时是否停止,默认false
* @param endOnSuccess 子节点成功时是否停止,默认false
* @throws {Error} 当count不是有效整数时抛出错误
*/
constructor(count, endOnFailure = false, endOnSuccess = false) {
super();
/** 当前已执行的迭代次数 */
this._iterationCount = 0;
/** 最后一次子节点的执行结果 */
this._lastChildStatus = exports.TaskStatus.Invalid;
if (!Number.isInteger(count) || count < -1 || count === 0) {
throw new Error('重复次数必须是正整数或-1(无限重复)');
}
this.count = count;
this.endOnFailure = endOnFailure;
this.endOnSuccess = endOnSuccess;
}
/**
* 是否永远重复
*/
get repeatForever() {
return this.count === -1;
}
/**
* 设置是否永远重复
*/
set repeatForever(value) {
this.count = value ? -1 : Math.max(1, this.count);
}
onStart() {
this._iterationCount = 0;
this._lastChildStatus = exports.TaskStatus.Invalid;
}
update(context) {
if (!this.child) {
throw new Error('子节点不能为空');
}
// 检查是否已经达到重复次数(非无限重复的情况)
if (!this.repeatForever && this._iterationCount >= this.count) {
return exports.TaskStatus.Success;
}
// 执行子节点
const status = this.child.tick(context);
this._lastChildStatus = status;
// 如果子节点仍在运行,继续等待
if (status === exports.TaskStatus.Running) {
return exports.TaskStatus.Running;
}
// 子节点完成了一次执行
this._iterationCount++;
// 检查停止条件
if (this.endOnFailure && status === exports.TaskStatus.Failure) {
return exports.TaskStatus.Success;
}
if (this.endOnSuccess && status === exports.TaskStatus.Success) {
return exports.TaskStatus.Success;
}
// 检查是否已经达到重复次数
if (!this.repeatForever && this._iterationCount >= this.count) {
return exports.TaskStatus.Success;
}
// 重置子节点状态以便下次执行
this.child.invalidate();
return exports.TaskStatus.Running;
}
/**
* 获取当前执行次数
* @returns 已执行的次数
*/
getIterationCount() {
return this._iterationCount;
}
/**
* 获取剩余执行次数
* @returns 剩余次数,无限重复时返回-1
*/
getRemainingCount() {
if (this.repeatForever) {
return -1;
}
return Math.max(0, this.count - this._iterationCount);
}
/**
* 获取执行进度(0-1)
* @returns 进度百分比,无限重复时返回-1
*/
getProgress() {
if (this.repeatForever) {
return -1;
}
return Math.min(this._iterationCount / this.count, 1.0);
}
/**
* 获取最后一次子节点的执行结果
* @returns 最后的执行状态
*/
getLastChildStatus() {
return this._lastChildStatus;
}
/**
* 重置重复器状态
*/
reset() {
this._iterationCount = 0;
this._lastChildStatus = exports.TaskStatus.Invalid;
if (this.child) {
this.child.invalidate();
}
}
/**
* 创建一个重复直到成功的装饰器
* @param maxAttempts 最大尝试次数,-1表示无限
* @returns 新的Repeater实例
*/
static createUntilSuccess(maxAttempts = -1) {
return new Repeater(maxAttempts, false, true);
}
/**
* 创建一个重复直到失败的装饰器
* @param maxAttempts 最大尝试次数,-1表示无限
* @returns 新的Repeater实例
*/
static createUntilFailure(maxAttempts = -1) {
return new Repeater(maxAttempts, true, false);
}
/**
* 创建一个无限重复的装饰器
* @returns 新的Repeater实例
*/
static createInfinite() {
return new Repeater(-1, false, false);
}
}
/**
* 将继续执行其子任务,直到子任务返回失败
*/
class UntilFail extends Decorator {
update(context) {
if (!this.child) {
throw new Error("child必须不为空");
}
let status = this.child.update(context);
if (status != exports.TaskStatus.Failure)
return exports.TaskStatus.Running;
return exports.TaskStatus.Success;
}
}
/**
* 将继续执行其子任务,直到子任务返回成功
*/
class UntilSuccess extends Decorator {
update(context) {
if (!this.child) {
throw new Error("child必须不为空");
}
let status = this.child.update(context);
if (status != exports.TaskStatus.Success)
return exports.TaskStatus.Running;
return exports.TaskStatus.Success;
}
}
/**
* 并行组合器
*
* @description
* 同时执行所有子节点,直到满足终止条件:
* - 任何子节点失败时返回失败
* - 所有子节点成功时返回成功
* - 其他情况返回运行中
*
* @template T 上下文类型
*/
class Parallel extends Composite {
constructor() {
super(...arguments);
/** 缓存的子节点数量,避免重复访问length属性*/
this._childCount = 0;
}
onStart() {
super.onStart();
this._childCount = this._children.length;
}
update(context) {
if (this._childCount === 0) {
return exports.TaskStatus.Success;
}
let successCount = 0;
// 使用缓存的长度和提前退出优化
for (let i = 0; i < this._childCount; i++) {
const child = this._children[i];
child.tick(context);
const status = child.status;
// 提前退出:任何子节点失败立即返回失败
if (status === exports.TaskStatus.Failure) {
return exports.TaskStatus.Failure;
}
// 计数成功的子节点
if (status === exports.TaskStatus.Success) {
successCount++;
}
}
// 所有子节点都成功
if (successCount === this._childCount) {
return exports.TaskStatus.Success;
}
return exports.TaskStatus.Running;
}
/**
* 添加子节点时更新缓存
*/
addChild(child) {
super.addChild(child);
this._childCount = this._children.length;
}
}
/**
* 并行选择器
*
* @description
* 同时执行所有子节点,直到满足终止条件:
* - 任何子节点成功时返回成功
* - 所有子节点失败时返回失败
* - 其他情况返回运行中
*
* @template T 上下文类型
*/
class ParallelSelector extends Composite {
constructor() {
super(...arguments);
/** 缓存的子节点数量,避免重复访问length属性*/
this._childCount = 0;
}
onStart() {
super.onStart();
this._childCount = this._children.length;
}
update(context) {
if (this._childCount === 0) {
return exports.TaskStatus.Failure;
}
let failureCount = 0;
// 使用缓存的长度和提前退出优化
for (let i = 0; i < this._childCount; i++) {
const child = this._children[i];
child.tick(context);
const status = child.status;
// 提前退出:任何子节点成功立即返回成功
if (status === exports.TaskStatus.Success) {
return exports.TaskStatus.Success;
}
// 计数失败的子节点
if (status === exports.TaskStatus.Failure) {
failureCount++;
}
}
// 所有子节点都失败
if (failureCount === this._childCount) {
return exports.TaskStatus.Failure;
}
return exports.TaskStatus.Running;
}
/**
* 添加子节点时更新缓存
*/
addChild(child) {
super.addChild(child);
this._childCount = this._children.length;
}
}
/**
* 选择器组合器
*
* @description
* 类似于逻辑"或"操作,按顺序执行子节点直到找到成功的节点:
* - 任何子节点成功时返回成功
* - 所有子节点失败时返回失败
* - 子节点运行中时返回运行中
*
* @template T 上下文类型
*/
class Selector extends Composite {
constructor(abortType = AbortTypes.None) {
super();
/** 缓存的子节点数量,避免重复访问length属性*/
this._childCount = 0;
this.abortType = abortType;
}
onStart() {
super.onStart();
this._childCount = this._children.length;
// 确保每次开始时都从第一个子节点开始
this._currentChildIndex = 0;
}
update(context) {
// 检查是否有子节点
if (this._childCount === 0) {
return exports.TaskStatus.Failure;
}
// 处理条件性中止
if (this._currentChildIndex !== 0) {
this.handleConditionalAborts(context);
}
// 确保索引有效
if (this._currentChildIndex >= this._childCount) {
this._currentChildIndex = 0;
return exports.TaskStatus.Failure;
}
const current = this._children[this._currentChildIndex];
const status = current.tick(context);
// 如果子节点成功或仍在运行,直接返回
if (status !== exports.TaskStatus.Failure) {
return status;
}
this._currentChildIndex++;
// 如果已经是最后一个子节点,整个选择器失败
if (this._currentChildIndex >= this._childCount) {
this._currentChildIndex = 0;
return exports.TaskStatus.Failure;
}
return exports.TaskStatus.Running;
}
/**
* 重写invalidate方法,确保在节点无效化时重置索引
*/
invalidate() {
super.invalidate();
this._currentChildIndex = 0;
}
/**
* 添加子节点时更新缓存
*/
addChild(child) {
super.addChild(child);
this._childCount = this._children.length;
}
/**
* 处理条件性中止
*/
handleConditionalAborts(context) {
// 检查低优先级任务的状态变化
if (this._hasLowerPriorityConditionalAbort) {
this.updateLowerPriorityAbortConditional(context, exports.TaskStatus.Failure);
}
// 检查自中止条件
if (AbortTypesExt.has(this.abortType, AbortTypes.Self)) {
this.updateSelfAbortConditional(context, exports.TaskStatus.Failure);
}
}
}
/**
* 随机选择器节点
*
* @description
* 与Selector相同的执行逻辑,但在开始时会随机打乱子节点的执行顺序。
* 适用于需要随机化选择优先级的场景,增加AI决策的多样性。
*
* @template T 上下文类型
*
* @example
* ```typescript
* // 创建一个随机选择攻击方式的选择器
* const randomAttack = new RandomSelector<GameContext>();
* randomAttack.addChild(new MeleeAttack());
* randomAttack.addChild(new RangedAttack());
* randomAttack.addChild(new SpecialAttack());
* // 每次执行时,攻击方式的优先级都会被随机打乱
* ```
*/
class RandomSelector extends Selector {
/**
* 创建随机选择器节点
* @param abortType 中止类型,默认为None
* @param reshuffleOnRestart 是否在每次重新开始时都重新洗牌,默认true
*/
constructor(abortType = AbortTypes.None, reshuffleOnRestart = true) {
super(abortType);
/** 原始子节点顺序的备份 */
this._originalOrder = null;
this._reshuffleOnRestart = reshuffleOnRestart;
}
/**
* 节点开始时的处理
* 随机打乱子节点顺序
*/
onStart() {
// 首先调用父类的onStart方法,重置_currentChildIndex
super.onStart();
// 备份原始顺序(仅在第一次时)
if (this._originalOrder === null && this._children.length > 0) {
this._originalOrder = [...this._children];
}
// 只有在有多个子节点时才进行洗牌
if (this._children.length > 1) {
try {
ArrayExt.shuffle(this._children);
}
catch (error) {
console.error('RandomSelector: 洗牌子节点时发生错误:', error);
// 如果洗牌失败,恢复原始顺序
if (this._originalOrder) {
this._children = [...this._originalOrder];
}
}
}
}
/**
* 重置节点状态
* 如果启用了reshuffleOnRestart,会在下次开始时重新洗牌
*/
invalidate() {
super.invalidate();
// 如果不需要每次重启都洗牌,恢复原始顺序
if (!this._reshuffleOnRestart && this._originalOrder) {
this._children = [...this._originalOrder];
}
}
/**
* 设置是否在重新开始时重新洗牌
* @param enabled 是否启用
*/
setReshuffleOnRestart(enabled) {
this._reshuffleOnRestart = enabled;
}
/**
* 获取是否在重新开始时重新洗牌
* @returns 当前设置
*/
getReshuffleOnRestart() {
return this._reshuffleOnRestart;
}
/**
* 恢复原始子节点顺序
* @description 将子节点顺序恢复到添加时的原始顺序
*/
restoreOriginalOrder() {
if (this._originalOrder) {
this._children = [...this._originalOrder];
}
}
/**
* 手动重新洗牌子节点
* @description 立即重新洗牌子节点顺序,不等待下次开始
*/
reshuffleNow() {
if (this._children.length > 1) {
try {
ArrayExt.shuffle(this._children);
}
catch (error) {
console.error('RandomSelector: 手动洗牌时发生错误', error);
}
}
}
}
/**
* 序列组合器
*
* @description
* 类似于逻辑"与"操作,按顺序执行子节点直到所有节点成功:
* - 任何子节点失败时返回失败
* - 所有子节点成功时返回成功
* - 子节点运行中时返回运行中
*
* @template T 上下文类型
*/
class Sequence extends Composite {
constructor(abortType = AbortTypes.None) {
super();
/** 缓存的子节点数量,避免重复访问length属性*/
this._childCount = 0;
this.abortType = abortType;
}
onStart() {
super.onStart();
this._childCount = this._children.length;
// 确保每次开始时都从第一个子节点开始
this._currentChildIndex = 0;
}
update(context) {
// 检查是否有子节点
if (this._childCount === 0) {
return exports.TaskStatus.Success;
}
// 处理条件性中止
if (this._currentChildIndex !== 0) {
this.handleConditionalAborts(context);
}
// 确保索引有效
if (this._currentChildIndex >= this._childCount) {
this._currentChildIndex = 0;
return exports.TaskStatus.Success;
}
const current = this._children[this._currentChildIndex];
const status = current.tick(context);
// 如果子节点失败或仍在运行,直接返回
if (status !== exports.TaskStatus.Success) {
return status;
}
this._currentChildIndex++;
// 如果已经是最后一个子节点,整个序列成功
if (this._currentChildIndex >= this._childCount) {
this._currentChildIndex = 0;
return exports.TaskStatus.Success;
}
return exports.TaskStatus.Running;
}
/**
* 重写invalidate方法,确保在节点无效化时重置索引
*/
invalidate() {
super.invalidate();
this._currentChildIndex = 0;
}
/**
* 添加子节点时更新缓存
*/
addChild(child) {
super.addChild(child);
this._childCount = this._children.length;
}
/**
* 处理条件性中止
*/
handleConditionalAborts(context) {
// 检查低优先级任务的状态变化
if (this._hasLowerPriorityConditionalAbort) {
this.updateLowerPriorityAbortConditional(context, exports.TaskStatus.Success);
}
// 检查自中止条件
if (AbortTypesExt.has(this.abortType, AbortTypes.Self)) {
this.updateSelfAbortConditional(context, exports.TaskStatus.Success);
}
}
}
/**
* 随机序列节点
*
* @description
* 与Sequence相同的执行逻辑,但在开始时会随机打乱子节点的执行顺序。
* 适用于需要随机化行为执行顺序的场景,增加AI行为的不可预测性。
*
* @template T 上下文类型
*
* @example
* ```typescript
* // 创建一个随机执行巡逻点的序列
* const randomPatrol = new RandomSequence<GameContext>();
* randomPatrol.addChild(new MoveToPoint(point1));
* randomPatrol.addChild(new MoveToPoint(point2));
* randomPatrol.addChild(new MoveToPoint(point3));
* // 每次执行时,巡逻点的顺序都会被随机打乱
* ```
*/
class RandomSequence extends Sequence {
/**
* 创建随机序列节点
* @param abortType 中止类型,默认为None
* @param reshuffleOnRestart 是否在每次重新开始时都重新洗牌,默认true
*/
constructor(abortType = AbortTypes.None, reshuffleOnRestart = true) {
super(abortType);
/** 原始子节点顺序的备份 */
this._originalOrder = null;
this._reshuffleOnRestart = reshuffleOnRestart;
}
/**
* 节点开始时的处理
* 随机打乱子节点顺序
*/
onStart() {
// 首先调用父类的onStart方法,重置_currentChildIndex
super.onStart();
// 备份原始顺序(仅在第一次时)
if (this._originalOrder === null && this._children.length > 0) {
this._originalOrder = [...this._children];
}
// 只有在有多个子节点时才进行洗牌
if (this._children.length > 1) {
try {
ArrayExt.shuffle(this._children);
}
catch (error) {
console.error('RandomSequence: 洗牌子节点时发生错误:', error);
// 如果洗牌失败,恢复原始顺序
if (this._originalOrder) {
this._children = [...this._originalOrder];
}
}
}
}
/**
* 重置节点状态
* 如果启用了reshuffleOnRestart,会在下次开始时重新洗牌
*/
invalidate() {
super.invalidate();
// 如果不需要每次重启都洗牌,恢复原始顺序
if (!this._reshuffleOnRestart && this._originalOrder) {
this._children = [...this._originalOrder];
}
}
/**
* 设置是否在重新开始时重新洗牌
* @param enabled 是否启用
*/
setReshuffleOnRestart(enabled) {
this._reshuffleOnRestart = enabled;
}
/**
* 获取是否在重新开始时重新洗牌
* @returns 当前设置
*/
getReshuffleOnRestart() {
return this._reshuffleOnRestart;
}
/**
* 恢复原始子节点顺序
* @description 将子节点顺序恢复到添加时的原始顺序
*/
restoreOriginalOrder() {
if (this._originalOrder) {
this._children = [...this._originalOrder];
}
}
/**
* 手动重新洗牌子节点
* @description 立即重新洗牌子节点顺序,不等待下次开始
*/
reshuffleNow() {
if (this._children.length > 1) {
try {
ArrayExt.shuffle(this._children);
}
catch (error) {
console.error('RandomSequence: 手动洗牌时发生错误', error);
}
}
}
}
/**
* 设置黑板变量值
*
* @description 将指定值或另一个黑板变量的值设置到目标变量
*
* @example
* ```typescript
* // 设置固定值
* const setHealth = new SetBlackboardValue<GameContext>('playerHealth', 100);
*
* // 从另一个变量复制值
* const copyValue = new SetBlackboardValue<GameContext>('targetHealth', null, 'playerHealth');
* ```
*/
class SetBlackboardValue extends Behavior {
constructor(variableName, value = null, sourceVariable, force = false) {
super();
this.variableName = variableName;
this.value = value;
this.sourceVariable = sourceVariable;
this.force = force;
}
update(context) {
const blackboard = context.blackboard;
if (!blackboard || !(blackboard instanceof Blackboard)) {
console.warn('SetBlackboardValue: 上下文中未找到Blackboard实例');
return exports.TaskStatus.Failure;
}
let valueToSet;
if (this.sourceVariable) {
if (!blackboard.hasVariable(this.sourceVariable)) {
console.warn(`SetBlackboardValue: 源变量 "${this.sourceVariable}" 不存在`);
return exports.TaskStatus.Failure;
}
valueToSet = blackboard.getValue(this.sourceVariable);
}
else {
valueToSet = this.value;
// 处理黑板变量引用,如 "{{variableName}}"
if (typeof valueToSet === 'string') {
// 检查是否是纯黑板变量引用(如 "{{variableName}}")
const pureVariableMatch = valueToSet.match(/^{{\s*(\w+)\s*}}$/);
if (pureVariableMatch) {
// 纯变量引用,返回原始类型的值
const varName = pureVariableMatch[1];
if (blackboard.hasVariable(varName)) {
valueToSet = blackboard.getValue(varName);
}
else {
console.warn(`SetBlackboardValue: 引用的变量 "${varName}" 不存在`);
return exports.TaskStatus.Failure;
}
}
else {
// 包含变量的字符串模板,进行字符串替换
valueToSet = valueToSet.replace(/\{\{(\w+)\}\}/g, (match, varName) => {
if (blackboard.hasVariable(varName)) {
const value = blackboard.getValue(varName);
return value !== undefined ? String(value) : match;
}
return match;
});
}
}
}
// 获取目标变量的类型定义,确保类型匹配
const targetVariableDef = blackboard.getVariableDefinition(this.variableName);
if (targetVariableDef && valueToSet !== null && valueToSet !== undefined) {
// 根据目标变量类型转换值
valueToSet = this.convertValueToTargetType(valueToSet, targetVariableDef.type);
}
const success = blackboard.setValue(this.variableName, valueToSet, this.force);
return success ? exports.TaskStatus.Success : exports.TaskStatus.Failure;
}
/**
* 将值转换为目标类型
*/
convertValueToTargetType(value, targetType) {
if (value === null || value === undefined) {
return value;
}
// 处理枚举值和字符串值
const typeStr = targetType === exports.BlackboardValueType.Number || targetType === 'number' ? 'number' :
targetType === exports.BlackboardValueType.String || targetType === 'string' ? 'string' :
targetType === exports.BlackboardValueType.Boolean || targetType === 'boolean' ? 'boolean' :
'unknown';
// 如果已经是正确类型,直接返回
switch (typeStr) {
case 'string':
return typeof value === 'string' ? value : String(value);
case 'number':
if (typeof value === 'number')
return value;
if (typeof value === 'string') {
const num = parseFloat(value);
return isNaN(num) ? 0 : num;
}
return Number(value) || 0;
case 'boolean':
if (typeof value === 'boolean')
return value;
if (typeof value === 'string') {
return value.toLowerCase() === 'true';
}
return Boolean(value);
default:
return value;
}
}
}
/**
* 增加数值型黑板变量
*
* @description 将数值型变量增加指定的数值,支持从另一个变量获取增量
*/
class AddToBlackboardValue extends Behavior {
constructor(variableName, increment, incrementVariable) {
super();
this.variableName = variableName;
this.increment = increment;
this.incrementVariable = incrementVariable;
}
update(context) {
const blackboard = context.blackboard;
if (!blackboard || !(blackboard instanceof Blackboard)) {
console.warn('AddToBlackboardValue: 上下文中未找到Blackboard实例');
return exports.TaskStatus.Failure;
}
if (!blackboard.hasVariable(this.variableName)) {
console.warn(`AddToBlackboardValue: 变量 "${this.variableName}" 不存在`);
return exports.TaskStatus.Failure;
}
const currentValue = blackboard.getValue(this.variableName);
if (typeof currentValue !== 'number') {
console.warn(`AddToBlackboardValue: 变量 "${this.variableName}" 不是数值类型`);
return exports.TaskStatus.Failure;
}
let incrementValue;
if (this.incrementVariable) {
if (!blackboard.hasVariable(this.incrementVariable)) {
console.warn(`AddToBlackboardValue: 增量变量 "${this.incrementVariable}" 不存在`);
return exports.TaskStatus.Failure;
}
incrementValue = blackboard.getValue(this.incrementVariable);
if (typeof incrementValue !== 'number') {
console.warn(`AddToBlackboardValue: 增量变量 "${this.incrementVariable}" 不是数值类型`);
return exports.TaskStatus.Failure;
}
}
else {
incrementValue = this.increment;
}
const newValue = currentValue + incrementValue;
const success = blackboard.setValue(this.variableName, newValue);
return success ? exports.TaskStatus.Success : exports.TaskStatus.Failure;
}
}
/**
* 切换布尔型黑板变量
*
* @description 将布尔型变量的值取反
*/
class ToggleBlackboardBool extends Behavior {
constructor(variableName) {
super();
this.variableName = variableName;
}
update(context) {
const blackboard = context.blackboard;
if (!blackboard || !(blackboard instanceof Blackboard)) {
console.warn('ToggleBlackboardBool: 上下文中未找到Blackboard实例');
return exports.TaskStatus.Failure;
}
if (!blackboard.hasVariable(this.variableName)) {
console.warn(`ToggleBlackboardBool: 变量 "${this.variableName}" 不存在`);
return exports.TaskStatus.Failure;
}
const currentValue = blackboard.getValue(this.variableName);
if (typeof currentValue !== 'boolean') {
console.warn(`ToggleBlackboardBool: 变量 "${this.variableName}" 不是布尔类型`);
return exports.TaskStatus.Failure;
}
const success = blackboard.setValue(this.variableName, !currentValue);
return success ? exports.TaskStatus.Success : exports.TaskStatus.Failure;
}
}
/**
* 重置黑板变量到默认值
*
* @description 将指定变量重置为其定义时的默认值
*/
class ResetBlackboardVariable extends Behavior {
constructor(variableName) {
super();
this.variableName = variableName;
}
update(context) {
const blackboard = context.blackboard;
if (!blackboard || !(blackboard instanceof Blackboard)) {
console.warn('ResetBlackboardVariable: 上下文中未找到Blackboard实例');
return exports.TaskStatus.Failure;
}
const success = blackboard.resetVariable(this.variableName);
return success ? exports.TaskStatus.Success : exports.TaskStatus.Failure;
}
}
/**
* 等待黑板变量满足条件
*
* @description 等待指定的黑板变量满足某个条件,常用于同步操作
*/
class WaitForBlackboardCondition extends Behavior {
constructor(variableName, expectedValue, compareFn) {
super();
this.variableName = variableName;
this.expectedValue = expectedValue;
this.compareFn = compareFn;
}
update(context) {
const blackboard = context.blackboard;
if (!blackboard || !(blackboard instanceof Blackboard)) {
console.warn('WaitForBlackboardCondition: 上下文中未找到Blackboard实例');
return exports.TaskStatus.Failure;
}
if (!blackboard.hasVariable(this.variableName)) {
console.warn(`WaitForBlackboardCondition: 变量 "${this.variableName}" 不存在`);
return exports.TaskStatus.Failure;
}
const currentValue = blackboard.getValue(this.variableName);
let conditionMet;
if (this.compareFn) {
conditionMet = this.compareFn(currentValue, this.expectedValue);
}
else {
conditionMet = currentValue === this.expectedValue;
}
return conditionMet ? exports.TaskStatus.Success : exports.TaskStatus.Running;
}
}
/**
* 记录黑板变量到控制台
*
* @description 将黑板变量的当前值记录到控制台,用于调试
*/
class LogBlackboardValue extends Behavior {
constructor(variableName, prefix = '[Blackboard]') {
super();
this.variableName = variableName;
this.prefix = prefix;
}
update(context) {
const blackboard = context.blackboard;
if (!blackboard || !(blackboard instanceof Blackboard)) {
console.warn('LogBlackboardValue: 上下文中未找到Blackboard实例');
return exports.TaskStatus.Failure;
}
if (!blackboard.hasVariable(this.variableName)) {
console.warn(`LogBlackboardValue: 变量 "${this.variableName}" 不存在`);
return exports.TaskStatus.Failure;
}
const value = blackboard.getValue(this.variableName);
const variableDefinition = blackboard.getVariableDefinition(this.variableName);
console.log(`${this.prefix} ${this.variableName} (${variableDefinition?.type}):`, value);
return exports.TaskStatus.Success;
}
}
/**
* 数学运算黑板变量
*
* @description 对数值型黑板变量执行数学运算
*/
var MathOperation;
(function (MathOperation) {
MathOperation["Add"] = "add";
MathOperation["Subtract"] = "subtract";
MathOperation["Multiply"] = "multiply";
MathOperation["Divide"] = "divide";
MathOperation["Modulo"] = "modulo";
MathOperation["Power"] = "power";
MathOperation["Min"] = "min";
MathOperation["Max"] = "max";
})(MathOperation || (MathOperation = {}));
class MathBlackboardOperation extends Behavior {
constructor(targetVariable, operand1Variable, operand2, operation) {
super();
this.targetVariable = targetVariable;
this.operand1Variable = operand1Variable;
this.operand2 = operand2;
this.operation = operation;
}
update(context) {
const blackboard = context.blackboard;
if (!blackboard || !(blackboard instanceof Blackboard)) {
console.warn('MathBlackboardOperation: 上下文中未找到Blackboard实例');
return exports.TaskStatus.Failure;
}
// 获取第一个操作数
if (!blackboard.hasVariable(this.operand1Variable)) {
console.warn(`MathBlackboardOperation: 操作数变量 "${this.operand1Variable}" 不存在`);
return exports.TaskStatus.Failure;
}
const operand1 = blackboard.getValue(this.operand1Variable);
if (typeof operand1 !== 'number') {
console.warn(`MathBlackboardOperation: 操作数变量 "${this.operand1Variable}" 不是数值类型`);
return exports.TaskStatus.Failure;
}
// 获取第二个操作数
let operand2;
if (typeof this.operand2 === 'string') {
if (!blackboard.hasVariable(this.operand2)) {
console.warn(`MathBlackboardOperation: 操作数变量 "${this.operand2}" 不存在`);
return exports.TaskStatus.Failure;
}
operand2 = blackboard.getValue(this.operand2);
if (typeof operand2 !== 'number') {
console.warn(`MathBlackboardOperation: 操作数变量 "${this.operand2}" 不是数值类型`);
return exports.TaskStatus.Failure;
}
}
else {
operand2 = this.operand2;
}
// 执行数学运算
let result;
try {
switch (this.operation) {
case MathOperation.Add:
result = operand1 + operand2;
break;
case MathOperation.Subtract:
result = operand1 - operand2;
break;
case MathOperation.Multiply:
result = operand1 * operand2;
break;
case MathOperation.Divide:
if (operand2 === 0) {
console.warn('MathBlackboardOperation: 除数不能为零');
return exports.TaskStatus.Failure;
}
result = operand1 / operand2;
break;
case MathOperation.Modulo:
if (operand2 === 0) {
console.warn('MathBlackboardOperation: 模运算的除数不能为零');
return exports.TaskStatus.Failure;
}
result = operand1 % operand2;
break;
case MathOperation.Power:
result = Math.pow(operand1, operand2);
break;
case MathOperation.Min:
result = Math.min(operand1, operand2);
break;
case MathOperation.Max:
result = Math.max(operand1, operand2);
break;
default:
console.warn(`MathBlackboardOperation: 不支持的数学操作 "${this.operation}"`);
return exports.TaskStatus.Failure;
}
}
catch (error) {
console.error('MathBlackboardOperation: 数学运算执行失败:', error);
return exports.TaskStatus.Failure;
}
// 设置结果
const success = blackboard.setValue(this.targetVariable, result);
return success ? exports.TaskStatus.Success : exports.TaskStatus.Failure;
}
}
/**
* 数值比较条件
*
* @description 对上下文中的数值属性进行比较
*/
class NumericComparison {
constructor(propertyPath, compareOperator, compareValue) {
this.discriminator = 'IConditional';
this.propertyPath = propertyPath;
this.compareOperator = compareOperator;
this.compareValue = compareValue;
}
update(context) {
try {
const value = this._getNestedProperty(context, this.propertyPath);
if (typeof value !== 'number') {
console.warn(`NumericComparison: 属性 "${this.propertyPath}" 不是数值类型,值为: ${value}`);
return exports.TaskStatus.Failure;
}
const result = this._performComparison(value, this.compareValue, this.compareOperator);
return result ? exports.TaskStatus.Success : exports.TaskStatus.Failure;
}
catch (error) {
console.error(`NumericComparison: 访问属性 "${this.propertyPath}" 时发生错误:`, error);
return exports.TaskStatus.Failure;
}
}
/**
* 获取嵌套属性值
*/
_getNestedProperty(obj, path) {
return path.split('.').reduce((current, key) => {
return current && current[key] !== undefined ? current[key] : undefined;
}, obj);
}
/**
* 执行数值比较
*/
_performComparison(left, right, operator) {
switch (operator) {
case 'greater': return left > right;
case 'less': return left < right;
case 'equal': return left === right;
case 'greaterEqual': return left >= right;
case 'lessEqual': return left <= right;
case 'notEqual': return left !== right;
default:
console.warn(`NumericComparison: 未知的比较操作符: ${operator}`);
return false;
}
}
}
/**
* 属性存在检查条件
*
* @description 检查上下文对象中是否存在指定的属性
*/
class PropertyExists {
constructor(propertyPath) {
this.discriminator = 'IConditional';
this.propertyPath = propertyPath;
}
update(context) {
try {
const value = this._getNestedProperty(context, this.propertyPath);
const exists = value !== undefined && value !== null;
return exists ? exports.TaskStatus.Success : exports.TaskStatus.Failure;
}
catch (error) {
console.error(`PropertyExists: 访问属性 "${this.propertyPath}" 时发生错误:`, error);
return exports.TaskStatus.Failure;
}
}
/**
* 获取嵌套属性值
*/
_getNestedProperty(obj, path) {
return path.split('.').reduce((current, key) => {
return current && current[key] !== undefined ? current[key] : undefined;
}, obj);
}
}
/**
* 冷却装饰器
*
* @description 在指定时间内阻止子节点重复执行,实现技能冷却等机制
*/
class CooldownDecorator extends Decorator {
constructor(cooldownTime) {
super();
/** 上次执行时间 */
this.lastExecutionTime = 0;
this.cooldownTime = cooldownTime;
}
onStart() {
if (this.child && this.child.onStart) {
this.child.onStart();
}
}
update(context) {
const currentTime = performance.now() / 1000;
// 检查是否还在冷却中
if (currentTime - this.lastExecutionTime < this.cooldownTime) {
return exports.TaskStatus.Failure; // 还在冷却中
}
// 执行子节点
const childResult = this.child ? this.child.update(context) : exports.TaskStatus.Success;
// 如果子节点执行完成(成功或失败),更新最后执行时间
if (childResult === exports.TaskStatus.Success || childResult === exports.TaskStatus.Failure) {
this.lastExecutionTime = currentTime;
}
return childResult;
}
onEnd() {
if (this.child && this.child.onEnd) {
this.child.onEnd();
}
}
/**
* 重置冷却时间
*/
resetCooldown() {
this.lastExecutionTime = 0;
}
/**
* 获取剩余冷却时间
*/
getRemainingCooldownTime() {
const currentTime = performance.now() / 1000;
const remaining = this.cooldownTime - (currentTime - this.lastExecutionTime);
return Math.max(0, remaining);
}
/**
* 检查是否在冷却中
*/
isOnCooldown() {
return this.getRemainingCooldownTime() > 0;
}
}
/**
* 超时装饰器
*
* @description 如果子节点执行时间超过指定限制,则强制返回失败状态
*/
class TimeoutDecorator extends Decorator {
constructor(timeoutDuration) {
super();
/** 开始执行时间 */
this.startTime = 0;
/** 是否已开始执行 */
this.hasStarted = false;
this.timeoutDuration = timeoutDuration;
}
onStart() {
this.startTime = performance.now() / 1000;
this.hasStarted = true;
if (this.child && this.child.onStart) {
this.child.onStart();
}
}
update(context) {
if (!this.hasStarted) {
return exports.TaskStatus.Failure;
}
const currentTime = performance.now() / 1000;
const elapsedTime = currentTime - this.startTime;
// 检查是否超时
if (elapsedTime >= this.timeoutDuration) {
console.warn(`TimeoutDecorator: 子节点执行超时 (${elapsedTime.toFixed(2)}s >= ${this.timeoutDuration}s)`);
return exports.TaskStatus.Failure; // 超时失败
}
// 执行子节点
const childResult = this.child ? this.child.update(context) : exports.TaskStatus.Success;
// 如果子节点完成,重置状态
if (childResult !== exports.TaskStatus.Running) {
this.hasStarted = false;
}
return childResult;
}
onEnd() {
this.hasStarted = false;
if (this.child && this.child.onEnd) {
this.child.onEnd();
}
}
/**
* 获取剩余时间
*/
getRemainingTime() {
if (!this.hasStarted) {
return this.timeoutDuration;
}
const currentTime = performance.now() / 1000;
const elapsedTime = currentTime - this.startTime;
return Math.max(0, this.timeoutDuration - elapsedTime);
}
/**
* 获取已执行时间
*/
getElapsedTime() {
if (!this.hasStarted) {
return 0;
}
const currentTime = performance.now() / 1000;
return currentTime - this.startTime;
}
/**
* 检查是否已超时
*/
isTimedOut() {
return this.getRemainingTime() <= 0;
}
}
/**
* 概率装饰器
*
* @description 以指定概率执行子节点,用于实现随机性行为
*/
class ChanceDecorator extends Decorator {
constructor(successChance) {
super();
this.successChance = Math.max(0, Math.min(1, successChance)); // 确保在0-1范围内
}
onStart() {
if (this.child && this.child.onStart) {
this.child.onStart();
}
}
update(context) {
// 进行概率检查
const random = Math.random();
if (random > this.successChance) {
// 概率检查失败,不执行子节点
return exports.TaskStatus.Failure;
}
// 概率检查成功,执行子节点
return this.child ? this.child.update(context) : exports.TaskStatus.Success;
}
onEnd() {
if (this.child && this.child.onEnd) {
this.child.onEnd();
}
}
/**
* 设置成功概率
*/
setSuccessChance(chance) {
this.successChance = Math.max(0, Math.min(1, chance));
}
/**
* 获取成功概率
*/
getSuccessChance() {
return this.successChance;
}
/**
* 获取成功概率百分比
*/
getSuccessChancePercentage() {
return this.successChance * 100;
}
}
/**
* 行为树构建器类
* @description 提供构建行为树的流畅API和配置加载功能
* @template T 执行上下文类型
*
* @example
* ```typescript
* // 使用流畅API构建
* const tree = BehaviorTreeBuilder.begin(context)
* .selector()
* .sequence()
* .logAction("开始执行")
* .waitAction(1.0)
* .endComposite()
* .logAction("备选方案")
* .endComposite()
* .build();
*
* // 从JSON配置构建
* const result = BehaviorTreeBuilder.fromBehaviorTreeConfig(jsonConfig, context);
* ```
*/
class BehaviorTreeBuilder {
/**
* 构造函数
* @param context 执行上下文
*/
constructor(context) {
/** 父节点堆栈,用于流畅API构建 */
this._parentNodeStack = new Array();
this._context = context;
}
/**
* 开始构建行为树
* @param context 执行上下文
* @returns 新的构建器实例
*/
static begin(context) {
return new BehaviorTreeBuilder(context);
}
/**
* 设置子节点到父节点
* @param child 子节点
* @returns 构建器实例
*/
setChildOnParent(child) {
const parent = this._parentNodeStack[this._parentNodeStack.length - 1];
if (parent instanceof Composite) {
parent.addChild(child);
}
else if (parent instanceof Decorator) {
// 装饰器只有一个子节点,所以自动结束
parent.child = child;
this.endDecorator();
}
return this;
}
/**
* 将节点推入父节点堆栈
* @param composite 复合节点或装饰器节点
* @returns 构建器实例
*/
pushParentNode(composite) {
if (this._parentNodeStack.length > 0) {
this.setChildOnParent(composite);
}
this._parentNodeStack.push(composite);
return this;
}
/**
* 结束装饰器节点
* @returns 构建器实例
*/
endDecorator() {
this._currentNode = this._parentNodeStack.pop();
return this;
}
/**
* 添加动作节点
* @param func 动作执行函数
* @returns 构建器实例
*/
action(func) {
if (this._parentNodeStack.length === 0) {
throw new Error("无法创建无嵌套的动作节点,它必须是一个叶节点");
}
return this.setChildOnParent(new ExecuteAction(func));
}
/**
* 添加返回布尔值的动作节点
* @param func 返回布尔值的函数
* @returns 构建器实例
*/
actionR(func) {
return this.action(t => func(t) ? exports.TaskStatus.Success : exports.TaskStatus.Failure);
}
/**
* 添加条件节点
* @param func 条件检查函数
* @returns 构建器实例
*/
conditional(func) {
if (this._parentNodeStack.length === 0) {
throw new Error("无法创建无嵌套的条件节点,它必须是一个叶节点");
}
return this.setChildOnParent(new ExecuteActionConditional(func));
}
/**
* 添加返回布尔值的条件节点
* @param func 返回布尔值的条件函数
* @returns 构建器实例
*/
conditionalR(func) {
return this.conditional(t => func(t) ? exports.TaskStatus.Success : exports.TaskStatus.Failure);
}
/**
* 添加日志动作节点
* @param text 日志文本
* @returns 构建器实例
*/
logAction(text) {
if (this._parentNodeStack.length === 0) {
throw new Error("无法创建无嵌套的动作节点,它必须是一个叶节点");
}
return this.setChildOnParent(new LogAction(text));
}
/**
* 添加等待动作节点
* @param waitTime 等待时间(秒)
* @returns 构建器实例
*/
waitAction(waitTime) {
if (this._parentNodeStack.length === 0) {
throw new Error("无法创建无嵌套的动作节点,它必须是一个叶节点");
}
return this.setChildOnParent(new WaitAction(waitTime));
}
/**
* 添加子行为树节点
* @param subTree 子行为树实例
* @returns 构建器实例
*/
subTree(subTree) {
if (this._parentNodeStack.length === 0) {
throw new Error("无法创建无嵌套的动作节点,它必须是一个叶节点");
}
return this.setChildOnParent(new BehaviorTreeReference(subTree));
}
/**
* 添加条件装饰器
* @param func 条件函数
* @param shouldReevaluate 是否重新评估
* @returns 构建器实例
*/
conditionalDecorator(func, shouldReevaluate = true) {
const conditional = new ExecuteActionConditional(func);
return this.pushParentNode(new ConditionalDecorator(conditional, shouldReevaluate));
}
/**
* 添加返回布尔值的条件装饰器
* @param func 返回布尔值的条件函数
* @param shouldReevaluate 是否重新评估
* @returns 构建器实例
*/
conditionalDecoratorR(func, shouldReevaluate = true) {
return this.conditionalDecorator(t => func(t) ? exports.TaskStatus.Success : exports.TaskStatus.Failure, shouldReevaluate);
}
/**
* 添加总是失败装饰器
* @returns 构建器实例
*/
alwaysFail() {
return this.pushParentNode(new AlwaysFail());
}
/**
* 添加总是成功装饰器
* @returns 构建器实例
*/
alwaysSucceed() {
return this.pushParentNode(new AlwaysSucceed());
}
/**
* 添加反转装饰器
* @returns 构建器实例
*/
inverter() {
return this.pushParentNode(new Inverter());
}
/**
* 添加重复装饰器
* @param count 重复次数
* @returns 构建器实例
*/
repeater(count) {
return this.pushParentNode(new Repeater(count));
}
/**
* 添加直到失败装饰器
* @returns 构建器实例
*/
untilFail() {
return this.pushParentNode(new UntilFail());
}
/**
* 添加直到成功装饰器
* @returns 构建器实例
*/
untilSuccess() {
return this.pushParentNode(new UntilSuccess());
}
/**
* 添加并行节点
* @returns 构建器实例
*/
paraller() {
return this.pushParentNode(new Parallel());
}
/**
* 添加并行选择器节点
* @returns 构建器实例
*/
parallelSelector() {
return this.pushParentNode(new ParallelSelector());
}
/**
* 添加选择器节点
* @param abortType 中止类型
* @returns 构建器实例
*/
selector(abortType = AbortTypes.None) {
return this.pushParentNode(new Selector(abortType));
}
/**
* 添加随机选择器节点
* @returns 构建器实例
*/
randomSelector() {
return this.pushParentNode(new RandomSelector());
}
/**
* 添加序列节点
* @param abortType 中止类型
* @returns 构建器实例
*/
sequence(abortType = AbortTypes.None) {
return this.pushParentNode(new Sequence(abortType));
}
/**
* 添加随机序列节点
* @returns 构建器实例
*/
randomSequence() {
return this.pushParentNode(new RandomSequence());
}
/**
* 结束复合节点
* @returns 构建器实例
*/
endComposite() {
const topNode = this._parentNodeStack[this._parentNodeStack.length - 1];
if (!(topNode instanceof Composite)) {
throw new Error("尝试结束复合器,但顶部节点是装饰器");
}
this._currentNode = this._parentNodeStack.pop();
return this;
}
/**
* 构建最终的行为树
* @param updatePeriod 更新周期(秒),默认0.2秒
* @returns 构建好的行为树实例
*/
build(updatePeriod = 0.2) {
if (!this._currentNode) {
throw new Error('无法创建零节点的行为树');
}
return new BehaviorTree(this._context, this._currentNode, updatePeriod);
}
/**
* 从配置对象创建行为树
* @param config 行为树配置
* @param context 执行上下文
* @returns 构建好的行为树
*/
static fromConfig(config, context) {
try {
if (!config || !config.tree) {
throw new Error('配置无效:缺少tree属性');
}
const rootNode = BehaviorTreeBuilder.createNodeFromConfig(config.tree);
const updatePeriod = config.metadata?.updatePeriod ?? 0.2;
return new BehaviorTree(context, rootNode, updatePeriod);
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
throw new Error(`从配置创建行为树失败: ${errorMessage}`);
}
}
/**
* 从JSON配置创建行为树
* @description 自动初始化黑板变量和构建节点树,提供一键式行为树创建
* @param config JSON格式的行为树配置
* @param context 执行上下文(可选,如果不提供将创建默认上下文)
* @returns 包含行为树、黑板和增强上下文的结果对象
*
* @example
* ```typescript
* const config = {
* nodes: [...],
* blackboard: [...],
* metadata: { name: "MyBehaviorTree" }
* };
* const result = BehaviorTreeBuilder.fromBehaviorTreeConfig(config, context);
* const { tree, blackboard, context: enhancedContext } = result;
* ```
*/
static fromBehaviorTreeConfig(config, context) {
try {
// 验证配置
if (!config || !config.nodes || config.nodes.length === 0) {
throw new Error('配置无效:缺少nodes属性或nodes为空');
}
// 创建黑板并初始化变量
const blackboard = new Blackboard();
if (config.blackboard && config.blackboard.length > 0) {
for (const variable of config.blackboard) {
// 映射类型字符串到枚举
const blackboardType = BehaviorTreeBuilder.mapToBlackboardType(variable.type);
// 转换值类型以匹配黑板期望的类型
const convertedValue = BehaviorTreeBuilder.convertBlackboardValue(variable.value, blackboardType);
blackboard.defineVariable(variable.name, blackboardType, convertedValue, {
description: variable.description,
group: variable.group || 'Default',
readonly: variable.constraints?.readonly ?? false
});
}
}
// 创建或增强执行上下文
const enhancedContext = (context || {});
enhancedContext.blackboard = blackboard;
// 构建节点树
const nodeMap = new Map();
// 建立节点映射
for (const node of config.nodes) {
nodeMap.set(node.id, node);
}
// 找到根节点(通常是第一个节点或type为'root'的节点)
const rootNodeConfig = config.nodes.find(n => n.type === 'root') || config.nodes[0];
if (!rootNodeConfig) {
throw new Error('未找到根节点');
}
// 递归构建节点树
const rootNode = BehaviorTreeBuilder.createNodeFromJSONConfig(rootNodeConfig, nodeMap, enhancedContext);
// 创建行为树
const updatePeriod = config.metadata?.updatePeriod ?? 0.2;
const tree = new BehaviorTree(enhancedContext, rootNode, updatePeriod, false, blackboard);
return { tree, blackboard, context: enhancedContext };
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
throw new Error(`从配置创建行为树失败: ${errorMessage}`);
}
}
/**
* 映射字符串类型到BlackboardValueType枚举
* @param typeString 类型字符串
* @returns 对应的黑板值类型枚举
*/
static mapToBlackboardType(typeString) {
switch (typeString.toLowerCase()) {
case 'string':
return exports.BlackboardValueType.String;
case 'number':
return exports.BlackboardValueType.Number;
case 'boolean':
return exports.BlackboardValueType.Boolean;
case 'vector2':
return exports.BlackboardValueType.Vector2;
case 'vector3':
return exports.BlackboardValueType.Vector3;
case 'object':
return exports.BlackboardValueType.Object;
case 'array':
return exports.BlackboardValueType.Array;
default:
console.warn(`未知的变量类型: ${typeString}, 默认使用Object类型`);
return exports.BlackboardValueType.Object;
}
}
/**
* 转换黑板变量值到正确的类型
* @param value 原始值(通常来自JSON,都是字符串)
* @param targetType 目标类型
* @returns 转换后的值
*/
static convertBlackboardValue(value, targetType) {
// 为不同类型提供合理的默认值
if (value === null || value === undefined || value === '') {
switch (targetType) {
case exports.BlackboardValueType.String:
return '';
case exports.BlackboardValueType.Number:
return 0;
case exports.BlackboardValueType.Boolean:
return false; // 布尔类型默认为false
case exports.BlackboardValueType.Vector2:
return { x: 0, y: 0 };
case exports.BlackboardValueType.Vector3:
return { x: 0, y: 0, z: 0 };
case exports.BlackboardValueType.Object:
return {};
case exports.BlackboardValueType.Array:
return [];
default:
return null;
}
}
switch (targetType) {
case exports.BlackboardValueType.String:
return String(value);
case exports.BlackboardValueType.Number:
if (typeof value === 'string') {
const num = parseFloat(value);
if (isNaN(num)) {
console.warn(`无法将 "${value}" 转换为数字,使用默认值 0`);
return 0;
}
return num;
}
return typeof value === 'number' ? value : 0;
case exports.BlackboardValueType.Boolean:
if (typeof value === 'string') {
// 处理空字符串的情况
if (value === '')
return false;
return value.toLowerCase() === 'true';
}
return Boolean(value);
case exports.BlackboardValueType.Vector2:
if (typeof value === 'string') {
try {
const parsed = JSON.parse(value);
return parsed && typeof parsed === 'object' && 'x' in parsed && 'y' in parsed
? parsed
: { x: 0, y: 0 };
}
catch {
console.warn(`无法解析Vector2值 "${value}",使用默认值 {x:0, y:0}`);
return { x: 0, y: 0 };
}
}
return value && typeof value === 'object' && 'x' in value && 'y' in value
? value
: { x: 0, y: 0 };
case exports.BlackboardValueType.Vector3:
if (typeof value === 'string') {
try {
const parsed = JSON.parse(value);
return parsed && typeof parsed === 'object' && 'x' in parsed && 'y' in parsed && 'z' in parsed
? parsed
: { x: 0, y: 0, z: 0 };
}
catch {
console.warn(`无法解析Vector3值 "${value}",使用默认值 {x:0, y:0, z:0}`);
return { x: 0, y: 0, z: 0 };
}
}
return value && typeof value === 'object' && 'x' in value && 'y' in value && 'z' in value
? value
: { x: 0, y: 0, z: 0 };
case exports.BlackboardValueType.Object:
if (typeof value === 'string') {
try {
return JSON.parse(value);
}
catch {
console.warn(`无法解析Object值 "${value}",使用默认值 {}`);
return {};
}
}
return typeof value === 'object' ? value : {};
case exports.BlackboardValueType.Array:
if (typeof value === 'string') {
try {
const parsed = JSON.parse(value);
return Array.isArray(parsed) ? parsed : [];
}
catch {
console.warn(`无法解析Array值 "${value}",使用默认值 []`);
return [];
}
}
return Array.isArray(value) ? value : [];
default:
return value;
}
}
/**
* 从节点配置创建节点实例
* @param nodeConfig 节点配置
* @returns 创建的节点实例
*/
static createNodeFromConfig(nodeConfig) {
let node;
// 根据节点类型创建对应的节点实例
switch (nodeConfig.type) {
// 复合节点
case 'Sequence':
const sequenceAbortValue = nodeConfig.properties?.abortType?.value;
const sequenceAbortType = BehaviorTreeBuilder.getAbortType(typeof sequenceAbortValue === 'string' ? sequenceAbortValue : 'None');
node = new Sequence(sequenceAbortType);
break;
case 'Selector':
const selectorAbortValue = nodeConfig.properties?.abortType?.value;
const selectorAbortType = BehaviorTreeBuilder.getAbortType(typeof selectorAbortValue === 'string' ? selectorAbortValue : 'None');
node = new Selector(selectorAbortType);
break;
case 'Parallel':
node = new Parallel();
break;
case 'ParallelSelector':
node = new ParallelSelector();
break;
case 'RandomSelector':
node = new RandomSelector();
break;
case 'RandomSequence':
node = new RandomSequence();
break;
// 装饰器节点
case 'AlwaysSucceed':
node = new AlwaysSucceed();
break;
case 'AlwaysFail':
node = new AlwaysFail();
break;
case 'Inverter':
node = new Inverter();
break;
case 'Repeater':
const countValue = nodeConfig.properties?.count?.value;
const count = typeof countValue === 'number' ? countValue : 1;
node = new Repeater(count);
break;
case 'UntilSuccess':
node = new UntilSuccess();
break;
case 'UntilFail':
node = new UntilFail();
break;
// 动作节点
case 'LogAction':
const messageValue = nodeConfig.properties?.message?.value;
const message = typeof messageValue === 'string' ? messageValue : 'Default log message';
node = new LogAction(message);
break;
case 'WaitAction':
const waitTimeValue = nodeConfig.properties?.waitTime?.value;
const waitTime = typeof waitTimeValue === 'number' ? waitTimeValue : 1.0;
node = new WaitAction(waitTime);
break;
case 'ExecuteAction':
// 对于自定义动作,我们创建一个默认的执行函数
const actionCode = nodeConfig.properties?.actionCode?.value;
if (actionCode && typeof actionCode === 'string') {
try {
// 简单的代码执行(在实际项目中应该更安全地处理)
const actionFunc = new Function('context', 'TaskStatus', `
const { Success, Failure, Running } = TaskStatus;
${actionCode}
`);
node = new ExecuteAction((context) => {
try {
return actionFunc(context, exports.TaskStatus);
}
catch (error) {
console.error('执行动作失败:', error);
return exports.TaskStatus.Failure;
}
});
}
catch (error) {
console.warn('解析动作代码失败,使用默认动作:', error);
node = new ExecuteAction(() => exports.TaskStatus.Success);
}
}
else {
node = new ExecuteAction(() => exports.TaskStatus.Success);
}
break;
default:
console.warn('⚠️ 未知的节点类型:', nodeConfig.type, ',使用默认动作节点');
node = new ExecuteAction(() => exports.TaskStatus.Success);
break;
}
// 为复合节点和装饰器添加子节点
if (nodeConfig.children && nodeConfig.children.length > 0) {
if (node instanceof Composite) {
// 复合节点可以有多个子节点
for (const childConfig of nodeConfig.children) {
const childNode = BehaviorTreeBuilder.createNodeFromConfig(childConfig);
node.addChild(childNode);
}
}
else if (node instanceof Decorator) {
// 装饰器只能有一个子节点
if (nodeConfig.children.length > 1) {
console.warn('⚠️ 装饰器节点只能有一个子节点,将使用第一个');
}
const childNode = BehaviorTreeBuilder.createNodeFromConfig(nodeConfig.children[0]);
node.child = childNode;
}
}
return node;
}
/**
* 解析中止类型字符串为枚举值
* @param value 中止类型字符串
* @returns 对应的中止类型枚举值
*/
static getAbortType(value) {
switch (value) {
case 'LowerPriority':
return AbortTypes.LowerPriority;
case 'Self':
return AbortTypes.Self;
case 'Both':
return AbortTypes.Both;
default:
return AbortTypes.None;
}
}
/**
* 从JSON节点配置创建节点实例
* @description 递归创建节点树,支持所有标准行为树节点类型
* @param nodeConfig 当前节点配置
* @param nodeMap 节点ID到配置的映射表
* @param context 执行上下文
* @returns 创建的节点实例
*/
static createNodeFromJSONConfig(nodeConfig, nodeMap, context) {
let node;
const props = nodeConfig.properties || {};
// 根据节点类型创建对应的节点实例
switch (nodeConfig.type) {
// 根节点 - 通常是一个简单的传递节点
case 'root':
// 根节点本身不执行逻辑,直接处理第一个子节点
if (nodeConfig.children && nodeConfig.children.length > 0) {
const firstChildId = nodeConfig.children[0];
const firstChildConfig = nodeMap.get(firstChildId);
if (firstChildConfig) {
return BehaviorTreeBuilder.createNodeFromJSONConfig(firstChildConfig, nodeMap, context);
}
}
// 如果没有子节点,创建一个默认成功节点
node = new ExecuteAction(() => exports.TaskStatus.Success);
break;
// 复合节点
case 'selector':
const selectorAbortType = BehaviorTreeBuilder.getAbortType(String(props.abortType || 'None'));
node = new Selector(selectorAbortType);
break;
case 'sequence':
const sequenceAbortType = BehaviorTreeBuilder.getAbortType(String(props.abortType || 'None'));
node = new Sequence(sequenceAbortType);
break;
case 'parallel':
node = new Parallel();
break;
case 'parallel-selector':
node = new ParallelSelector();
break;
case 'random-selector':
node = new RandomSelector();
break;
case 'random-sequence':
node = new RandomSequence();
break;
// 装饰器节点
case 'repeater':
const countProp = props.count;
const count = typeof countProp === 'number' ? countProp : -1; // -1 表示无限重复
node = new Repeater(count);
break;
case 'inverter':
node = new Inverter();
break;
case 'always-succeed':
node = new AlwaysSucceed();
break;
case 'always-fail':
node = new AlwaysFail();
break;
case 'until-success':
node = new UntilSuccess();
break;
case 'until-fail':
node = new UntilFail();
break;
case 'conditional-decorator':
// 创建条件装饰器 - 使用新的条件工厂
let conditionConfig = nodeConfig.condition;
// 根据conditionType属性确定条件类型
if (props.conditionType === 'blackboardCompare') {
conditionConfig = { type: 'blackboard-value-comparison' };
}
else if (props.conditionType === 'eventCondition') {
conditionConfig = { type: 'event-condition' };
}
else if (props.conditionType === 'custom') {
conditionConfig = { type: 'condition-custom' };
}
// 使用条件工厂创建条件
const conditionalNode = ConditionFactory.createCondition(conditionConfig, props, context);
const shouldReevaluateValue = BehaviorTreeBuilder.extractNestedValue(props.shouldReevaluate);
const shouldReevaluate = shouldReevaluateValue !== false && shouldReevaluateValue !== "false";
const abortType = BehaviorTreeBuilder.getAbortType(BehaviorTreeBuilder.extractNestedValue(props.abortType) || 'None');
node = new ConditionalDecorator(conditionalNode, shouldReevaluate, abortType);
break;
// 动作节点
case 'log-action':
const message = props.message || 'Default log message';
// 支持变量替换
node = new ExecuteAction((ctx) => {
const blackboard = ctx.blackboard;
let finalMessage = message;
// 简单的变量替换 {{variableName}}
if (blackboard && typeof message === 'string') {
finalMessage = message.replace(/\{\{(\w+)\}\}/g, (match, varName) => {
const value = blackboard.getValue(varName);
return value !== undefined ? String(value) : match;
});
}
console.log(`[BehaviorTree] ${finalMessage}`);
if (ctx.log) {
ctx.log(finalMessage, props.logLevel || 'info');
}
return exports.TaskStatus.Success;
});
break;
case 'wait-action':
const waitTimeProp = props.waitTime;
const waitTime = typeof waitTimeProp === 'number' ? waitTimeProp : 1.0;
node = new WaitAction(waitTime);
break;
case 'behavior-tree-reference':
const subTreePath = props.subTreePath || props.treePath;
if (subTreePath && typeof subTreePath === 'string') {
try {
// 这里需要从路径加载子行为树
// 在实际应用中,应该有一个行为树管理器来处理这个
console.warn(`behavior-tree-reference节点需要实现子行为树加载机制: ${subTreePath}`);
node = new ExecuteAction((ctx) => {
console.log(`执行子行为树引用: ${subTreePath}`);
return exports.TaskStatus.Success;
});
}
catch (error) {
console.error('加载子行为树失败:', error);
node = new ExecuteAction(() => exports.TaskStatus.Failure);
}
}
else {
console.warn('behavior-tree-reference节点缺少subTreePath属性');
node = new ExecuteAction(() => exports.TaskStatus.Failure);
}
break;
case 'execute-action':
const actionCode = props.actionCode;
if (actionCode && typeof actionCode === 'string') {
try {
// 创建安全的执行函数
const actionFunc = new Function('context', 'TaskStatus', `
const { Success, Failure, Running, Invalid } = TaskStatus;
try {
${actionCode}
} catch (error) {
console.error('动作执行错误:', error);
return TaskStatus.Failure;
}
`);
node = new ExecuteAction((ctx) => {
try {
const result = actionFunc(ctx, exports.TaskStatus);
return result || exports.TaskStatus.Success;
}
catch (error) {
console.error('执行动作失败:', error);
return exports.TaskStatus.Failure;
}
});
}
catch (error) {
console.warn('解析动作代码失败,使用默认动作:', error);
node = new ExecuteAction(() => exports.TaskStatus.Success);
}
}
else {
node = new ExecuteAction(() => exports.TaskStatus.Success);
}
break;
// 条件节点
case 'condition-random':
const probabilityProp = props.successProbability;
const probability = typeof probabilityProp === 'number' ? probabilityProp : 0.5;
node = new ExecuteActionConditional(() => {
return Math.random() < probability ? exports.TaskStatus.Success : exports.TaskStatus.Failure;
});
break;
case 'condition-custom':
const conditionCodeProp = props.conditionCode;
const conditionCode = typeof conditionCodeProp === 'string' ? conditionCodeProp :
(typeof conditionCodeProp === 'object' && conditionCodeProp && 'value' in conditionCodeProp ?
String(conditionCodeProp.value) : undefined);
if (conditionCode && typeof conditionCode === 'string') {
try {
const condFunc = new Function('context', `
try {
${conditionCode}
} catch (error) {
console.error('条件检查错误:', error);
return false;
}
`);
node = new ExecuteActionConditional((ctx) => {
try {
const result = condFunc(ctx);
return result ? exports.TaskStatus.Success : exports.TaskStatus.Failure;
}
catch (error) {
console.error('条件检查失败:', error);
return exports.TaskStatus.Failure;
}
});
}
catch (error) {
console.warn('解析条件代码失败:', error);
node = new ExecuteActionConditional(() => exports.TaskStatus.Failure);
}
}
else {
node = new ExecuteActionConditional(() => exports.TaskStatus.Success);
}
break;
case 'condition-numeric':
node = new ExecuteActionConditional((ctx) => {
const conditional = new NumericComparison(String(props.propertyPath || 'value'), String(props.compareOperator || 'equal'), Number(props.compareValue) || 0);
return conditional.update(ctx);
});
break;
case 'condition-property':
node = new ExecuteActionConditional((ctx) => {
const conditional = new PropertyExists(String(props.propertyPath || 'property'));
return conditional.update(ctx);
});
break;
// 事件驱动节点
case 'event-action':
const eventActionName = props.eventName;
if (eventActionName && typeof eventActionName === 'string') {
node = new ExecuteAction((ctx) => {
try {
// 从上下文中获取事件注册表
const eventRegistry = ctx.eventRegistry;
if (!eventRegistry) {
console.warn(`[event-action] 未找到事件注册表,请在执行上下文中提供 eventRegistry`);
return exports.TaskStatus.Failure;
}
// 获取事件处理器
const handler = eventRegistry.getActionHandler ?
eventRegistry.getActionHandler(eventActionName) :
eventRegistry.handlers?.get(eventActionName);
if (!handler) {
console.warn(`[event-action] 未找到事件处理器: ${eventActionName}`);
return exports.TaskStatus.Failure;
}
// 解析参数
let parameters = {};
if (props.parameters) {
if (typeof props.parameters === 'string') {
try {
parameters = JSON.parse(props.parameters);
}
catch (e) {
console.warn(`[event-action] 参数解析失败: ${props.parameters}`);
}
}
else {
parameters = props.parameters;
}
// 支持黑板变量替换
const blackboard = ctx.blackboard;
if (blackboard) {
parameters = BehaviorTreeBuilder.replaceBlackboardVariables(parameters, blackboard);
}
}
// 执行事件处理器
const result = handler(ctx, parameters);
// 处理异步结果
if (result instanceof Promise) {
if (props.async !== false) {
result.then((asyncResult) => {
console.log(`[event-action] 异步事件 ${eventActionName} 完成: ${asyncResult}`);
}).catch((error) => {
console.error(`[event-action] 异步事件 ${eventActionName} 失败:`, error);
});
return exports.TaskStatus.Running;
}
else {
console.warn(`[event-action] 事件 ${eventActionName} 返回Promise但未标记为异步,将阻塞执行`);
return exports.TaskStatus.Running;
}
}
// 处理同步结果
if (typeof result === 'string') {
switch (result.toLowerCase()) {
case 'success': return exports.TaskStatus.Success;
case 'failure': return exports.TaskStatus.Failure;
case 'running': return exports.TaskStatus.Running;
default: return exports.TaskStatus.Success;
}
}
return result === true ? exports.TaskStatus.Success :
result === false ? exports.TaskStatus.Failure : exports.TaskStatus.Success;
}
catch (error) {
console.error(`[event-action] 事件 ${eventActionName} 执行失败:`, error);
return exports.TaskStatus.Failure;
}
});
}
else {
console.warn('[event-action] 缺少 eventName 属性');
node = new ExecuteAction(() => exports.TaskStatus.Failure);
}
break;
case 'event-condition':
const eventConditionName = props.eventName;
if (eventConditionName && typeof eventConditionName === 'string') {
node = new ExecuteActionConditional((ctx) => {
try {
// 从上下文中获取事件注册表
const eventRegistry = ctx.eventRegistry;
if (!eventRegistry) {
console.warn(`[event-condition] 未找到事件注册表,请在执行上下文中提供 eventRegistry`);
return exports.TaskStatus.Failure;
}
// 获取条件处理器
const checker = eventRegistry.getConditionHandler ?
eventRegistry.getConditionHandler(eventConditionName) :
eventRegistry.handlers?.get(eventConditionName);
if (!checker) {
console.warn(`[event-condition] 未找到条件处理器: ${eventConditionName}`);
return exports.TaskStatus.Failure;
}
// 解析参数
let parameters = {};
if (props.parameters) {
if (typeof props.parameters === 'string') {
try {
parameters = JSON.parse(props.parameters);
}
catch (e) {
console.warn(`[event-condition] 参数解析失败: ${props.parameters}`);
}
}
else {
parameters = props.parameters;
}
// 支持黑板变量替换
const blackboard = ctx.blackboard;
if (blackboard) {
parameters = BehaviorTreeBuilder.replaceBlackboardVariables(parameters, blackboard);
}
}
// 执行条件检查
const result = checker(ctx, parameters);
// 处理异步结果
if (result instanceof Promise) {
console.warn(`[event-condition] 条件 ${eventConditionName} 返回Promise,条件节点不支持异步操作`);
return exports.TaskStatus.Failure;
}
return result ? exports.TaskStatus.Success : exports.TaskStatus.Failure;
}
catch (error) {
console.error(`[event-condition] 条件 ${eventConditionName} 检查失败:`, error);
return exports.TaskStatus.Failure;
}
});
}
else {
console.warn('[event-condition] 缺少 eventName 属性');
node = new ExecuteActionConditional(() => exports.TaskStatus.Failure);
}
break;
// ========== 黑板动作节点 ==========
case 'set-blackboard-value':
const rawVariableName = String(props.variableName || 'variable');
// 清理变量名,移除黑板变量引用语法 {{variableName}}
const setVariableName = rawVariableName.replace(/^\{\{|\}\}$/g, '');
const setValue = props.value;
const setSourceVariable = props.sourceVariable ? String(props.sourceVariable).replace(/^\{\{|\}\}$/g, '') : undefined;
const setForce = props.force === true;
node = new SetBlackboardValue(setVariableName, setValue, setSourceVariable, setForce);
break;
case 'add-to-blackboard':
case 'add-blackboard-value':
node = new AddToBlackboardValue(String(props.variableName || 'variable'), Number(props.increment) || 1, props.incrementVariable ? String(props.incrementVariable) : undefined);
break;
case 'toggle-blackboard-bool':
node = new ToggleBlackboardBool(String(props.variableName || 'variable'));
break;
case 'reset-blackboard-variable':
node = new ResetBlackboardVariable(String(props.variableName || 'variable'));
break;
case 'math-blackboard-operation':
const mathOperation = String(props.operation || 'add');
const mathOperand2Value = typeof props.operand2 === 'string' ? props.operand2 : Number(props.operand2 || 0);
node = new MathBlackboardOperation(String(props.targetVariable || 'result'), String(props.operand1Variable || 'operand1'), mathOperand2Value, MathOperation[mathOperation] || MathOperation.Add);
break;
case 'log-blackboard-value':
node = new LogBlackboardValue(String(props.variableName || 'variable'), String(props.prefix || '[Blackboard]'));
break;
case 'wait-blackboard-condition':
const waitVarName = String(props.variableName || 'variable');
const expectedValue = props.expectedValue;
node = new WaitForBlackboardCondition(waitVarName, expectedValue);
break;
// ========== 黑板条件节点 ==========
case 'blackboard-value-comparison':
const operatorStr = String(props.operator || props.compareOperator || 'equal');
// 映射操作符字符串到枚举
let operator;
switch (operatorStr.toLowerCase()) {
case 'equal':
operator = CompareOperator.Equal;
break;
case 'notequal':
case 'not_equal':
operator = CompareOperator.NotEqual;
break;
case 'greater':
operator = CompareOperator.Greater;
break;
case 'greaterorequal':
case 'greater_or_equal':
operator = CompareOperator.GreaterOrEqual;
break;
case 'less':
operator = CompareOperator.Less;
break;
case 'lessorequal':
case 'less_or_equal':
operator = CompareOperator.LessOrEqual;
break;
case 'contains':
operator = CompareOperator.Contains;
break;
case 'notcontains':
case 'not_contains':
operator = CompareOperator.NotContains;
break;
default:
operator = CompareOperator.Equal;
break;
}
node = new ExecuteActionConditional((ctx) => {
const conditional = new BlackboardValueComparison(String(props.variableName || 'variable'), operator, props.compareValue, props.compareVariable ? String(props.compareVariable) : undefined);
return conditional.update(ctx);
});
break;
case 'blackboard-variable-exists':
node = new ExecuteActionConditional((ctx) => {
const conditional = new BlackboardVariableExists(String(props.variableName || 'variable'), props.invert === true);
return conditional.update(ctx);
});
break;
case 'blackboard-variable-type-check':
const expectedTypeStr = String(props.expectedType || 'string');
// 映射类型字符串到枚举
const expectedType = BehaviorTreeBuilder.mapToBlackboardType(expectedTypeStr);
node = new ExecuteActionConditional((ctx) => {
const conditional = new BlackboardVariableTypeCheck(String(props.variableName || 'variable'), expectedType);
return conditional.update(ctx);
});
break;
case 'blackboard-variable-range-check':
node = new ExecuteActionConditional((ctx) => {
const conditional = new BlackboardVariableRangeCheck(String(props.variableName || 'variable'), Number(props.minValue) || 0, Number(props.maxValue) || 100);
return conditional.update(ctx);
});
break;
// ========== 通用条件节点 ==========
case 'numeric-comparison':
node = new ExecuteActionConditional((ctx) => {
const conditional = new NumericComparison(String(props.propertyPath || 'value'), String(props.compareOperator || 'equal'), Number(props.compareValue) || 0);
return conditional.update(ctx);
});
break;
case 'property-exists':
node = new ExecuteActionConditional((ctx) => {
const conditional = new PropertyExists(String(props.propertyPath || 'property'));
return conditional.update(ctx);
});
break;
// ========== 高级装饰器节点 ==========
case 'cooldown':
const cooldownTime = Number(props.cooldownTime) || 1.0;
node = new CooldownDecorator(cooldownTime);
break;
case 'timeout':
const timeoutDuration = Number(props.timeoutDuration) || 5.0;
node = new TimeoutDecorator(timeoutDuration);
break;
case 'chance':
const successChance = Number(props.successChance) || 0.5;
node = new ChanceDecorator(successChance);
break;
default:
console.warn('⚠️ 未知的节点类型:', nodeConfig.type, ',使用默认成功节点');
node = new ExecuteAction(() => exports.TaskStatus.Success);
break;
}
// 为复合节点和装饰器添加子节点
if (nodeConfig.children && nodeConfig.children.length > 0) {
if (node instanceof Composite) {
// 复合节点可以有多个子节点
for (const childId of nodeConfig.children) {
const childConfig = nodeMap.get(childId);
if (childConfig) {
const childNode = BehaviorTreeBuilder.createNodeFromJSONConfig(childConfig, nodeMap, context);
node.addChild(childNode);
}
else {
console.warn(`⚠️ 未找到子节点配置: ${childId}`);
}
}
}
else if (node instanceof Decorator) {
// 装饰器只能有一个子节点
if (nodeConfig.children.length > 1) {
console.warn('⚠️ 装饰器节点只能有一个子节点,将使用第一个');
}
const childId = nodeConfig.children[0];
const childConfig = nodeMap.get(childId);
if (childConfig) {
const childNode = BehaviorTreeBuilder.createNodeFromJSONConfig(childConfig, nodeMap, context);
node.child = childNode;
}
else {
console.warn(`⚠️ 未找到子节点配置: ${childId}`);
}
}
}
return node;
}
/**
* 创建条件函数
* @param condition 条件配置
* @param context 执行上下文
* @returns 条件检查函数
*/
static createConditionFunction(condition, context) {
if (!condition) {
return () => exports.TaskStatus.Success;
}
if (condition.type === 'condition-custom') {
const conditionCodeConfig = condition.properties?.conditionCode;
const conditionCode = typeof conditionCodeConfig === 'string' ? conditionCodeConfig :
(typeof conditionCodeConfig === 'object' && conditionCodeConfig && 'value' in conditionCodeConfig ?
String(conditionCodeConfig.value) : undefined);
if (conditionCode && typeof conditionCode === 'string') {
try {
const condFunc = new Function('context', `
try {
return (${conditionCode})(context);
} catch (error) {
console.error('条件函数执行错误:', error);
return false;
}
`);
return (ctx) => {
try {
const result = condFunc(ctx);
return result ? exports.TaskStatus.Success : exports.TaskStatus.Failure;
}
catch (error) {
console.error('条件函数执行失败:', error);
return exports.TaskStatus.Failure;
}
};
}
catch (error) {
console.warn('解析条件函数失败:', error);
}
}
}
return () => exports.TaskStatus.Success;
}
/**
* 替换对象中的黑板变量引用
* @param obj 要处理的对象
* @param blackboard 黑板实例
* @returns 替换后的对象
*/
static replaceBlackboardVariables(obj, blackboard) {
if (obj === null || obj === undefined) {
return obj;
}
if (typeof obj === 'string') {
// 检查是否是纯黑板变量引用(如 "{{variableName}}")
const pureVariableMatch = obj.match(/^{{\s*(\w+)\s*}}$/);
if (pureVariableMatch) {
// 纯变量引用,返回原始类型的值
const varName = pureVariableMatch[1];
const value = blackboard.getValue(varName);
if (value !== undefined) {
return value; // 保持原始类型
}
return obj; // 变量不存在,返回原字符串
}
// 包含变量的字符串模板,进行字符串替换
return obj.replace(/\{\{(\w+)\}\}/g, (match, varName) => {
const value = blackboard.getValue(varName);
return value !== undefined ? String(value) : match;
});
}
if (Array.isArray(obj)) {
// 处理数组
return obj.map(item => BehaviorTreeBuilder.replaceBlackboardVariables(item, blackboard));
}
if (typeof obj === 'object') {
// 处理对象
const result = {};
for (const [key, value] of Object.entries(obj)) {
result[key] = BehaviorTreeBuilder.replaceBlackboardVariables(value, blackboard);
}
return result;
}
return obj;
}
/**
* 提取嵌套属性值
* @param prop 属性配置对象或直接值
* @returns 提取的值
*/
static extractNestedValue(prop) {
if (prop === null || prop === undefined) {
return prop;
}
// 如果是简单值,直接返回
if (typeof prop !== 'object') {
return prop;
}
// 如果有value属性,递归提取
if ('value' in prop) {
return BehaviorTreeBuilder.extractNestedValue(prop.value);
}
return prop;
}
}
/**
* 通用对象池,用于减少对象创建和销毁的开销
*
* @template T 池中对象的类型
*
* @example
* ```typescript
* // 创建一个ExecuteAction的对象池
* const actionPool = new ObjectPool(
* () => new ExecuteAction(() => TaskStatus.Success),
* (action) => action.invalidate(),
* 50 // 最大池大小
* );
*
* // 获取对象
* const action = actionPool.get();
*
* // 使用完毕后归还
* actionPool.release(action);
* ```
*/
class ObjectPool {
/**
* 创建对象池
* @param createFn 创建新对象的函数
* @param resetFn 重置对象状态的函数(可选)
* @param maxSize 池的最大大小,必须大于0,默认100
* @throws {Error} 当maxSize小于等于0时抛出错误
*/
constructor(createFn, resetFn, maxSize = 100) {
this._pool = [];
if (maxSize <= 0) {
throw new Error('池的最大大小必须大于0');
}
if (typeof createFn !== 'function') {
throw new Error('createFn必须是一个函数');
}
this._createFn = createFn;
this._resetFn = resetFn;
this._maxSize = maxSize;
}
/**
* 从池中获取一个对象
* 如果池为空,则创建新对象
* @returns 池中的对象或新创建的对象
*/
get() {
if (this._pool.length > 0) {
return this._pool.pop();
}
return this._createFn();
}
/**
* 将对象归还到池中
* @param obj 要归还的对象
* @throws {Error} 当obj为null或undefined时抛出错误
*/
release(obj) {
if (obj == null) {
throw new Error('不能归还null或undefined对象到池中');
}
// 检查是否已经在池中(避免重复归还)
if (this._pool.includes(obj)) {
console.warn('对象已经在池中,忽略重复归还');
return;
}
if (this._pool.length < this._maxSize) {
// 重置对象状态
if (this._resetFn) {
try {
this._resetFn(obj);
}
catch (error) {
console.error('重置对象时发生错误:', error);
// 即使重置失败,也不将对象放回池中
return;
}
}
this._pool.push(obj);
}
// 如果池已满,对象会被丢弃,由GC回收
}
/**
* 预填充池
* @param count 要预创建的对象数量,必须大于等于0
* @throws {Error} 当count小于0时抛出错误
*/
prewarm(count) {
if (count < 0) {
throw new Error('预填充数量不能小于0');
}
const actualCount = Math.min(count, this._maxSize - this._pool.length);
for (let i = 0; i < actualCount; i++) {
try {
this._pool.push(this._createFn());
}
catch (error) {
console.error('预填充对象时发生错误:', error);
break; // 停止预填充
}
}
}
/**
* 清空池
*/
clear() {
this._pool.length = 0;
}
/**
* 获取池的当前大小
*/
get size() {
return this._pool.length;
}
/**
* 获取池的最大大小
*/
get maxSize() {
return this._maxSize;
}
/**
* 设置池的最大大小
* @param value 新的最大大小,必须大于0
* @throws {Error} 当value小于等于0时抛出错误
*/
set maxSize(value) {
if (value <= 0) {
throw new Error('池的最大大小必须大于0');
}
this._maxSize = value;
// 如果当前池大小超过新的最大值,移除多余的对象
while (this._pool.length > this._maxSize) {
this._pool.pop();
}
}
/**
* 获取池的使用率(0-1之间)
* @returns 当前大小与最大大小的比率
*/
get utilization() {
return this._pool.length / this._maxSize;
}
/**
* 检查池是否为空
*/
get isEmpty() {
return this._pool.length === 0;
}
/**
* 检查池是否已满
*/
get isFull() {
return this._pool.length >= this._maxSize;
}
}
/**
* 行为树节点池管理器
* 为常用的行为树节点类型提供专门的对象池
*
* @example
* ```typescript
* const poolManager = BehaviorNodePoolManager.getInstance();
*
* // 注册节点池
* poolManager.registerPool('ExecuteAction',
* () => new ExecuteAction(() => TaskStatus.Success),
* (action) => action.invalidate()
* );
*
* // 获取和归还对象
* const action = poolManager.get<ExecuteAction>('ExecuteAction');
* poolManager.release('ExecuteAction', action);
* ```
*/
class BehaviorNodePoolManager {
constructor() {
this._pools = new Map();
}
/**
* 获取单例实例
*/
static getInstance() {
if (!this._instance) {
this._instance = new BehaviorNodePoolManager();
}
return this._instance;
}
/**
* 注册一个节点类型的对象池
* @param typeName 节点类型名称,不能为空字符串
* @param createFn 创建函数
* @param resetFn 重置函数
* @param maxSize 最大池大小,默认50
* @throws {Error} 当typeName为空或已存在时抛出错误
*/
registerPool(typeName, createFn, resetFn, maxSize = 50) {
if (!typeName || typeName.trim() === '') {
throw new Error('节点类型名称不能为空');
}
if (this._pools.has(typeName)) {
throw new Error(`节点类型 "${typeName}" 的池已经存在`);
}
const pool = new ObjectPool(createFn, resetFn, maxSize);
this._pools.set(typeName, pool);
}
/**
* 从指定类型的池中获取对象
* @param typeName 节点类型名称
* @returns 池中的对象,如果池不存在则返回null
*/
get(typeName) {
const pool = this._pools.get(typeName);
return pool ? pool.get() : null;
}
/**
* 将对象归还到对应的池中
* @param typeName 节点类型名称
* @param obj 要归还的对象
* @returns 是否成功归还
*/
release(typeName, obj) {
const pool = this._pools.get(typeName);
if (pool && obj != null) {
try {
pool.release(obj);
return true;
}
catch (error) {
console.error(`归还对象到池 "${typeName}" 时发生错误:`, error);
return false;
}
}
return false;
}
/**
* 预热所有池
* @param count 每个池预创建的对象数量,默认10
*/
prewarmAll(count = 10) {
for (const [typeName, pool] of this._pools.entries()) {
try {
pool.prewarm(count);
}
catch (error) {
console.error(`预热池 "${typeName}" 时发生错误:`, error);
}
}
}
/**
* 清空所有池
*/
clearAll() {
for (const pool of this._pools.values()) {
pool.clear();
}
}
/**
* 移除指定类型的池
* @param typeName 节点类型名称
* @returns 是否成功移除
*/
removePool(typeName) {
const pool = this._pools.get(typeName);
if (pool) {
pool.clear();
this._pools.delete(typeName);
return true;
}
return false;
}
/**
* 获取池的统计信息
* @returns 包含所有池统计信息的对象
*/
getStats() {
const stats = {};
for (const [typeName, pool] of this._pools.entries()) {
stats[typeName] = {
size: pool.size,
maxSize: pool.maxSize,
utilization: pool.utilization
};
}
return stats;
}
/**
* 获取已注册的池类型列表
*/
getRegisteredTypes() {
return Array.from(this._pools.keys());
}
}
/**
* 高性能分层对象池系统
*
* @description
* 提供比原始ObjectPool更高性能的对象池实现:
* - 使用WeakSet跟踪池中对象,避免includes()开销
* - 实现分层池,根据使用频率分配不同大小的池
* - 支持全局内存限制和自动清理
* - 提供详细的性能统计
*
* @template T 池中对象的类型
*/
/**
* 池优先级枚举
*/
var PoolPriority;
(function (PoolPriority) {
/** 低优先级 - 优先清理 */
PoolPriority[PoolPriority["Low"] = 0] = "Low";
/** 普通优先级 */
PoolPriority[PoolPriority["Normal"] = 1] = "Normal";
/** 高优先级 - 最后清理 */
PoolPriority[PoolPriority["High"] = 2] = "High";
/** 关键优先级 - 不会被自动清理 */
PoolPriority[PoolPriority["Critical"] = 3] = "Critical";
})(PoolPriority || (PoolPriority = {}));
/**
* 高性能对象池
*/
class AdvancedObjectPool {
/**
* 创建高性能对象池
* @param createFn 创建新对象的函数
* @param resetFn 重置对象状态的函数(可选)
* @param config 池配置选项
*/
constructor(createFn, resetFn, config = {}) {
this._pool = [];
this._poolSet = new WeakSet();
// 性能优化
this._lastCleanupTime = 0;
this._cleanupInterval = 5000; // 5秒清理一次
if (typeof createFn !== 'function') {
throw new Error('createFn必须是一个函数');
}
this._createFn = createFn;
this._resetFn = resetFn;
this._validator = config.validator;
// 设置默认配置
this._config = {
initialSize: config.initialSize ?? 0,
maxSize: config.maxSize ?? 100,
priority: config.priority ?? PoolPriority.Normal,
enableStats: config.enableStats ?? true,
validator: config.validator
};
if (this._config.maxSize <= 0) {
throw new Error('最大池大小必须大于0');
}
// 初始化统计信息
this._stats = {
currentSize: 0,
maxSize: this._config.maxSize,
totalGets: 0,
totalReleases: 0,
totalCreations: 0,
hitRate: 0,
utilization: 0,
priority: this._config.priority
};
// 预填充池
if (this._config.initialSize > 0) {
this.prewarm(this._config.initialSize);
}
// 注册到全局池管理器
AdvancedPoolManager.registerPool(this);
}
/**
* 从池中获取一个对象
* @returns 池中的对象或新创建的对象
*/
get() {
this._updateStats('get');
// 尝试从池中获取
if (this._pool.length > 0) {
const obj = this._pool.pop();
this._poolSet.delete(obj);
this._updateStats('hit');
return obj;
}
// 池为空,创建新对象
const newObj = this._createObject();
this._updateStats('creation');
return newObj;
}
/**
* 将对象归还到池中
* @param obj 要归还的对象
* @returns 是否成功归还
*/
release(obj) {
if (obj == null) {
console.warn('不能归还null或undefined对象到池中');
return false;
}
// 检查对象是否已在池中
if (this._poolSet.has(obj)) {
console.warn('对象已经在池中,忽略重复归还');
return false;
}
// 验证对象
if (this._validator && !this._validator(obj)) {
console.warn('对象验证失败,拒绝归还到池中');
return false;
}
// 检查池是否已满
if (this._pool.length >= this._config.maxSize) {
return false; // 池已满,对象将被GC回收
}
// 重置对象状态
if (this._resetFn) {
try {
this._resetFn(obj);
}
catch (error) {
console.error('重置对象时发生错误:', error);
return false;
}
}
// 归还到池中
this._pool.push(obj);
this._poolSet.add(obj);
this._updateStats('release');
return true;
}
/**
* 创建新对象
*/
_createObject() {
try {
return this._createFn();
}
catch (error) {
console.error('创建对象时发生错误:', error);
throw error;
}
}
/**
* 更新统计信息
*/
_updateStats(operation) {
if (!this._config.enableStats) {
return;
}
switch (operation) {
case 'get':
this._stats.totalGets++;
break;
case 'release':
this._stats.totalReleases++;
break;
case 'creation':
this._stats.totalCreations++;
break;
}
// 更新派生统计信息
this._stats.currentSize = this._pool.length;
this._stats.hitRate = this._stats.totalGets > 0 ?
(this._stats.totalGets - this._stats.totalCreations) / this._stats.totalGets : 0;
this._stats.utilization = this._stats.currentSize / this._stats.maxSize;
}
/**
* 预填充池
* @param count 要预创建的对象数量
*/
prewarm(count) {
if (count < 0) {
throw new Error('预填充数量不能小于0');
}
const actualCount = Math.min(count, this._config.maxSize - this._pool.length);
for (let i = 0; i < actualCount; i++) {
try {
const obj = this._createObject();
this._pool.push(obj);
this._poolSet.add(obj);
this._updateStats('creation');
}
catch (error) {
console.error('预填充对象时发生错误:', error);
break;
}
}
}
/**
* 清空池
* @param force 是否强制清空(忽略优先级)
*/
clear(force = false) {
if (!force && this._config.priority === PoolPriority.Critical) {
return; // 关键优先级的池不会被清空
}
this._pool.length = 0;
// WeakSet会自动清理
this._updateStats('release'); // 更新统计信息
}
/**
* 收缩池到指定大小
* @param targetSize 目标大小
*/
shrink(targetSize) {
if (targetSize < 0) {
targetSize = 0;
}
while (this._pool.length > targetSize) {
const obj = this._pool.pop();
if (obj) {
this._poolSet.delete(obj);
}
}
this._updateStats('release');
}
/**
* 执行定期清理
*/
performMaintenance() {
const now = Date.now();
if (now - this._lastCleanupTime < this._cleanupInterval) {
return;
}
this._lastCleanupTime = now;
// 根据使用率决定是否收缩池
if (this._stats.utilization < 0.3 && this._pool.length > this._config.initialSize) {
const targetSize = Math.max(this._config.initialSize, Math.floor(this._pool.length * 0.7));
this.shrink(targetSize);
}
}
/**
* 获取池的当前大小
*/
get size() {
return this._pool.length;
}
/**
* 获取池的最大大小
*/
get maxSize() {
return this._config.maxSize;
}
/**
* 获取池的优先级
*/
get priority() {
return this._config.priority;
}
/**
* 设置池的最大大小
*/
set maxSize(value) {
if (value <= 0) {
throw new Error('最大池大小必须大于0');
}
this._config.maxSize = value;
this._stats.maxSize = value;
// 如果当前池大小超过新的最大值,收缩池
if (this._pool.length > value) {
this.shrink(value);
}
}
/**
* 获取池的统计信息
*/
getStats() {
this._updateStats('get'); // 更新当前统计信息
return { ...this._stats };
}
/**
* 重置统计信息
*/
resetStats() {
this._stats.totalGets = 0;
this._stats.totalReleases = 0;
this._stats.totalCreations = 0;
this._stats.hitRate = 0;
}
/**
* 检查池是否为空
*/
get isEmpty() {
return this._pool.length === 0;
}
/**
* 检查池是否已满
*/
get isFull() {
return this._pool.length >= this._config.maxSize;
}
}
/**
* 全局高级池管理器
*/
class AdvancedPoolManager {
/**
* 注册池到全局管理器
*/
static registerPool(pool) {
this._pools.add(pool);
}
/**
* 从全局管理器注销池
*/
static unregisterPool(pool) {
this._pools.delete(pool);
}
/**
* 执行全局内存清理
*/
static performGlobalCleanup() {
// 按优先级排序池(低优先级先清理)
const sortedPools = Array.from(this._pools).sort((a, b) => a.priority - b.priority);
for (const pool of sortedPools) {
if (pool.priority === PoolPriority.Critical) {
continue; // 跳过关键优先级的池
}
// 收缩池到初始大小的一半
const targetSize = Math.floor(pool.size * 0.5);
pool.shrink(targetSize);
}
}
/**
* 执行全局维护
*/
static performGlobalMaintenance() {
const now = Date.now();
if (now - this._lastMaintenanceTime < this._maintenanceInterval) {
return;
}
this._lastMaintenanceTime = now;
// 对所有池执行维护
for (const pool of this._pools) {
pool.performMaintenance();
}
// 检查是否需要全局清理
const totalPools = this._pools.size;
if (totalPools > 50) { // 如果池数量过多,执行清理
this.performGlobalCleanup();
}
}
/**
* 获取全局统计信息
*/
static getGlobalStats() {
let totalObjects = 0;
const poolsByPriority = {
[PoolPriority.Low]: 0,
[PoolPriority.Normal]: 0,
[PoolPriority.High]: 0,
[PoolPriority.Critical]: 0
};
for (const pool of this._pools) {
totalObjects += pool.size;
poolsByPriority[pool.priority]++;
}
return {
totalPools: this._pools.size,
totalObjects,
totalMemoryUsage: totalObjects * 64, // 估算内存使用(每个对象64字节)
poolsByPriority
};
}
/**
* 清理所有池
*/
static clearAllPools(force = false) {
for (const pool of this._pools) {
pool.clear(force);
}
}
}
AdvancedPoolManager._pools = new Set();
AdvancedPoolManager._maintenanceInterval = 10000; // 10秒
AdvancedPoolManager._lastMaintenanceTime = 0;
/**
* 当随机概率高于successProbability概率时返回成功。
* 否则它将返回失败。
* successProbability应该在0和1之间
*/
class RandomProbability extends Behavior {
constructor(successProbability) {
super();
this.discriminator = "IConditional";
this._successProbability = successProbability;
}
update(_context) {
if (Math.random() > this._successProbability)
return exports.TaskStatus.Success;
return exports.TaskStatus.Failure;
}
}
/**
* 事件注册表类
* 管理行为树中的动作和条件事件处理器
* 支持精确匹配和正则表达式匹配
*
* @example
* ```typescript
* // 定义自定义上下文类型
* interface GameContext extends IBehaviorTreeContext {
* player: Player;
* enemies: Enemy[];
* }
*
* // 定义参数类型
* interface MoveParams {
* targetX: number;
* targetY: number;
* speed?: number;
* }
*
* const registry = new EventRegistry();
*
* // 注册精确匹配的动作处理器
* registry.registerAction<GameContext, MoveParams>(
* 'move-to',
* (context, params) => {
* context.player.moveTo(params.targetX, params.targetY, params.speed || 1);
* return 'success';
* }
* );
*
* // 注册正则表达式动作处理器 - 匹配所有以 "enemy." 开头的事件
* registry.registerActionRegex<GameContext>(
* /^enemy\..+$/,
* (context, params) => {
* // 处理所有敌人相关的动作:enemy.attack, enemy.move, enemy.die 等
* console.log('处理敌人动作:', params);
* return 'success';
* }
* );
*
* // 注册正则表达式条件检查器 - 匹配所有以 "player." 开头的条件
* registry.registerConditionRegex<GameContext>(
* /^player\..+$/,
* (context, params) => {
* // 处理所有玩家相关的条件:player.alive, player.hasItem, player.canMove 等
* return context.player.health > 0;
* }
* );
*
* // 异步动作示例
* registry.registerAction<GameContext>(
* 'async-action',
* async (context) => {
* await context.player.performComplexAction();
* return 'success';
* }
* );
* ```
*/
class EventRegistry {
constructor() {
this.actionHandlers = new Map();
this.conditionHandlers = new Map();
// 正则表达式处理器存储
this.regexActionHandlers = new Map();
this.regexConditionHandlers = new Map();
}
/**
* 注册动作处理器
* @template TContext 上下文类型
* @template TParams 参数类型
* @param eventName 事件名称
* @param handler 处理器函数,必须返回 ActionResult 类型
*/
registerAction(eventName, handler) {
this.actionHandlers.set(eventName, handler);
}
/**
* 注册正则表达式动作处理器
* @template TContext 上下文类型
* @template TParams 参数类型
* @param eventPattern 事件名称正则表达式
* @param handler 处理器函数,必须返回 ActionResult 类型
*/
registerActionRegex(eventPattern, handler) {
this.regexActionHandlers.set(eventPattern, handler);
}
/**
* 注册条件检查器
* @template TContext 上下文类型
* @template TParams 参数类型
* @param eventName 事件名称
* @param checker 检查器函数,必须返回 boolean 类型
*/
registerCondition(eventName, checker) {
this.conditionHandlers.set(eventName, checker);
}
/**
* 注册正则表达式条件检查器
* @template TContext 上下文类型
* @template TParams 参数类型
* @param eventPattern 事件名称正则表达式
* @param checker 检查器函数,必须返回 boolean 类型
*/
registerConditionRegex(eventPattern, checker) {
this.regexConditionHandlers.set(eventPattern, checker);
}
/**
* 获取动作处理器
* @param eventName 事件名称
* @returns 处理器函数或undefined
*/
getActionHandler(eventName) {
const exactMatch = this.actionHandlers.get(eventName);
if (exactMatch) {
return exactMatch;
}
for (const [pattern, handler] of this.regexActionHandlers) {
if (pattern.test(eventName)) {
return handler;
}
}
return undefined;
}
/**
* 获取条件检查器
* @param eventName 事件名称
* @returns 检查器函数或undefined
*/
getConditionHandler(eventName) {
const exactMatch = this.conditionHandlers.get(eventName);
if (exactMatch) {
return exactMatch;
}
for (const [pattern, handler] of this.regexConditionHandlers) {
if (pattern.test(eventName)) {
return handler;
}
}
return undefined;
}
getAllEventNames() {
const actionNames = Array.from(this.actionHandlers.keys());
const conditionNames = Array.from(this.conditionHandlers.keys());
return [...new Set([...actionNames, ...conditionNames])];
}
/**
* 获取所有正则表达式模式
* @returns 包含所有注册的正则表达式模式的数组
*/
getAllRegexPatterns() {
const actionPatterns = Array.from(this.regexActionHandlers.keys());
const conditionPatterns = Array.from(this.regexConditionHandlers.keys());
return [...new Set([...actionPatterns, ...conditionPatterns])];
}
/**
* 测试事件名是否匹配任何已注册的处理器(包括正则表达式)
* @param eventName 事件名称
* @returns 是否有匹配的处理器
*/
hasHandler(eventName) {
return this.getActionHandler(eventName) !== undefined ||
this.getConditionHandler(eventName) !== undefined;
}
clear() {
this.actionHandlers.clear();
this.conditionHandlers.clear();
this.regexActionHandlers.clear();
this.regexConditionHandlers.clear();
}
}
class GlobalEventRegistry {
static getInstance() {
if (!GlobalEventRegistry.instance) {
GlobalEventRegistry.instance = new EventRegistry();
}
return GlobalEventRegistry.instance;
}
}
GlobalEventRegistry.instance = null;
// BehaviourTree (行为树) 模块
// 适用于NPC AI、Boss战、宠物系统、任务系统等
// 核心类
var index$2 = /*#__PURE__*/Object.freeze({
__proto__: null,
AddToBlackboardValue: AddToBlackboardValue,
AdvancedObjectPool: AdvancedObjectPool,
AdvancedPoolManager: AdvancedPoolManager,
AlwaysFail: AlwaysFail,
AlwaysSucceed: AlwaysSucceed,
Behavior: Behavior,
BehaviorNodePoolManager: BehaviorNodePoolManager,
BehaviorTree: BehaviorTree,
BehaviorTreeBuilder: BehaviorTreeBuilder,
BehaviorTreeReference: BehaviorTreeReference,
Blackboard: Blackboard,
BlackboardValueComparison: BlackboardValueComparison,
get BlackboardValueType () { return exports.BlackboardValueType; },
BlackboardVariableExists: BlackboardVariableExists,
BlackboardVariableRangeCheck: BlackboardVariableRangeCheck,
BlackboardVariableTypeCheck: BlackboardVariableTypeCheck,
ChanceDecorator: ChanceDecorator,
get CompareOperator () { return CompareOperator; },
Composite: Composite,
ConditionalDecorator: ConditionalDecorator,
CooldownDecorator: CooldownDecorator,
Decorator: Decorator,
EventRegistry: EventRegistry,
ExecuteAction: ExecuteAction,
ExecuteActionConditional: ExecuteActionConditional,
GlobalEventRegistry: GlobalEventRegistry,
Inverter: Inverter,
LogAction: LogAction,
LogBlackboardValue: LogBlackboardValue,
MathBlackboardOperation: MathBlackboardOperation,
get MathOperation () { return MathOperation; },
ObjectPool: ObjectPool,
Parallel: Parallel,
ParallelSelector: ParallelSelector,
get PoolPriority () { return PoolPriority; },
RandomProbability: RandomProbability,
RandomSelector: RandomSelector,
RandomSequence: RandomSequence,
Repeater: Repeater,
ResetBlackboardVariable: ResetBlackboardVariable,
Selector: Selector,
Sequence: Sequence,
SetBlackboardValue: SetBlackboardValue,
get TaskStatus () { return exports.TaskStatus; },
TimeoutDecorator: TimeoutDecorator,
ToggleBlackboardBool: ToggleBlackboardBool,
UntilFail: UntilFail,
UntilSuccess: UntilSuccess,
WaitAction: WaitAction,
WaitForBlackboardCondition: WaitForBlackboardCondition,
isIConditional: isIConditional
});
class State {
setMachineAndContext(machine, context) {
this._machine = machine;
this._context = context;
this.onInitialized();
}
/**
* 在设置machine和context之后直接调用,允许状态执行任何所需的设置
*
* @memberof State
*/
onInitialized() { }
/**
* 当状态变为活动状态时调用
*
* @memberof State
*/
begin() { }
/**
* 在更新之前调用,允许状态最后一次机会改变状态
*
* @memberof State
*/
reason() { }
/**
* 此状态不再是活动状态时调用
*
* @memberof State
*/
end() { }
}
/**
* 状态机实现
*
* @description
* 基于"状态作为对象"模式的状态机实现。
* 每个状态使用单独的类,适合复杂的状态管理系统。
*
* @template T 上下文类型
*
* @example
* ```typescript
* interface GameContext {
* player: Player;
* enemies: Enemy[];
* }
*
* const context: GameContext = { ... };
* const machine = new StateMachine(context, new IdleState());
*
* machine.addState(new AttackState());
* machine.addState(new DefendState());
*
* // 在游戏循环中更新
* machine.update(deltaTime);
*
* // 切换状态
* machine.changeState(AttackState);
* ```
*/
class StateMachine {
/** 获取当前状态 */
get currentState() {
return this._currentState;
}
/**
* 创建状态机
* @param context 执行上下文
* @param initialState 初始状态实例
* @throws {Error} 当context或initialState为null时抛出错误
*/
constructor(context, initialState) {
/** 在当前状态中的经过时间(秒) */
this.elapsedTimeInState = 0;
/** 状态实例缓存 */
this._states = new Map();
if (context == null) {
throw new Error('上下文不能为null或undefined');
}
if (initialState == null) {
throw new Error('初始状态不能为null或undefined');
}
this._context = context;
this.addState(initialState);
this._currentState = initialState;
this._currentState.begin();
}
/**
* 将状态添加到状态机
* @param state 要添加的状态实例
* @throws {Error} 当state为null或已存在时抛出错误
*/
addState(state) {
if (state == null) {
throw new Error('状态不能为null或undefined');
}
const stateConstructor = state.constructor;
if (this._states.has(stateConstructor)) {
throw new Error(`状态 ${stateConstructor.name} 已经存在`);
}
state.setMachineAndContext(this, this._context);
this._states.set(stateConstructor, state);
}
/**
* 移除指定类型的状态
* @param stateType 状态构造函数
* @returns 是否成功移除
*/
removeState(stateType) {
if (this._currentState instanceof stateType) {
console.warn('无法移除当前正在使用的状态');
return false;
}
return this._states.delete(stateType);
}
/**
* 使用提供的时间差更新状态机
* @param deltaTime 时间差(秒)
* @throws {Error} 当deltaTime为负数或无效时抛出错误
*/
update(deltaTime) {
if (deltaTime < 0 || !isFinite(deltaTime)) {
throw new Error('deltaTime必须是非负的有限数');
}
this.elapsedTimeInState += deltaTime;
try {
this._currentState.reason();
this._currentState.update(deltaTime);
}
catch (error) {
console.error('更新状态时发生错误:', error);
}
}
/**
* 从状态机获取特定状态实例,而不改变当前状态
* @param stateType 状态构造函数
* @returns 状态实例,如果不存在则返回null
*/
getState(stateType) {
const state = this._states.get(stateType);
if (!state) {
console.error(`状态 ${stateType.name} 不存在。请确保已调用 addState 添加该状态。`);
return null;
}
return state;
}
/**
* 更改当前状态
* @param newStateType 新状态的构造函数
* @returns 新状态实例,如果切换失败则返回null
*/
changeState(newStateType) {
// 如果已经是目标状态,直接返回
if (this._currentState instanceof newStateType) {
return this._currentState;
}
const newState = this._states.get(newStateType);
if (!newState) {
console.error(`状态 ${newStateType.name} 不存在。请确保已调用 addState 添加该状态。`);
return null;
}
try {
// 结束当前状态
this._currentState.end();
// 切换到新状态
this.elapsedTimeInState = 0;
this.previousState = this._currentState;
this._currentState = newState;
this._currentState.begin();
// 触发状态改变回调
if (this.onStateChanged) {
this.onStateChanged();
}
return this._currentState;
}
catch (error) {
console.error('切换状态时发生错误:', error);
return null;
}
}
/**
* 强制切换到指定状态(即使是相同状态也会重新初始化)
* @param stateType 状态构造函数
* @returns 状态实例,如果切换失败则返回null
*/
forceChangeState(stateType) {
const state = this._states.get(stateType);
if (!state) {
console.error(`状态 ${stateType.name} 不存在。请确保已调用 addState 添加该状态。`);
return null;
}
try {
// 结束当前状态
this._currentState.end();
// 切换到新状态
this.elapsedTimeInState = 0;
this.previousState = this._currentState;
this._currentState = state;
this._currentState.begin();
// 触发状态改变回调
if (this.onStateChanged) {
this.onStateChanged();
}
return this._currentState;
}
catch (error) {
console.error('强制切换状态时发生错误:', error);
return null;
}
}
/**
* 检查当前是否为指定状态
* @param stateType 状态构造函数
* @returns 是否为指定状态
*/
isInState(stateType) {
return this._currentState instanceof stateType;
}
/**
* 获取所有已注册的状态类型
* @returns 状态构造函数数组
*/
getRegisteredStateTypes() {
return Array.from(this._states.keys());
}
/**
* 获取状态机的统计信息
* @returns 包含状态数量和当前状态信息的对象
*/
getStats() {
return {
stateCount: this._states.size,
currentStateName: this._currentState.constructor.name,
elapsedTimeInState: this.elapsedTimeInState,
previousStateName: this.previousState?.constructor.name
};
}
}
/**
* 状态方法缓存
* 存储状态的进入、更新和退出方法
*/
class StateMethodCache {
}
/**
* 简单状态机实现
*
* @description
* 基于枚举的简单状态机,通过约定的方法名来处理状态逻辑。
* 适合简单的状态管理场景,状态逻辑直接写在状态机类中。
*
* @template TEnum 状态枚举类型
*
* @example
* ```typescript
* enum PlayerState {
* Idle = "Idle",
* Running = "Running",
* Jumping = "Jumping"
* }
*
* class PlayerStateMachine extends SimpleStateMachine<PlayerState> {
* constructor() {
* super(PlayerState);
* this.initialState = PlayerState.Idle;
* }
*
* // 状态方法按照 "状态名_enter/tick/exit" 的约定命名
* Idle_enter() {
* console.log("进入空闲状态");
* }
*
* Idle_tick() {
* // 空闲状态逻辑
* }
*
* Idle_exit() {
* console.log("退出空闲状态");
* }
*
* Running_enter() {
* console.log("开始跑步");
* }
*
* Running_tick() {
* // 跑步状态逻辑
* }
*
* Running_exit() {
* console.log("停止跑步");
* }
* }
* ```
*/
class SimpleStateMachine {
/**
* 获取当前状态
*/
get currentState() {
return this._currentState;
}
/**
* 设置当前状态
* @param value 新状态
*/
set currentState(value) {
if (this._currentState === value) {
return;
}
this.previousState = this._currentState;
this._currentState = value;
// 退出前一个状态
if (this._stateMethods.exitState) {
try {
this._stateMethods.exitState.call(this);
}
catch (error) {
console.error('退出状态时发生错误:', error);
}
}
this.elapsedTimeInState = 0;
const newStateMethods = this._stateCache.get(this._currentState);
if (newStateMethods) {
this._stateMethods = newStateMethods;
}
else {
console.warn('状态的方法缓存不存在');
this._stateMethods = new StateMethodCache();
}
// 进入新状态
if (this._stateMethods.enterState) {
try {
this._stateMethods.enterState.call(this);
}
catch (error) {
console.error('进入状态时发生错误:', error);
}
}
}
/**
* 设置初始状态
* @param value 初始状态
*/
set initialState(value) {
this._currentState = value;
const stateMethods = this._stateCache.get(this._currentState);
if (stateMethods) {
this._stateMethods = stateMethods;
}
else {
console.warn('初始状态的方法缓存不存在');
this._stateMethods = new StateMethodCache();
}
if (this._stateMethods.enterState) {
try {
this._stateMethods.enterState.call(this);
}
catch (error) {
console.error('进入初始状态时发生错误:', error);
}
}
}
/**
* 创建简单状态机
* @param stateEnum 状态枚举对象
*/
constructor(stateEnum) {
/** 在当前状态中的经过时间 */
this.elapsedTimeInState = 0;
/** 状态方法缓存 */
this._stateCache = new Map();
/** 当前状态的方法缓存 */
this._stateMethods = new StateMethodCache();
this._stateCache = new Map();
// 遍历枚举值并配置状态方法
for (const enumKey in stateEnum) {
if (Object.prototype.hasOwnProperty.call(stateEnum, enumKey)) {
const enumValue = stateEnum[enumKey];
if (enumValue !== undefined) {
this.configureAndCacheState(enumKey, enumValue);
}
}
}
}
/**
* 配置并缓存状态方法
* @param stateName 状态名称
* @param stateEnum 状态枚举值
*/
configureAndCacheState(stateName, stateEnum) {
const state = new StateMethodCache();
// 使用类型安全的方法查找
const enterMethodName = stateName + '_enter';
const tickMethodName = stateName + '_tick';
const exitMethodName = stateName + '_exit';
// 检查方法是否存在并且是函数
if (this.hasMethod(enterMethodName)) {
state.enterState = this[enterMethodName].bind(this);
}
if (this.hasMethod(tickMethodName)) {
state.tick = this[tickMethodName].bind(this);
}
if (this.hasMethod(exitMethodName)) {
state.exitState = this[exitMethodName].bind(this);
}
this._stateCache.set(stateEnum, state);
}
/**
* 检查方法是否存在
* @param methodName 方法名
* @returns 方法是否存在且为函数
*/
hasMethod(methodName) {
return methodName in this && typeof this[methodName] === 'function';
}
/**
* 更新状态机
* @param deltaTime 时间差
*/
update(deltaTime) {
if (deltaTime < 0 || !isFinite(deltaTime)) {
console.warn('SimpleStateMachine: 无效的deltaTime值');
return;
}
this.elapsedTimeInState += deltaTime;
if (this._stateMethods.tick) {
try {
this._stateMethods.tick.call(this);
}
catch (error) {
console.error('更新状态时发生错误:', error);
}
}
}
/**
* 强制切换到指定状态
* @param newState 新状态
*/
changeState(newState) {
this.currentState = newState;
}
/**
* 检查当前是否为指定状态
* @param state 要检查的状态
* @returns 是否为指定状态
*/
isInState(state) {
return this._currentState === state;
}
/**
* 获取状态机统计信息
* @returns 统计信息对象
*/
getStats() {
return {
currentState: this._currentState,
previousState: this.previousState,
elapsedTimeInState: this.elapsedTimeInState,
registeredStatesCount: this._stateCache.size
};
}
}
// FSM (有限状态机) 模块
// 适用于游戏状态管理、角色状态、UI状态等
var index$1 = /*#__PURE__*/Object.freeze({
__proto__: null,
SimpleStateMachine: SimpleStateMachine,
State: State,
StateMachine: StateMachine
});
class UtilityAI {
constructor(context, rootSelector, updatePeriod = 0.2) {
this._rootReasoner = rootSelector;
this._context = context;
this.updatePeriod = this._elapsedTime = updatePeriod;
}
tick(deltaTime) {
this._elapsedTime -= deltaTime;
while (this._elapsedTime <= 0) {
this._elapsedTime += this.updatePeriod;
let action = this._rootReasoner.select(this._context);
if (action != null)
action.execute(this._context);
}
}
}
/**
* 总是返回一个固定的分数。 作为默认考虑,提供双重任务。
*/
class FixedScoreConsideration {
constructor(score = 1) {
this.score = score;
}
getScore(_context) {
return this.score;
}
}
/**
* UtilityAI的根节点推理器
*
* @description
* 推理器负责从多个考虑因素中选择最佳的行动方案。
* 它是效用AI系统的核心组件,通过评估各种考虑因素来做出决策。
*
* @template T 上下文类型
*
* @example
* ```typescript
* class MyReasoner extends Reasoner<GameContext> {
* protected selectBestConsideration(context: GameContext): IConsideration<GameContext> {
* // 实现选择逻辑
* return this._considerations[0];
* }
* }
*
* const reasoner = new MyReasoner();
* reasoner.addConsideration(new AttackConsideration());
* reasoner.addConsideration(new DefendConsideration());
*
* const action = reasoner.select(gameContext);
* if (action) {
* action.execute(gameContext);
* }
* ```
*/
class Reasoner {
constructor() {
/**
* 默认考虑因素,当没有其他考虑因素可用时使用
* 通常返回一个固定的低分数
*/
this.defaultConsideration = new FixedScoreConsideration();
/**
* 考虑因素列表
* 推理器将从这些考虑因素中选择最佳的一个
*/
this._considerations = new Array();
}
/**
* 选择并返回最佳行动
*
* @param context 决策上下文
* @returns 选中的行动,如果没有可用行动则返回null
*/
select(context) {
try {
const consideration = this.selectBestConsideration(context);
if (consideration != null) {
return consideration.action;
}
}
catch (error) {
console.error('选择最佳考虑因素时发生错误:', error);
}
return null;
}
/**
* 添加考虑因素到推理器
*
* @param consideration 要添加的考虑因素
* @returns 返回自身以支持链式调用
* @throws {Error} 当consideration为null或undefined时抛出错误
*/
addConsideration(consideration) {
if (consideration == null) {
throw new Error('考虑因素不能为null或undefined');
}
this._considerations.push(consideration);
return this;
}
/**
* 移除指定的考虑因素
*
* @param consideration 要移除的考虑因素
* @returns 是否成功移除
*/
removeConsideration(consideration) {
const index = this._considerations.indexOf(consideration);
if (index !== -1) {
this._considerations.splice(index, 1);
return true;
}
return false;
}
/**
* 清空所有考虑因素
*/
clearConsiderations() {
this._considerations.length = 0;
}
/**
* 获取考虑因素数量
*
* @returns 当前考虑因素的数量
*/
getConsiderationCount() {
return this._considerations.length;
}
/**
* 获取所有考虑因素的只读副本
*
* @returns 考虑因素数组的副本
*/
getConsiderations() {
return [...this._considerations];
}
/**
* 设置默认考虑因素
*
* @param defaultConsideration 新的默认考虑因素
* @returns 返回自身以支持链式调用
* @throws {Error} 当defaultConsideration为null或undefined时抛出错误
*/
setDefaultConsideration(defaultConsideration) {
if (defaultConsideration == null) {
throw new Error('默认考虑因素不能为null或undefined');
}
this.defaultConsideration = defaultConsideration;
return this;
}
/**
* 检查是否有可用的考虑因素
*
* @returns 是否有考虑因素可用
*/
hasConsiderations() {
return this._considerations.length > 0;
}
}
/**
* 选择高于默认考虑分数的第一个考虑因素
*
* @description
* 遍历所有考虑因素,返回第一个分数高于或等于默认分数的考虑因素。
* 如果没有找到合适的考虑因素,则返回默认考虑因素。
*
* @template T 上下文类型
*/
class FirstScoreReasoner extends Reasoner {
/**
* 选择最佳考虑因素
* @param context 决策上下文
* @returns 选中的考虑因素
*/
selectBestConsideration(context) {
const defaultScore = this.defaultConsideration.getScore(context);
for (let i = 0; i < this._considerations.length; i++) {
const consideration = this._considerations[i];
if (consideration && consideration.getScore(context) >= defaultScore) {
return consideration;
}
}
return this.defaultConsideration;
}
}
/**
* 选择评分最高的考虑因素
*
* @description
* 遍历所有考虑因素,找到评分最高的一个。
* 如果没有考虑因素的分数高于默认分数,则返回默认考虑因素。
*
* @template T 上下文类型
*/
class HighestScoreReasoner extends Reasoner {
/**
* 选择最佳考虑因素
* @param context 决策上下文
* @returns 选中的考虑因素
*/
selectBestConsideration(context) {
let highestScore = this.defaultConsideration.getScore(context);
let bestConsideration = null;
for (let i = 0; i < this._considerations.length; i++) {
const currentConsideration = this._considerations[i];
if (currentConsideration) {
const score = currentConsideration.getScore(context);
if (score > highestScore) {
highestScore = score;
bestConsideration = currentConsideration;
}
}
}
if (bestConsideration == null) {
return this.defaultConsideration;
}
return bestConsideration;
}
}
// UtilityAI (效用AI) 模块
// 适用于智能决策、资源分配、难度调节等
var index = /*#__PURE__*/Object.freeze({
__proto__: null,
FirstScoreReasoner: FirstScoreReasoner,
FixedScoreConsideration: FixedScoreConsideration,
HighestScoreReasoner: HighestScoreReasoner,
Reasoner: Reasoner,
UtilityAI: UtilityAI
});
exports.ArrayExt = ArrayExt;
exports.Assert = Assert;
exports.BehaviorTree = BehaviorTree;
exports.BehaviorTreeBuilder = BehaviorTreeBuilder;
exports.BehaviourTree = index$2;
exports.Blackboard = Blackboard;
exports.Deque = Deque;
exports.ErrorHandler = ErrorHandler;
exports.EventManager = EventManager;
exports.EventRegistry = EventRegistry;
exports.FSM = index$1;
exports.GlobalEventRegistry = GlobalEventRegistry;
exports.Logger = Logger;
exports.PrefixedLogger = PrefixedLogger;
exports.Random = Random;
exports.State = State;
exports.StateMachine = StateMachine;
exports.TimeManager = TimeManager;
exports.TypeGuards = TypeGuards;
exports.UtilityAI = index;
exports.UtilityAICore = UtilityAI;
exports.errorHandler = errorHandler;
//# sourceMappingURL=index.cjs.map