106 lines
4.3 KiB
JavaScript
106 lines
4.3 KiB
JavaScript
// 无头冒烟测试:构造全部关卡 + 模拟输入跑物理
|
||
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);
|