import { Director, director, game } from 'cc'; import { ThermalProfile } from './ThermalProfile'; import { PerfReport } from './PerfReport'; /** 战斗内 FPS 滑动窗口(帧数,约 1s@60) */ const WINDOW_FRAMES = 60; /** * 战斗 FPS 采样:窗口上报 PF-BTL-FPS,离局汇总 PF-BTL-SESS(含目标帧率 gap)。 */ export class PerfSampler { private static _active = false; private static _targetFps = 60; private static _windowBuf: number[] = []; private static _windowLeft = 0; private static _sessionBuf: number[] = []; /** 地图可交互后开始采样 */ static beginBattle(): void { if (PerfSampler._active) return; ThermalProfile.resolve(); PerfSampler._targetFps = ThermalProfile.current.battleFrameRate; PerfReport.reportBattleRuntimeConfig(); PerfSampler._active = true; PerfSampler._windowBuf = []; PerfSampler._sessionBuf = []; PerfSampler._windowLeft = WINDOW_FRAMES; director.on(Director.EVENT_AFTER_UPDATE, PerfSampler._onFrame, PerfSampler); } /** 战斗 UI teardown:汇总并上报 */ static endBattle(): void { if (!PerfSampler._active) return; director.off(Director.EVENT_AFTER_UPDATE, PerfSampler._onFrame, PerfSampler); PerfSampler._active = false; PerfSampler._flushWindow(true); PerfSampler._flushSession(); PerfReport.resetBattlePerfSession(); } private static _onFrame(): void { const dt = game.deltaTime || 0; if (dt <= 0) return; const fps = 1 / dt; PerfSampler._windowBuf.push(fps); PerfSampler._sessionBuf.push(fps); PerfSampler._windowLeft--; if (PerfSampler._windowLeft <= 0) { PerfSampler._flushWindow(false); PerfSampler._windowLeft = WINDOW_FRAMES; PerfSampler._windowBuf = []; } } private static _flushWindow(force: boolean): void { if (PerfSampler._windowBuf.length === 0) return; if (!force && PerfSampler._windowBuf.length < WINDOW_FRAMES / 2) return; const stats = PerfSampler._stats(PerfSampler._windowBuf); PerfReport.reportBattleFps(stats.avg, stats.p10, PerfSampler._targetFps); } private static _flushSession(): void { if (PerfSampler._sessionBuf.length === 0) return; const stats = PerfSampler._stats(PerfSampler._sessionBuf); PerfReport.reportBattleSessionFps( stats.avg, stats.p10, PerfSampler._targetFps, PerfSampler._sessionBuf.length, ); PerfSampler._sessionBuf = []; } private static _stats(buf: number[]): { avg: number; p10: number } { const sorted = [...buf].sort((a, b) => a - b); const sum = sorted.reduce((a, b) => a + b, 0); const avg = sum / sorted.length; const p10Idx = Math.floor(sorted.length * 0.1); const p10 = sorted[p10Idx] ?? avg; return { avg, p10 }; } }