Files
kidgo/tools/smoke.mjs
T
2026-10-24 02:35:03 +08:00

106 lines
4.3 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.
// 无头冒烟测试:构造全部关卡 + 模拟输入跑物理
const handlers = {};
const addL = (t, fn) => { (handlers[t] = handlers[t] || []).push(fn); };
globalThis.addEventListener = addL;
globalThis.window = { addEventListener: addL };
const key = (type, code) => (handlers[type] || []).forEach(fn => fn({ code, preventDefault() { }, repeat: false }));
const down = c => key('keydown', c);
const up = c => key('keyup', c);
const { LEVELS } = await import('../js/levels/index.js');
const { Level } = await import('../js/level.js');
const { Player } = await import('./player.js'.replace('./player.js', '../js/player.js'));
const { Input } = await import('../js/input.js');
let fail = 0;
const err = m => { console.log(' ✗ ' + m); fail++; };
console.log('=== 关卡构造 ===');
for (const d of LEVELS) {
try {
const L = new Level(d);
const P = new Player(L);
// 静止 60 帧
for (let i = 0; i < 60; i++) { L.update(1, P, null); P.update(1); Input.endFrame(); }
const grounded = P.grounded, alive = P.alive;
console.log(` ${d.id.padEnd(3)} ${String(d.name).padEnd(16)} 实体=${String(L.entities.length).padStart(3)} boss=${L.bosses.length} 平台=${L.movers.length} 站住=${grounded ? 'Y' : 'N'} 存活=${alive ? 'Y' : 'N'}`);
if (!grounded && d.type !== 'boss') err(`${d.id} 出生点悬空(60帧后未着地)`);
if (!alive) err(`${d.id} 出生即死`);
// 模拟:向右跑 + 反复跳跃 400 帧
down('ArrowRight');
for (let i = 0; i < 400; i++) {
if (i % 40 === 0) down('ShiftLeft');
if (i % 40 === 8) up('ShiftLeft');
if (i % 40 === 12) { down('ShiftLeft'); }
if (i % 40 === 16) up('ShiftLeft');
L.update(1, P, null);
for (const b of L.bosses) b.update(1, P);
P.update(1);
Input.endFrame();
}
up('ArrowRight'); up('ShiftLeft');
const moved = P.x;
if (!Number.isFinite(P.x) || !Number.isFinite(P.y)) err(`${d.id} 坐标 NaN`);
if (Math.abs(P.vx) > 20 || Math.abs(P.vy) > 40) err(`${d.id} 速度异常 vx=${P.vx} vy=${P.vy}`);
console.log(` → 400帧后 x=${moved.toFixed(0)} y=${P.y.toFixed(0)} 死亡=${G_DEATHS(P)}`);
} catch (e) {
err(`${d.id} 运行异常: ${e.message}\n${e.stack?.split('\n')[1] || ''}`);
}
}
function G_DEATHS() { return ''; }
console.log('\n=== 死亡与手动重生 ===');
{
const L = new Level(LEVELS.find(l => l.id === 'j1'));
const P = new Player(L);
let deaths = 0;
P.onDeath = () => deaths++;
for (let i = 0; i < 30; i++) { L.update(1, P, null); P.update(1); Input.endFrame(); }
P.kill();
// 新语义(2026-10-24):死亡后不自动重生,定格等待玩家手动按重生键
for (let i = 0; i < 80; i++) { L.update(1, P, null); P.update(1); Input.endFrame(); }
if (P.alive) err('死亡后未等待手动重生(自动复活了)');
else console.log(` 死亡计数=${deaths} 80帧后仍定格等待手动重生 ✓(deadT=${P.deadT})`);
P.respawn();
for (let i = 0; i < 10; i++) { L.update(1, P, null); P.update(1); Input.endFrame(); }
if (!P.alive) err('手动重生失败');
else console.log(` 手动重生后 alive ✓ 位置=(${P.x.toFixed(0)},${P.y.toFixed(0)})`);
if (deaths !== 1) err('死亡回调未触发');
}
console.log('\n=== 射击与 BOSS ===');
{
const L = new Level(LEVELS.find(l => l.id === 'b1'));
const P = new Player(L);
const boss = L.bosses[0];
const hp0 = boss.hp;
P.hasGun = true;
for (let i = 0; i < 600; i++) {
if (i % 12 === 0) P.shootCool = 0, P.shoot();
L.update(1, P, null);
for (const b of L.bosses) b.update(1, P);
P.update(1);
Input.endFrame();
if (boss.hp <= 0) break;
}
console.log(` BOSS hp ${hp0} → ${boss.hp} 弹幕数=${L.ebullets.length} 阶段=${boss.phase}`);
if (boss.hp >= hp0) err('子弹没有对 BOSS 造成伤害');
}
console.log('\n=== 坑向事件 ===');
{
const L = new Level(LEVELS.find(l => l.id === 'r4'));
const P = new Player(L);
let died = 0; P.onDeath = () => died++;
// 走到传送门 (r4: col 44, row 17)
P.x = 44 * 32; P.y = 17 * 32;
for (let i = 0; i < 4; i++) { L.update(1, P, null); P.update(1); Input.endFrame(); }
console.log(` 传送门:玩家被送到 x=${P.x.toFixed(0)} (起点 x=${L.spawn.x})`);
if (Math.abs(P.x - L.spawn.x) > 4) err('传送门未送回起点');
}
console.log(fail ? `\n❌ ${fail} 项失败` : '\n✅ 全部通过');
process.exit(fail ? 1 : 0);