Files
kidgo/tools/dj-test.mjs
T

96 lines
5.1 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.
// 二段跳时机回归(tools/dj-test.mjs)
// 历史 bug 链:
// ① 全额抵消(旧 `vy = max(vy,0) - DJUMP`):满力一段到顶点后晚几帧接二段,二段塌到接近 0(用户报"二段非常短")
// ② 部分抵消(DJ_INERTIA 0.5→0.35):仍有"好沉+高度短"——起跳初速被下落速度从 6.7 吃到 3~4,
// 起跳那一下没劲才是"沉"的根源,与上升重力无关
// ③ 现行(DJ_INERTIA = 0,同 IWBT 原版):任何时机接二段都满力起跳,初速恒 -DJUMP
// 本测试用真实引擎测量:不同时机接二段时,二段自身的提升高度(djRise)。
// 通过标准:
// · 任意时机接二段都 ≈ 满力(≈60px ≈ 1.9 格)——INERTIA=0 语义,曲线应基本持平
// · 满力一段 ≈ 84px(≈2.6 格);顶点接二段总高 ≈ 4.5 格
const handlers = {};
const addL = (t, fn) => { (handlers[t] = handlers[t] || []).push(fn); };
globalThis.addEventListener = addL;
globalThis.window = { addEventListener: addL };
const key = (t, c) => (handlers[t] || []).forEach(fn => fn({ code: c, preventDefault() { }, repeat: false }));
const { Level } = await import('../js/level.js');
const { Player } = await import('../js/player.js');
const { Input } = await import('../js/input.js');
// 与 jumpdist.mjs 同一块平地:row17 是实心平台
const flat = {
id: 'test', name: 'T', type: 'jump', width: 44,
grid: (() => {
const rows = [];
rows.push('#'.repeat(44));
for (let i = 0; i < 16; i++) rows.push('#' + '.'.repeat(42) + '#');
rows.push('#' + '#'.repeat(42) + '#');
rows.push('#'.repeat(44));
return rows;
})(),
};
// 满力一段跳(起跳后一直按住);第 djFrame 帧松键、djFrame+1 帧接二段(之后保持按住)
// 返回:firstRise 一段顶点提升 / djRise 二段自身提升(接二段位置→二段后最高点)/ total 二段顶点离平台高度
function measure(djFrame) {
const L = new Level(flat);
const P = new Player(L);
P.x = 8 * 32; P.y = 17 * 32 - P.h; // 站在 row17 实心平台上
P.vx = 0; P.vy = 0; P.grounded = true; P.jumps = 0;
const y0 = P.y;
key('keydown', 'ShiftLeft'); // 起跳并按住 = 满力一段
let apex1 = y0, apex2 = y0, djDone = false, vyAtDj = null, yAtDj = y0;
for (let i = 0; i < 240; i++) {
const f = i + 1;
if (f === djFrame) key('keyup', 'ShiftLeft');
if (f === djFrame + 1) { key('keydown', 'ShiftLeft'); vyAtDj = P.vy; yAtDj = P.y; }
L.update(1, P, null);
P.update(1);
Input.endFrame();
if (djFrame && f === djFrame + 1 && P.jumps === 2) djDone = true;
if (djDone) apex2 = Math.min(apex2, P.y);
else apex1 = Math.min(apex1, P.y);
if (i > 2 && P.grounded) break;
if (P.dead) break;
}
key('keyup', 'ShiftLeft');
Input.endFrame();
return { firstRise: y0 - apex1, djRise: djDone ? yAtDj - apex2 : 0, total: y0 - apex2, vyAtDj, djDone };
}
// 满力一段顶点≈第 27 帧;落地≈第 50 帧。取 27~46 帧覆盖"顶点 → 落地前"整个二段窗口
const FRAMES = [27, 30, 34, 38, 42, 46];
const T = 32;
let fail = 0;
const rows = [];
console.log('满力一段跳后,不同时机接二段:二段自身提升高度(真实引擎实测)');
console.log(' 时机 接二段时vy 一段顶点 二段自身提升 二段顶点离平台');
for (const f of FRAMES) {
const r = measure(f);
rows.push({ f, ...r });
const dj = r.djDone
? `${r.djRise.toFixed(1).padStart(6)}px = ${(r.djRise / T).toFixed(2)} 格`
: ' —— 已落地,二段窗口已过 ——';
console.log(` 第${String(f).padStart(2)}帧 ${(r.vyAtDj ?? 0).toFixed(2).padStart(5)} ${r.firstRise.toFixed(1).padStart(6)}px ${dj} ${(r.total / T).toFixed(2)} 格`);
}
const at = f => rows.find(r => r.f === f);
const need = (cond, msg) => { if (!cond) { fail++; console.log(' ❌ ' + msg); } };
for (const r of rows) need(r.djDone, `第 ${r.f} 帧应还在二段窗口内(未落地)`);
const apex = at(27);
need(apex.firstRise > 79 && apex.firstRise < 90, `满力一段高度应 ≈84px(2.6格),实测 ${apex.firstRise.toFixed(1)}`);
need(apex.djRise > 52 && apex.djRise < 68, `顶点接二段自身提升应 ≈59px(1.85格),实测 ${apex.djRise.toFixed(1)}`);
need(apex.total > 138 && apex.total < 150, `顶点接二段总高应 ≈4.5格,实测 ${(apex.total / T).toFixed(2)}`);
// INERTIA=0:任何时机接二段都满力起跳,曲线应基本持平(与顶点差异 ≤3px)
for (const r of rows) {
if (!r.f) continue;
need(r.djRise >= 55, `第 ${r.f} 帧接二段自身提升应 ≈满力(≥55px),实测 ${r.djRise.toFixed(1)}`);
need(Math.abs(r.djRise - apex.djRise) <= 3, `第 ${r.f} 帧与顶点接二段差异应 ≤3px(INERTIA=0 曲线持平),实测差 ${Math.abs(r.djRise - apex.djRise).toFixed(1)}`);
}
need(at(46).djRise >= 55, `即使摔得快二段也不应衰减(INERTIA=0),实测 ${at(46).djRise.toFixed(1)}`);
if (fail) { console.log(`\n❌ dj-test 失败 ${fail} 项`); process.exit(1); }
console.log('\n✅ dj-test 通过:任意时机接二段均满力起跳(INERTIA=0),顶点总高 ≈4.5 格');