@esengine/ai
Version:
用于Laya、Cocos Creator等JavaScript游戏引擎的高性能AI系统库:行为树、实用AI和有限状态机
1,885 lines (1,879 loc) • 289 kB
JavaScript
/**
* @esengine/ai v2.0.30
* 高性能TypeScript AI系统库 - 行为树、实用AI和有限状态机
*
* @author yhh
* @license MIT
*/
/**
* 高性能伪随机数生成器
* 使用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;
/**
* 日志级别枚举
*/
var LogLevel;
(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";
})(LogLevel || (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(LogLevel.Debug, message, data);
}
/**
* 记录一般信息
* @param message 消息
* @param data 附加数据
*/
static info(message, data) {
this._log(LogLevel.Info, message, data);
}
/**
* 记录警告信息
* @param message 消息
* @param data 附加数据
*/
static warn(message, data) {
this._log(LogLevel.Warn, message, data);
}
/**
* 记录错误信息
* @param message 消息
* @param error 错误对象或附加数据
*/
static error(message, error) {
this._log(LogLevel.Error, message, error);
}
/**
* 内部日志记录方法
* @param level 日志级别
* @param message 消息
* @param data 附加数据
*/
static _log(level, message, data) {
// 检查日志级别
if (level < this._config.minLevel || this._config.minLevel === 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 === 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 === 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 LogLevel.Debug:
return console.debug || console.log;
case LogLevel.Info:
return console.info || console.log;
case LogLevel.Warn:
return console.warn || console.log;
case 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: 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 = {
[LogLevel.Debug]: 'DEBUG',
[LogLevel.Info]: 'INFO',
[LogLevel.Warn]: 'WARN',
[LogLevel.Error]: 'ERROR',
[LogLevel.None]: 'NONE'
};
/** 日志级别样式映射(用于浏览器控制台) */
Logger._levelStyles = {
[LogLevel.Debug]: 'color: #888',
[LogLevel.Info]: 'color: #007acc',
[LogLevel.Warn]: 'color: #ff8c00',
[LogLevel.Error]: 'color: #ff4444; font-weight: bold',
[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; // 第一帧时间差为0
}
else {
this._unscaledDeltaTime = currentSystemTime - this._lastTime;
this._lastTime = currentSystemTime; // 更新lastTime为当前系统时间
}
}
// 限制最大时间差,防止时间跳跃
this._unscaledDeltaTime = Math.min(this._unscaledDeltaTime, this._maxDeltaTime);
// 应用时间缩放
this._deltaTime = this._unscaledDeltaTime * this._timeScale;
// 更新当前时间
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._unscaledDeltaTime <= 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._timeScale = 1.0; // 重置时间缩放
this._maxDeltaTime = 0.1; // 重置最大时间差
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 = [];
/**
* 错误处理级别枚举
*/
var ErrorLevel;
(function (ErrorLevel) {
/** 开发模式 - 严格检查,抛出所有错误 */
ErrorLevel[ErrorLevel["Development"] = 0] = "Development";
/** 测试模式 - 记录错误但不中断执行 */
ErrorLevel[ErrorLevel["Testing"] = 1] = "Testing";
/** 生产模式 - 最小化错误处理,优先性能 */
ErrorLevel[ErrorLevel["Production"] = 2] = "Production";
/** 静默模式 - 完全禁用错误处理 */
ErrorLevel[ErrorLevel["Silent"] = 3] = "Silent";
})(ErrorLevel || (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 ErrorLevel.Development:
this._config.enableAssertions = true;
this._config.enableTypeChecking = true;
break;
case ErrorLevel.Testing:
this._config.enableAssertions = true;
this._config.enableTypeChecking = false;
break;
case ErrorLevel.Production:
this._config.enableAssertions = false;
this._config.enableTypeChecking = false;
break;
case 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 === 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 === 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 === 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 === 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 === 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 === 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 === 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 ErrorLevel.Development:
throw error; // 开发模式:抛出错误
case ErrorLevel.Testing:
console.error('错误:', error.message, context);
throw error; // 测试模式:记录并抛出
case ErrorLevel.Production:
console.warn('错误:', error.message);
throw error; // 生产模式:警告并抛出
}
throw error; // 默认行为
}
/**
* 发出警告
* @param message 警告消息
* @param context 上下文信息
*/
static warn(message, context) {
if (this._config.level === 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 ErrorLevel.Development:
case ErrorLevel.Testing:
console.warn('警告:', message, context);
break;
case 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: 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.cleanup(); // 尝试清理
if (this._stats.totalListeners >= this._config.maxListeners) {
throw new Error('无法添加更多事件监听器,已达到上限');
}
}
// 添加到监听器列表
if (!this._listeners.has(eventName)) {
this._listeners.set(eventName, []);
}
const listeners = this._