You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

285 lines
10 KiB

(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 += '<option value="' + d.id + '"' + (d.id === this.device.deviceId ? ' selected' : '') + '>' +
d.name + (d.w ? ' (' + d.w + '×' + d.h + ')' : '') + '</option>';
}
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);