(function (global) { 'use strict'; /** * Workbench host: wait for cc, wire panels / device / soft API. */ function PreviewWorkbenchHost() { this.cc = null; this.layout = null; this.sampler = null; this.markers = null; this.pick = null; this.device = null; this.panels = {}; this._ready = false; this._paused = false; } PreviewWorkbenchHost.prototype.boot = function () { var root = document.getElementById('pw-root'); if (!root) { console.warn('[调试工作台] 缺少 #pw-root'); return; } global.PWDevicePreview.hideOfficialToolbar(); this.layout = new global.PWLayout(root); this.sampler = new global.PWPerfSampler(); this.markers = new global.PWAutoMarkers(this.sampler); this.pick = new global.PWNodePick(); this.device = new global.PWDevicePreview(); this.device.restore(); var center = document.getElementById('pw-center'); var content = document.getElementById('content'); if (center && content) this.device.mount(center, content); this.panels.console = new global.PWConsolePanel(); this.panels.hierarchy = new global.PWHierarchyPanel(); this.panels.inspector = new global.PWInspectorPanel(); this.panels.assets = new global.PWAssetsPanel(); this.panels.perf = new global.PWPerfPanel(this.sampler); this.layout.registerPanel('console', this.panels.console.mount(), '控制台'); this.layout.registerPanel('hierarchy', this.panels.hierarchy.mount(), '层级'); this.layout.registerPanel('inspector', this.panels.inspector.mount(), '属性'); this.layout.registerPanel('assets', this.panels.assets.mount(), '资源'); this.layout.registerPanel('perf', this.panels.perf.mount(), '性能'); this.layout.init(); this.panels.hierarchy.setPick(this.pick); this.panels.inspector.setPick(this.pick); this._bindToolbar(); this._fillDeviceSelect(); this.device.apply(); var self = this; this._setStatus('引擎等待中…', false); this._waitForEngine(function (cc) { self._onEngineReady(cc); }); global.__PreviewWorkbench = { mark: function (label) { if (self.sampler) self.sampler.mark(label); }, getSampler: function () { return self.sampler; }, getPick: function () { return self.pick; }, device: self.device, isReady: function () { return self._ready; }, }; }; PreviewWorkbenchHost.prototype._fillDeviceSelect = function () { var sel = document.getElementById('pw-device-select'); if (!sel || !this.device) return; var list = this.device.list(); var html = ''; for (var i = 0; i < list.length; i++) { var d = list[i]; html += ''; } sel.innerHTML = html; }; PreviewWorkbenchHost.prototype._bindToolbar = function () { var self = this; document.getElementById('pw-mode-game').addEventListener('click', function () { self.pick.setMode('game'); }); document.getElementById('pw-mode-inspect').addEventListener('click', function () { self.pick.setMode('inspect'); }); var deviceSel = document.getElementById('pw-device-select'); if (deviceSel) { deviceSel.addEventListener('change', function () { self.device.setDevice(deviceSel.value); }); } var rotateBtn = document.getElementById('pw-device-rotate'); if (rotateBtn) { rotateBtn.addEventListener('click', function () { var rotated = self.device.toggleRotate(); rotateBtn.classList.toggle('active', rotated); rotateBtn.textContent = rotated ? '竖屏' : '旋转'; }); } var pauseBtn = document.getElementById('pw-game-pause'); if (pauseBtn) { pauseBtn.addEventListener('click', function () { var cc = self.cc; if (!cc || !cc.director) return; self._paused = !self._paused; try { if (self._paused) cc.director.pause(); else cc.director.resume(); } catch (e) { console.warn('[调试工作台] 暂停失败', e); } pauseBtn.textContent = self._paused ? '继续' : '暂停'; pauseBtn.classList.toggle('active', self._paused); }); } var bindStep = function (btn) { if (!btn) return; btn.addEventListener('click', function () { self._stepOneFrame(); }); }; bindStep(document.getElementById('pw-game-step')); bindStep(document.getElementById('pw-game-step-compact')); this._bindFpsButton(); }; /** 推进一帧(建议在暂停状态下使用) */ PreviewWorkbenchHost.prototype._stepOneFrame = function () { var cc = this.cc; if (!cc) { console.warn('[调试工作台] 引擎未就绪,无法按帧执行'); return; } try { if (!this._paused && cc.director && typeof cc.director.pause === 'function') { cc.director.pause(); this._paused = true; var pauseBtn = document.getElementById('pw-game-pause'); if (pauseBtn) { pauseBtn.textContent = '继续'; pauseBtn.classList.add('active'); } } if (cc.game && typeof cc.game.step === 'function') { cc.game.step(); return; } if (cc.director && typeof cc.director.tick === 'function') { var fps = (cc.game && cc.game.frameRate) ? cc.game.frameRate : 60; cc.director.tick(1 / Math.max(1, fps)); return; } console.warn('[调试工作台] 当前引擎不支持按帧执行'); } catch (e) { console.warn('[调试工作台] 按帧执行失败', e); } }; /** FPS 浮窗高亮按钮(主栏 / 紧凑栏同步),默认关闭 */ PreviewWorkbenchHost.prototype._bindFpsButton = function () { var self = this; this._fpsOn = false; var main = document.getElementById('pw-show-fps'); var compact = document.getElementById('pw-show-fps-compact'); var syncUi = function (on) { if (main) { main.classList.toggle('active', on); main.setAttribute('aria-pressed', on ? 'true' : 'false'); } if (compact) { compact.classList.toggle('active', on); compact.setAttribute('aria-pressed', on ? 'true' : 'false'); } }; var apply = function (on) { self._fpsOn = !!on; syncUi(self._fpsOn); var cc = self.cc; if (!cc || !cc.profiler) return; try { if (self._fpsOn) cc.profiler.showStats(); else cc.profiler.hideStats(); } catch (e) { console.warn('[调试工作台] 切换 FPS 浮窗失败', e); } }; var toggle = function () { apply(!self._fpsOn); }; if (main) main.addEventListener('click', toggle); if (compact) compact.addEventListener('click', toggle); this._setFpsVisible = function (on) { apply(!!on); }; syncUi(false); }; PreviewWorkbenchHost.prototype._onEngineReady = function (cc) { this.cc = cc; this._ready = true; this._setStatus('引擎已就绪', true); this.sampler.bindEngine(cc); this.sampler.start(); this.markers.bindEngine(cc); this.pick.bindEngine(cc); this.panels.hierarchy.bindEngine(cc); this.panels.inspector.bindEngine(cc); this.panels.assets.bindEngine(cc); this.panels.perf.render(); // 引擎就绪后必须同步设备帧尺寸,否则仍按窗口适配导致画面拉伸 this.device.apply(false); if (this.layout) this.layout.onEngineReady(); var self = this; setTimeout(function () { if (self.device) self.device.apply(false); }, 100); // 默认不显示 FPS;若引擎自动打开则关掉 setTimeout(function () { if (self._setFpsVisible) self._setFpsVisible(false); }, 500); }; PreviewWorkbenchHost.prototype._setStatus = function (text, ok) { var el = document.getElementById('pw-engine-status'); if (!el) return; el.textContent = text; el.classList.toggle('ok', !!ok); el.classList.toggle('err', ok === false && text.indexOf('失败') >= 0); }; PreviewWorkbenchHost.prototype._waitForEngine = function (done) { var self = this; var tries = 0; var max = 300; var timer = setInterval(function () { tries++; var cc = self._probeCc(); if (cc && cc.director && cc.game) { var scene = null; try { scene = cc.director.getScene(); } catch (e) { scene = null; } var running = false; try { running = !!cc.game._isRunning || (cc.director && !cc.director.isPaused()); } catch (e2) { running = !!scene; } if (scene || running || tries > 40) { clearInterval(timer); done(cc); return; } } if (tries >= max) { clearInterval(timer); self._setStatus('引擎未就绪', false); console.warn('[调试工作台] 引擎探测超时'); } }, 100); }; PreviewWorkbenchHost.prototype._probeCc = function () { if (global.cc && global.cc.director) return global.cc; if (global.CocosEngine && global.CocosEngine.director) return global.CocosEngine; return null; }; function start() { var host = new PreviewWorkbenchHost(); host.boot(); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', start); } else { start(); } })(window);