Files
cocos/extensions/game-controller-inspector/dist/footer.js
刘宇飞 d393302388 Complete Cocos Creator port with level bundles, themes, and tooling.
Adds level prefabs, theme assets, audio, extensions, and deployment scripts for the Unity WebGL migration.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-16 15:30:58 +08:00

174 lines
6.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use strict';
/** AppRoot InspectorSwitchLevel + 游戏调试(对齐 Unity TestPlayer */
function compUuid(dump) {
if (!dump || !dump.value) return '';
const u = dump.value.uuid;
return (u && u.value) ? u.value : (typeof u === 'string' ? u : '');
}
function nodeUuid(dump) {
if (!dump || !dump.value) return '';
const n = dump.value.node;
return (n && n.value && n.value.uuid) ? n.value.uuid : '';
}
function getMessageProtocolScene(el) {
let element = el;
while (element) {
const root = element.getRootNode && element.getRootNode();
element = element.parentElement || (root && root.host) || null;
if (element && element.messageProtocol && element.messageProtocol.scene) {
return element.messageProtocol.scene;
}
}
return 'scene';
}
async function callMethod(contextEl, uuid, name, args) {
if (!uuid || typeof Editor === 'undefined') return;
const protocols = [];
const primary = getMessageProtocolScene(contextEl);
if (primary) protocols.push(primary);
if (protocols.indexOf('scene') < 0) protocols.push('scene');
let lastErr;
for (let i = 0; i < protocols.length; i++) {
try {
await Editor.Message.request(protocols[i], 'execute-component-method', {
uuid,
name,
args: args || [],
});
return;
} catch (e) {
lastErr = e;
}
}
console.warn('[game-controller-inspector]', name, lastErr);
}
async function findGameControllerUuid(nu) {
if (!nu) return null;
try {
const node = await Editor.Message.request('scene', 'query-node', nu);
for (const c of node?.__comps__ || []) {
if (c.type === 'GameController' || c.type === '8940aPSKJhGKKIBE/qKnFm7') {
return c.value.uuid.value;
}
}
} catch (e) {
console.warn('[game-controller-inspector] query-node failed', e);
}
return null;
}
async function callGame(contextEl, dump, method, args) {
const gc = await findGameControllerUuid(nodeUuid(dump));
if (!gc) {
console.warn('[game-controller-inspector] 请先点预览 ▶,等关卡加载后再调试');
return;
}
await callMethod(contextEl, gc, method, args);
}
function parseStep(raw) {
const n = parseInt(String(raw || '1'), 10);
return Number.isNaN(n) || n === 0 ? 1 : n;
}
let lastDebugAt = 0;
function guardDebug(fn) {
return () => {
const now = Date.now();
if (now - lastDebugAt < 350) return;
lastDebugAt = now;
fn();
};
}
module.exports = Editor.Panel.define({
template: `
<div class="gc-footer">
<ui-label class="hint">① 预览 ▶ ② GameController 填 inputLevel ③ 点 SwitchLevel</ui-label>
<div class="row level-nav">
<ui-button class="btn-prev">上一关</ui-button>
<ui-button class="btn-next">下一关</ui-button>
</div>
<ui-button class="btn-switch blue">SwitchLevel</ui-button>
<ui-label class="sep">— 游戏调试(须预览运行中)—</ui-label>
<div class="row">
<ui-label class="lbl">步数</ui-label>
<ui-input class="step" value="1"></ui-input>
</div>
<div class="row">
<ui-button class="fwd">前进</ui-button>
<ui-button class="back">后退</ui-button>
<ui-button class="jump">跳</ui-button>
</div>
<div class="row">
<ui-button class="rot-l">左转</ui-button>
<ui-button class="rot-r">右转</ui-button>
<ui-button class="info">坐标</ui-button>
</div>
<div class="row">
<ui-button class="end">结束输入</ui-button>
<ui-button class="veh">载具+1</ui-button>
<ui-button class="reset">重置关卡</ui-button>
</div>
</div>
`,
style: `
.gc-footer { margin-top: 6px; }
.gc-footer .hint, .gc-footer .sep {
opacity: 0.8;
font-size: 11px;
margin: 6px 0;
display: block;
}
.gc-footer .row { display: flex; gap: 4px; margin-bottom: 6px; }
.gc-footer .lbl { font-size: 11px; align-self: center; min-width: 28px; }
.gc-footer .step { flex: 1; }
.gc-footer ui-button { flex: 1; }
.gc-footer .level-nav { margin-bottom: 4px; }
.gc-footer .btn-switch { width: 100%; margin-bottom: 4px; }
`,
$: {
hint: '.hint',
step: '.step',
btnSwitch: '.btn-switch',
btnPrev: '.btn-prev',
btnNext: '.btn-next',
fwd: '.fwd',
back: '.back',
jump: '.jump',
rotL: '.rot-l',
rotR: '.rot-r',
info: '.info',
end: '.end',
veh: '.veh',
reset: '.reset',
},
ready() {
const ctx = () => this.$this || this.$.btnSwitch;
const step = () => parseStep(this.$.step.value);
this.$.btnPrev.addEventListener('confirm', guardDebug(() => void callGame(ctx(), this.dump, 'prevLevel', [])));
this.$.btnNext.addEventListener('confirm', guardDebug(() => void callGame(ctx(), this.dump, 'nextLevel', [])));
this.$.btnSwitch.addEventListener('confirm', () => {
void callMethod(ctx(), compUuid(this.dump), 'switchLevelFromBootstrap', []);
});
this.$.fwd.addEventListener('confirm', guardDebug(() => void callGame(ctx(), this.dump, 'debugMove', [step()])));
this.$.back.addEventListener('confirm', guardDebug(() => void callGame(ctx(), this.dump, 'debugMove', [-step()])));
this.$.jump.addEventListener('confirm', guardDebug(() => void callGame(ctx(), this.dump, 'debugJump', [])));
this.$.rotL.addEventListener('confirm', guardDebug(() => void callGame(ctx(), this.dump, 'debugRotateLeft', [1])));
this.$.rotR.addEventListener('confirm', guardDebug(() => void callGame(ctx(), this.dump, 'debugRotateRight', [1])));
this.$.info.addEventListener('confirm', guardDebug(() => void callGame(ctx(), this.dump, 'debugPlayerInfo', [])));
this.$.end.addEventListener('confirm', guardDebug(() => void callGame(ctx(), this.dump, 'debugInputEnd', [])));
this.$.veh.addEventListener('confirm', guardDebug(() => void callGame(ctx(), this.dump, 'debugVehicleMove', [1])));
this.$.reset.addEventListener('confirm', guardDebug(() => void callGame(ctx(), this.dump, 'debugResetLevel', [])));
},
update(dump) {
if (dump) this.dump = dump;
},
});