UNPKG

mm_os

Version:

MM_OS服务端架构,用于快速构建应用程序,支持网站建设、小程序后台、AI应用、物联网(IOT/AIOT)、游戏服务端等多种场景。

1,255 lines (1,125 loc) 33 kB
const { Drive } = require('mm_machine'); /** * 游戏循环管理器 - 通用增强版 * 支持各种游戏类型,提供灵活的更新策略和可扩展架构 */ class GameLoop extends Drive { static config = { type: 'general', systems: [], base: { max_fps: 60, min_fps: 20, adaptive: true, time_scale: 1.0, stop_on_error: false, name: 'GameLoop', tick_count: 0 }, tick_rates: { world: 30, physics: 60, anim: 30, ai: 10, network: 10, cleanup: 1, input: 60, ui: 30, default: 60 }, sync: { lockstep: false, rollback: false, interp: true, extrap: false, timeout: 5000, retry_count: 3 }, perf: { monitor: true, auto_adjust: true, budget: { world: 8, physics: 4, anim: 3, ai: 2 }, profile: false }, events: { priority: 3, queue_size: 1000, max_queue_size: 1000, immed_proc: false, max_per_frame: 100 }, phases: { pre_update: true, update: true, post_update: true, render: true, cleanup: true }, // 持久化配置 persist: { // 是否启用定时持久化 enabled: true, // 持久化间隔(秒) interval: 60, // 是否只保存脏数据 dirty_only: true }, // 空闲状态配置 idle: { // 是否启用空闲优化 enabled: true, // 空闲时目标帧率 fps: 5, // 进入空闲状态的空闲帧数阈值 threshold: 60, // 空闲计数器 counter: 0 } }; /** * 构造函数 * @param {object} config 配置参数 */ constructor(config = {}) { super({ ...GameLoop.config, ...config || {} }); this.current_tick = 0; // 持久化计数器 this._persist_counter = 0; this.last_frame_time = 0; // 初始化性能统计 this.perf_stats = { frame_times: [], update_times: {}, fps: 0, load: 0, phase_times: {} }; // 初始化内部对象 this._system = {}; // 事件队列 this._event_queue = {}; this._accrual = {}; this._deps = {}; this._hook = { pre_update: [], post_update: [], pre_render: [], post_render: [], pre_tick: [], post_tick: [] }; // 循环状态 this.loop_status = 'running'; } } /** * 获取模板目录 * @returns {string} 模板目录 */ GameLoop.prototype.getTplDir = function () { return __dirname; }; /** * 初始化核心 * @param {object} world 游戏世界 * @param {object} eventer 事件总线 * @param {object} logger 日志管理器 * @returns {void} */ GameLoop.prototype._initCore = async function (world, eventer, logger) { if (logger) { this.setLogger(logger); } if (eventer) { this.getEventer = function () { return eventer; }; } // 初始化依赖项 if (world) { this._world = world; this._system = world.system; } // 从配置中解构必要参数 let { type = 'general', sync = {}, phases = {} } = this.config; // 初始化事件队列 for (let i = 0; i < this.config.events.priority; i++) { this._event_queue[i] = []; } // 初始化性能记录 for (let phase of Object.keys(phases)) { this.perf_stats.phase_times[phase] = []; } // 根据游戏类型应用特定优化 this.applyTypeOpts(type, sync); }; /** * 游戏类型特定优化 * @param {string} type 游戏类型 * @param {object} sync_config 同步配置 * @returns {void} */ GameLoop.prototype.applyTypeOpts = function (type, sync_config) { // 保存原始配置用于重置 this.original_config = JSON.parse(JSON.stringify(this.config)); // 使用类型映射表处理不同的游戏类型 this._runType(type, sync_config); }; /** * 处理游戏类型优化 * @param {string} type 游戏类型 * @param {object} sync_config 同步配置 * @returns {void} */ GameLoop.prototype._runType = function (type, sync_config) { let map = { comp: () => this.setupComp(sync_config), mmorpg: () => this.setupMMORPG(), casual: () => this.setupCasual(), rts: () => this.setupRTS(sync_config), sim: () => this.setupSimu(), card: () => this.setupCard(sync_config), board: () => this.setupBoard(sync_config), sandbox: () => this.setupSandbox(), turn: () => this.setupTurnBased(), rhythm: () => this.setupRhythm(), general: () => this.setupGeneral() }; let handler = map[type]; if (handler) { handler(); } else { this.setupGeneral(); } }; /** * 设置棋牌游戏循环 * @param {object} sync_config 同步配置 * @returns {void} */ GameLoop.prototype.setupBoard = function (sync_config) { // 棋牌游戏:低频率、确定性更新 this.config.tick_rates.world = 10; this.config.tick_rates.physics = 10; this.fixed_time_step = 1 / 10; // 关闭非必要系统 this.config.tick_rates.anim = 5; // 棋牌游戏:支持锁步和回滚 if (sync_config.lockstep) { this.setupLockstep(); } // 棋牌游戏:支持回滚 if (sync_config.rollback) { this.setupRollback(); } // 开启确定性执行 this.determ = true; }; /** * 设置卡牌游戏循环 * @param {object} sync_config 同步配置 * @returns {void} */ GameLoop.prototype.setupCard = function (sync_config) { // 卡牌游戏:中等频率、确定性更新 this.config.tick_rates.world = 15; this.config.tick_rates.physics = 10; this.fixed_time_step = 1 / 15; // 关闭非必要系统 this.config.tick_rates.anim = 20; // 卡牌游戏通常只需要回滚同步 if (sync_config.rollback) { this.setupRollback(); } // 卡牌游戏特有:事件优先级调整 this.config.event_priority = true; // 开启确定性执行 this.determ = true; }; /** * 设置沙盒游戏循环 * @returns {void} */ GameLoop.prototype.setupSandbox = function () { // 沙盒游戏:支持高自由度和物理模拟 this.config.tick_rates.world = 30; this.config.tick_rates.physics = 60; this.config.tick_rates.ai = 15; this.fixed_time_step = 1 / 30; // 沙盒游戏:增强性能适应性 this.config.perf.auto_adjust = true; // 支持时间缩放 this.config.base.time_scale = 1.0; }; /** * 设置回合制游戏循环 * @returns {void} */ GameLoop.prototype.setupTurnBased = function () { // 回合制游戏:非常低的频率,事件驱动 this.config.tick_rates.world = 5; this.config.tick_rates.physics = 5; this.config.tick_rates.ai = 5; this.fixed_time_step = 1 / 5; // 回合制游戏:更精确的事件处理 this.config.events.immed_proc = true; // 开启确定性执行 this.determ = true; }; /** * 设置音乐节奏游戏循环 * @returns {void} */ GameLoop.prototype.setupRhythm = function () { // 音乐节奏游戏:高频率、高精度 this.config.tick_rates.world = 120; this.config.tick_rates.physics = 120; this.config.tick_rates.input = 120; this.fixed_time_step = 1 / 120; // 关闭自适应以保证稳定帧率 this.config.base.adaptive = false; }; /** * 设置竞技游戏循环 * @param {object} sync_config 同步配置 * @returns {void} */ GameLoop.prototype.setupComp = function (sync_config) { // 竞技游戏:高频率、确定性更新 this.config.tick_rates.physics = 64; this.config.tick_rates.world = 64; this.fixed_time_step = 1 / 64; // 竞技游戏:支持锁步和回滚 if (sync_config.lockstep) { this.setupLockstep(); } // 竞技游戏:支持回滚 if (sync_config.rollback) { this.setupRollback(); } }; /** * 设置MMORPG游戏循环 * @returns {void} */ GameLoop.prototype.setupMMORPG = function () { // MMORPG:分层更新,性能优化 this.config.tick_rates.world = 10; this.config.tick_rates.ai = 2; this.config.tick_rates.anim = 30; this.config.perf.auto_adjust = true; }; /** * 设置休闲游戏循环 * @returns {void} */ GameLoop.prototype.setupCasual = function () { // 休闲游戏:事件驱动,低频率 this.config.tick_rates.world = 10; this.config.tick_rates.ai = 5; this.config.base.adaptive = false; }; /** * 设置RTS游戏循环 * @param {object} sync_config 同步配置 * @returns {void} */ GameLoop.prototype.setupRTS = function (sync_config) { // RTS:锁步同步 this.config.tick_rates.world = 16; // ~60Hz this.config.sync.lockstep = true; this.cmdBuf = new Map(); }; /** * 设置模拟游戏循环 * @returns {void} */ GameLoop.prototype.setupSimu = function () { // 模拟游戏:支持时间缩放 this.config.base.time_scale = 1.0; this.config.tick_rates.world = 20; this.config.perf.auto_adjust = true; }; /** * 设置通用游戏循环 * @returns {void} */ GameLoop.prototype.setupGeneral = function () { // 通用配置 this.config.tick_rates.world = 30; this.config.tick_rates.physics = 50; }; /** * 设置锁步同步 * @returns {void} */ GameLoop.prototype.setupLockstep = function () { // 锁步同步配置 this.config.sync.lockstep = true; // 锁步需要确定性执行 this.determ = true; // 初始化锁步状态 this._lockstep = { turn: 0, readyPlayers: new Set(), pendingActions: [], confirmed: false }; }; /** * 设置回滚同步 * @returns {void} */ GameLoop.prototype.setupRollback = function () { // 回滚同步配置 this.config.sync.rollback = true; // 回滚需要确定性执行 this.determ = true; // 初始化回滚状态 this._rollback = { frame: 0, history: [], max_history: 60, predInputs: new Map() }; }; /** * 启动游戏循环具体实现 * @private * @returns {Promise<void>} */ GameLoop.prototype._startCore = async function () { // 初始化时间变量 this.last_frame_time = performance.now(); this.last_second_time = this.last_frame_time; this.frames_this_second = 0; // 启动游戏循环 await this.gameLoop(); }; /** * 停止游戏循环具体实现 * @private * @returns {Promise<void>} */ GameLoop.prototype._stop = async function () { // 状态由基类stop方法设置,此处只记录日志和执行停止逻辑 this.log('info', '游戏循环已停止'); }; /** * 错误处理状态设置 * @private * @returns {void} */ GameLoop.prototype._error = function () { // 错误状态处理,基类没有提供统一管理error状态的方法,所以保留此处设置 this.loop_status = 'error'; this.log('error', '游戏循环进入错误状态'); }; /** * 执行游戏阶段 * @param {number} delta_time 帧间隔时间 * @returns {Promise<void>} */ GameLoop.prototype._execPhases = async function (delta_time) { let phases = this.config.phases; let phase_start = 0; // 预更新阶段 if (phases.pre_update) { phase_start = performance.now(); await this._runHooks('pre_update', delta_time); this.recordPhaseTime('pre_update', performance.now() - phase_start); } // 更新阶段 if (phases.update) { phase_start = performance.now(); await this.setSystems(delta_time); this.recordPhaseTime('update', performance.now() - phase_start); } // 后更新阶段 if (phases.post_update) { phase_start = performance.now(); await this._runHooks('post_update', delta_time); this.recordPhaseTime('post_update', performance.now() - phase_start); } // 渲染阶段 if (phases.render) { phase_start = performance.now(); await this._runHooks('pre_render', delta_time); await this._render(delta_time); await this._runHooks('post_render', delta_time); this.recordPhaseTime('render', performance.now() - phase_start); } // 清理阶段 if (phases.cleanup) { phase_start = performance.now(); await this._cleanup(delta_time); this.recordPhaseTime('cleanup', performance.now() - phase_start); } // 处理事件队列 await this.runEvents(); this.checkFrameBudget(); }; /** * 执行钩子函数 * @param {string} hook_name 钩子名称 * @param {number} delta_time 帧间隔时间 * @returns {Promise<void>} */ GameLoop.prototype._runHooks = async function (hook_name, delta_time) { let hooks = this._hook[hook_name] || []; for (let hook of hooks) { try { await hook(delta_time); } catch (error) { this.log('error', `钩子 ${hook_name} 执行错误:`, error); } } }; /** * 渲染处理 * @param {number} delta_time 帧间隔时间 * @returns {Promise<void>} */ GameLoop.prototype._render = async function (delta_time) { if (this._world && this._world.render) { await this._world.render(delta_time); } }; /** * 清理处理 * @param {number} delta_time 帧间隔时间 * @returns {Promise<void>} */ GameLoop.prototype._cleanup = async function (delta_time) { // 清理无效实体 if (this._world && this._world.cleanup) { await this._world.cleanup(delta_time); } // 定时持久化脏数据 await this._persistEntities(delta_time); }; /** * 定时持久化实体 * @param {number} delta_time 帧间隔时间 * @returns {Promise<void>} */ GameLoop.prototype._persistEntities = async function (delta_time) { var persist_config = this.config.persist; if (!persist_config || !persist_config.enabled) { return; } // 累计时间 this._persist_counter += delta_time; var interval_ms = persist_config.interval * 1000; // 检查是否到达持久化间隔 if (this._persist_counter >= interval_ms) { this._persist_counter = 0; // 保存脏数据实体 if (this._world && this._world._saveDirtyEntities) { await this._world._saveDirtyEntities(); } } }; /** * 处理循环错误 * @param {Error} error 错误对象 * @returns {Promise<void>} */ GameLoop.prototype._handleLoopError = async function (error) { if (this.config.base.stop_on_error) { this.loop_status = 'error'; this._error(); } }; /** * 处理暂停状态 * @returns {Promise<void>} */ GameLoop.prototype._handlePausedState = async function () { // 暂停状态下只处理高优先级事件 await this.runHighPriEvents(); // 等待恢复 await this.sleep(100); // 继续循环 if (this.loop_status === 'paused') { setImmediate(() => this.gameLoop()); } }; /** * 游戏主循环 * @returns {Promise<void>} */ GameLoop.prototype.gameLoop = async function () { if (this.loop_status !== 'running') return; // 检查暂停状态 if (this.loop_status === 'paused') { await this._handlePausedState(); return; } let frame_start = performance.now(); let delta_time = Math.min(frame_start - this.last_frame_time, 100); this.last_frame_time = frame_start; this.startMon(); try { await this._execPhases(delta_time); } catch (error) { await this._handleLoopError(error); } this.endMon(frame_start); // 动态帧率控制 let sleep_time = this.calcSleepTime(); if (sleep_time > 1) { await this.sleep(sleep_time); } if (this.loop_status === 'running') { setImmediate(() => this.gameLoop()); } }; /** * 系统更新 * @param {number} delta_time 帧间隔时间 * @returns {Promise<void>} */ GameLoop.prototype.setSystems = async function (delta_time) { let scaled_delta_time = delta_time * this.config.base.time_scale; // 获取有序的系统更新列表(考虑依赖关系) let ordered_systems = this.getOrderedSystems(); // 更新各个系统(根据各自的tick_rate) for (let [system_name] of ordered_systems) { let tick_rate = this.config.tick_rates[system_name] || this.config.tick_rates.world; if (tick_rate <= 0) continue; // 跳过禁用的系统 await this.updateSystem( system_name, scaled_delta_time, tick_rate ); } }; /** * 获取按依赖关系排序的系统列表 * @returns {Array} 有序的系统列表 */ GameLoop.prototype.getOrderedSystems = function () { // 如果没有依赖关系,直接返回系统列表 if (Object.keys(this._deps).length === 0) { return Object.entries(this._system); } // 简单的拓扑排序实现 let visited = new Set(); let result = []; let graph = this._deps; let visit = (system_name) => { if (visited.has(system_name)) return; visited.add(system_name); // 先访问依赖项 let dependencies = graph[system_name] || []; for (let dep of dependencies) { if (this._system[dep]) { visit(dep); } } if (this._system[system_name]) { result.push([system_name, this._system[system_name]]); } }; // 遍历所有系统 for (let system_name in this._system) { visit(system_name); } return result; }; /** * 根据固定帧率更新系统 * @param {string} system_name 系统名称 * @param {number} delta_time 帧间隔时间 * @param {number} tick_rate 帧率 * @returns {Promise<void>} */ GameLoop.prototype.updateSystem = async function (system_name, delta_time, tick_rate) { let system = this._system[system_name]; if (!system || !system.isEnabled()) return; // 获取累加器并累加帧时间 let acc = (this._accrual[system_name] || 0) + delta_time; let system_delta = 1000 / tick_rate; // 执行固定时间步长更新 while (acc >= system_delta) { try { let start_time = performance.now(); await system.update(system_delta); let update_time = performance.now() - start_time; // 记录性能数据 this.perf_stats.update_times[system_name] = update_time; acc -= system_delta; // 更新tick计数 this.config.tick_count++; } catch (error) { this.log('error', `系统 ${system_name} 更新错误:`, error); // 处理系统错误 if (system.critical) { throw error; } break; } } // 更新累加器 this._accrual[system_name] = acc; }; /** * 处理事件队列 * @returns {Promise<void>} */ GameLoop.prototype.runEvents = async function () { // 按优先级处理事件 for (let priority = 0; priority < this.config.events.priority; priority++) { let queue = this._event_queue[priority] || []; let events_to_process = queue.splice(0, Math.min(queue.length, this.config.events .max_per_frame)); // 限制每帧处理数量 for (let event of events_to_process) { try { await this.handleEvent(event, priority); } catch (error) { this.log('error', `事件处理错误 (优先级 ${priority}):`, error); } } } }; /** * 仅处理高优先级事件(用于暂停状态) * @returns {Promise<void>} */ GameLoop.prototype.runHighPriEvents = async function () { let queue = this._event_queue[0] || []; let events_to_process = queue.splice(0, Math.min(queue.length, 20)); for (let event of events_to_process) { try { await this.handleEvent(event, 0); } catch (error) { this.log('error', `高优先级事件处理错误 (优先级 0):`, error); } } }; /** * 处理单个事件 * @param {object} event 事件对象 * @param {number} priority 优先级 * @returns {Promise<void>} */ GameLoop.prototype.handleEvent = async function (event, priority) { // 事件处理逻辑 this.log('debug', `处理事件 (优先级 ${priority}):`, event); }; /** * 性能监控开始 * @returns {void} */ GameLoop.prototype.startMon = function () { this.perf_stats.frame_start = performance.now(); }; /** * 性能监控结束 * @param {number} frame_start 帧开始时间 * @returns {void} */ GameLoop.prototype.endMon = function (frame_start) { let frame_time = performance.now() - frame_start; // 记录帧时间 this.perf_stats.frame_times.push(frame_time); if (this.perf_stats.frame_times.length > 60) { this.perf_stats.frame_times.shift(); } // 计算FPS this.frames_this_second++; let now = performance.now(); if (now - this.last_second_time >= 1000) { this.perf_stats.fps = this.frames_this_second; this.frames_this_second = 0; this.last_second_time = now; // 计算系统负载 this.calcLoad(); // 触发性能统计更新事件 this.emitEvent('performance_stats_update', { fps: this.perf_stats.fps, load: this.perf_stats.load, frame_time: frame_time, timestamp: Date.now() }); // 自适应调整 if (this.config.perf.auto_adjust) { this.adjustPerf(); } // 性能分析日志(如果启用) if (this.config.perf.profile) { this.logPerf(); } } }; /** * 记录阶段执行时间 * @param {string} phase 阶段名称 * @param {number} time 执行时间(毫秒) * @returns {void} */ GameLoop.prototype.recordPhaseTime = function (phase, time) { let times = this.perf_stats.phase_times[phase] || []; times.push(time); if (times.length > 60) times.shift(); this.perf_stats.phase_times[phase] = times; }; /** * 检查帧时间预算 * @returns {void} */ GameLoop.prototype.checkFrameBudget = function () { let target_frame_time = 1000 / this.config.base.max_fps; let avg_frame_time = this.perf_stats.frame_times.reduce((a, b) => a + b, 0) / this.perf_stats.frame_times.length; if (avg_frame_time > target_frame_time * 1.2) { this.log('warn', `帧时间超出预算: ${avg_frame_time.toFixed(2)}ms > ${target_frame_time.toFixed(2)}ms`); // 触发帧时间超出预算事件 this.emitEvent('performance_frame_budget_exceeded', { avg_frame_time: avg_frame_time, target_frame_time: target_frame_time, timestamp: Date.now() }); if (this.config.perf.auto_adjust) { this.adjustPerf(); } } }; /** * 性能监控日志 * @returns {void} */ GameLoop.prototype.logPerf = function () { // 记录各阶段平均耗时 for (let phase in this.perf_stats.phase_times) { let times = this.perf_stats.phase_times[phase]; if (times.length > 0) { let avg_time = times.reduce((a, b) => a + b, 0) / times.length; this.log('debug', ` ${phase}: ${avg_time.toFixed(2)}ms`); } } }; /** * 计算系统负载 * @returns {void} */ GameLoop.prototype.calcLoad = function () { let target_frame_time = 1000 / this.config.base.max_fps; let avg_frame_time = this.perf_stats.frame_times.reduce((a, b) => a + b, 0) / this.perf_stats.frame_times.length; this.perf_stats.load = Math.min(avg_frame_time / target_frame_time, 1.0); }; /** * 自适应性能调整 * @returns {void} */ GameLoop.prototype.adjustPerf = function () { let load = this.perf_stats.load; let entity_count = this._world ? this._world.entities.size : 0; let player_count = this._world ? this._world.getPlayerNum() : 0; if (load > 0.8) { // 触发高负载事件 this.emitEvent('performance_high_load', { load: load, entity_count: entity_count, player_count: player_count, timestamp: Date.now() }); this.reduceLoad(entity_count, player_count); } else if (load < 0.5) { // 触发低负载事件 this.emitEvent('performance_low_load', { load: load, entity_count: entity_count, player_count: player_count, timestamp: Date.now() }); this.increaseQuality(entity_count, player_count); } }; /** * 降低性能负载 * @param {number} entity_count 实体数量 * @param {number} player_count 玩家数量 * @returns {void} */ GameLoop.prototype.reduceLoad = function (entity_count, player_count) { if (player_count > 100) { this.config.tick_rates.ai = Math.max(1, this.config.tick_rates.ai / 2); this.config.tick_rates.anim = Math.max(10, this.config.tick_rates.anim / 1.5); this.config.tick_rates.physics = Math.max(30, this.config.tick_rates.physics / 1.2); } else if (entity_count > 1000) { this.config.tick_rates.ai = Math.max(1, this.config.tick_rates.ai / 1.5); this.config.tick_rates.physics = Math.max(30, this.config.tick_rates.physics / 1.2); } else { this.config.tick_rates.ai = Math.max(1, this.config.tick_rates.ai / 2); this.config.tick_rates.anim = Math.max(10, this.config.tick_rates.anim / 1.5); } }; /** * 提高性能质量 * @param {number} entity_count 实体数量 * @param {number} player_count 玩家数量 * @returns {void} */ GameLoop.prototype.increaseQuality = function (entity_count, player_count) { let load = this.perf_stats.load; if (load < 0.3) { this.config.tick_rates.ai = Math.min(30, this.config.tick_rates.ai * 1.5); this.config.tick_rates.anim = Math.min(60, this.config.tick_rates.anim * 1.2); this.config.tick_rates.physics = Math.min(60, this.config.tick_rates.physics * 1.1); } else { this.config.tick_rates.ai = Math.min(30, this.config.tick_rates.ai * 1.2); this.config.tick_rates.anim = Math.min(60, this.config.tick_rates.anim * 1.1); } }; /** * 休眠函数 * @param {number} ms 休眠时间(毫秒) * @returns {Promise<void>} */ GameLoop.prototype.sleep = function (ms) { if (typeof ms !== 'number' || ms < 0) { throw new Error('休眠时间必须是非负数字'); } return new Promise(resolve => setTimeout(resolve, ms)); }; /** * 检测是否处于空闲状态 * @returns {boolean} 是否空闲 */ GameLoop.prototype.isIdle = function () { if (!this.config.idle.enabled) { return false; } if (!this._world) { return true; } let entity_count = this._world.entities ? this._world.entities.size : 0; let player_count = this._world._player_ids ? this._world._player_ids.size : 0; let is_idle = entity_count === 0 && player_count === 0; if (is_idle) { this.config.idle.counter++; if (this.config.idle.counter >= this.config.idle.threshold) { return true; } } else { this.config.idle.counter = 0; } return false; }; /** * 计算动态休眠时间 * @returns {number} 休眠时间(毫秒) */ GameLoop.prototype.calcSleepTime = function () { let idle_config = this.config.idle; let is_idle = this.isIdle(); if (is_idle) { idle_config.counter++; if (idle_config.counter >= idle_config.threshold) { let idle_interval = 1000 / idle_config.fps; return Math.max(idle_interval, 1); } } else { idle_config.counter = 0; } let target_interval = 1000 / this.config.base.max_fps; let elapsed = performance.now() - this.last_frame_time; let sleep_time = target_interval - elapsed; return Math.max(0, sleep_time); }; /** * 注册生命周期钩子 * @param {string} hook_name 钩子名称 * @param {Function} callback 回调函数 * @returns {void} */ GameLoop.prototype.registerHook = function (hook_name, callback) { if (!hook_name || typeof hook_name !== 'string') { throw new Error('钩子名称不能为空且必须是字符串'); } if (typeof callback !== 'function') { throw new Error('回调必须是函数'); } if (!this._hook[hook_name]) { throw new Error(`未知的钩子类型: ${hook_name}`); } this._hook[hook_name].push(callback); }; /** * 注销系统 * @param {string} name 系统名称 * @returns {Promise<void>} */ GameLoop.prototype.unregSystem = async function (name) { // 参数验证 if (!name || typeof name !== 'string') { throw new TypeError('系统名称不能为空且必须是字符串'); } try { // 清理系统资源 var system = this._system[name]; if (system && typeof system.cleanup === 'function') { await system.cleanup(); } // 删除系统引用 delete this._system[name]; delete this._accrual[name]; delete this.perf_stats.update_times[name]; delete this._deps[name]; this.log('info', `系统已注销: ${name}`); } catch (error) { this.log('error', `注销系统 ${name} 时发生错误`, error); throw error; } }; /** * 清理所有资源 * @returns {Promise<void>} */ GameLoop.prototype.cleanupAll = async function () { this.log('info', '开始清理所有游戏循环资源'); var cleanup_promises = []; // 清理所有系统 for (var system_name in this._system) { var system = this._system[system_name]; if (system && typeof system.cleanup === 'function') { var promise = system.cleanup().catch(error => { this.log('error', `清理系统 ${system_name} 时发生错误`, error); }); cleanup_promises.push(promise); } } // 等待所有清理操作完成 await Promise.all(cleanup_promises); // 清空所有数据结构 this._system = {}; this._accrual = {}; this._event_queue = {}; this._deps = {}; this.perf_stats = { frame_times: [], update_times: {}, frame_start: 0 }; this.log('info', '所有游戏循环资源已清理完成'); }; /** * 记录系统性能 * @param {string} system_name 系统名称 * @param {number} time 执行时间 * @returns {void} */ GameLoop.prototype.recordPerf = function (system_name, time) { let times = this.perf_stats.update_times[system_name] || []; times.push(time); if (times.length > 60) times.shift(); this.perf_stats.update_times[system_name] = times; }; /** * 处理游戏循环错误 * @param {Error} error 错误对象 * @returns {void} */ GameLoop.prototype.runError = function (error) { // 设置错误状态 this._error(); // 错误处理策略 if (this.config.perf?.auto_adjust) { this.reduceLoad(); } // 根据配置决定是否停止游戏循环 if (this.config.base?.stop_on_error) { this.log('warn', '游戏循环停止 (stop_on_error=true)'); this._stop(); } // 记录错误日志 this.log('error', '游戏循环错误处理:', error); }; /** * 获取性能统计 * @returns {object} 性能统计数据 */ GameLoop.prototype.getStats = function () { return { fps: this.perf_stats.fps, load: this.perf_stats.load, sys_perf: { ...this.perf_stats.update_times }, frame_times: [...this.perf_stats.frame_times], current_tick: this.current_tick }; }; /** * 动态配置更新 * @param {object} new_config 新配置 * @returns {void} */ GameLoop.prototype.setConfig = function (new_config) { if (!new_config || typeof new_config !== 'object') { throw new Error('新配置必须是对象'); } $.push(this.config, new_config, true); }; /** * 重置配置为初始状态 * @returns {void} */ GameLoop.prototype.resetConfig = function () { if (this.original_config) { this.config = JSON.parse(JSON.stringify(this.original_config)); this._init(); } }; /** * 设置游戏暂停状态 * @param {boolean} paused 是否暂停 * @returns {void} */ GameLoop.prototype.setPaused = function (paused) { if (typeof paused !== 'boolean') { throw new Error('暂停状态必须是布尔值'); } let old_status = this.loop_status; this.loop_status = paused ? 'paused' : (old_status === 'error' ? 'error' : 'running'); this.log('info', `游戏循环 ${paused ? '暂停' : '恢复'}`); }; /** * 清理方法(定期执行) * @returns {Promise<void>} */ GameLoop.prototype.cleanup = async function () { // 清理过期事件队列 for (let priority in this._event_queue) { let queue = this._event_queue[priority]; if (queue.length > this.config.events.queue_size * 0.8) { this.log('warn', `事件队列 (优先级 ${priority}) 几乎已满,正在清理...`); // 只保留高优先级事件 this._event_queue[priority] = queue.filter(event => event && event.persistent); } } // 执行各系统的清理方法 for (let system_name in this._system) { let system = this._system[system_name]; if (typeof system.cleanup === 'function') { try { await system.cleanup(); } catch (error) { this.log('error', `系统 ${system_name} 清理失败:`, error); } } } }; exports.GameLoop = GameLoop;