插件 Demo · 跳一跳无敌
这个 Demo 对应市场里的 跳一跳无敌(jump-invincible)。它演示把 Debugger 用在“无感改写”上:
- 在落点判定处下动作断点
- 命中后在当前调用帧执行改写,然后立即
resume - 支持自定义分数,且只改一次
- 面板只负责布防/撤防,不依赖“暂停栈”
1. 布防:动作断点
debugger.break(url, line, { column, condition, action }) 会:
- 在
url对应脚本的line/column下断点; - 命中时先执行
action表达式; - 立即
resume,用户看不到 “Paused in debugger”。
js
/**
* 布防一次。
*
* @param {number} score 目标分数;0 表示只改落点、不改分数
* @returns {Promise<{id:string, locations:Array}>} 断点信息
*/
async function arm(score) {
// 开启 Debugger 域(幂等)。
await wadPanelLayer.debugger.enable();
// 每次布防生成独立 token:
// action 里用 token 作为“本次布防已改分”的标记,
// 这样同一次布防只改一次,下一次重新布防才会再改。
const token = 'jump' + Date.now().toString(36);
const action = `(function(){
try {
var G = globalThis;
var k = '__wadJumpScore_${token}';
// 本次布防还没改过分:写一次分数,然后置标记。
if (!G[k]) {
G[k] = 1;
var s = ${Number(score) || 0};
if (s > 0) {
// 兼容单机/联机/不同版本的游戏对象字段;
// 任意一个失败都不影响其它写法,最后再统一改 hit。
try { this.currentScore = s; } catch (e) {}
try { this.UI.score = s; } catch (e) {}
try { this.UI.setScore(s); } catch (e) {}
try { this.scoreText.setScore(s); } catch (e) {}
}
}
// 落点判定:2 = 成功落点。
this.hit = 2;
} catch (e) {}
}).call(this)`;
// condition='true':每次落点都进动作断点(为了在成功落点时也能改分)。
// 如果只想失败落点救场,可改成 this.hit===0||this.hit===3||...
return wadPanelLayer.debugger.break('usr/game\\.js', 191, {
column: 36920,
condition: 'true',
action
});
}要点:
this是落点逻辑所在的游戏对象,所以动作用.call(this)绑定hit = 2让失败落点按成功处理,角色不会掉下去- 分数用 token 标记只改一次;后续落点只继续改
hit - 动作断点不会暂停游戏,体感无卡顿
2. 面板:开启/关闭/自定义分数
html
<button id="toggle">开启无敌</button>
<input id="score" type="number" value="9999">
<button id="apply">改分(一次)</button>
<pre id="log"></pre>
<script>
// 当前已布防的断点 id;null 表示未开启。
let bpId = null;
const log = (s) => {
document.getElementById('log').textContent += s + '\n';
};
/**
* 撤掉旧断点,再按当前输入分数重新布防。
* 这样“开启中改分”不需要刷新页面。
*/
async function armCurrent() {
const score = Number(document.getElementById('score').value) || 0;
// 先删旧断点,避免同一位置重复断点报 “already exists”。
if (bpId) await wadPanelLayer.debugger.unbreak(bpId).catch(() => {});
const bp = await arm(score);
bpId = bp.id;
log(`已布防 ${bpId} · 分数=${score > 0 ? score : '不修改'}`);
}
// 开启/关闭无敌。
document.getElementById('toggle').onclick = async () => {
if (bpId) {
await wadPanelLayer.debugger.unbreak(bpId);
bpId = null;
log('已撤防');
} else {
await armCurrent();
}
};
// 只改分:重新布防,下一次落点自动写入分数(仅一次)。
document.getElementById('apply').onclick = armCurrent;
</script>3. 观察命中
动作断点执行后,宿主会记录一条 actionLog;可以用来确认“真的命中了、动作真的执行了”。
js
(async () => {
// items 里每条包含断点 id、执行时间、action 结果。
const log = await wadPanelLayer.debugger.actionLog();
for (const item of log.items || []) {
wadPanelLayer.log('action', item.id, item.result);
}
})();验证清单
- [ ] 开启后落点失败也不会结束游戏
- [ ] 分数变为自定义值,且后续落点不会反复重置
- [ ] 游戏过程中没有明显停顿
- [ ] 关闭无敌后恢复原始落点判定
- [ ] 小程序重启后不会残留断点
完整实现见市场插件 跳一跳无敌(jump-invincible,版本 1.0.0)。