Files
Toolbox/dev_test_scripts/debug/debug_physics_balls_preview_match.js
T
yangxiangyuan 91148fe064 feat: 新增物理弹球实验室及配套功能
1. 新增物理弹球游戏全套代码,包含物理引擎、规则、渲染、游戏逻辑、存档、音效、UI
2. 新增物理弹球相关调试与单元测试脚本
3. 优化私有剪贴上传功能:增加200MB上传限制与错误提示
4. 修复复古弹球桌的光滑面防粘附与休眠逻辑
2026-08-08 22:31:33 +08:00

53 lines
1.9 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.
/* ============================================================
* debug_physics_balls_preview_match.js · 物理弹球 · 预览=实际轨迹验证
* 清空砖块后以固定角度发射,对比 simulatePath 预览点与真实球位置:
* 瞄准折线必须与球实际运动线路一致(误差 < 2px)。
* 运行:node dev_test_scripts/debug/debug_physics_balls_preview_match.js
* ============================================================ */
'use strict';
const fs = require('fs');
const path = require('path');
const vm = require('vm');
const LAB = path.join(__dirname, '..', '..', 'public', 'tools', 'thought_lab', 'labs', 'physics_balls');
const ctx = {
Math,
console,
PBAudio: { fire() {}, hit() {}, wall() {}, item() {}, breakBlock() {}, over() {}, claim() {} },
PBStorage: { getEscape() { return 50; } }
};
vm.createContext(ctx);
for (const f of ['pb_physics.js', 'pb_rules.js', 'pb_game.js', 'pb_render.js']) {
vm.runInContext(fs.readFileSync(path.join(LAB, f), 'utf8'), ctx, { filename: f });
}
const G = ctx.PBGame, RD = ctx.PBRender;
let ok = true;
for (const ang of [0, 0.35, -0.6, 1.0]) {
const g = G.create();
G.startGame(g);
g.blocks = []; g.items = []; // 清空砖块,保证对比确定
g.aimAngle = ang;
const pts = RD.simulatePath(g); // 预览点:pts[k] 对应 t = k/60 s(subDt=1/240,每 4 子步采样)
G.fire(g);
let maxErr = 0, checked = 0;
for (let f = 1; f <= 30; f++) { // 前 0.5s,每帧 4 子步与预览采样对齐
G.update(g, 1 / 60);
if (!g.balls.length) break;
if (f % 2) continue;
if (f >= pts.length) break;
const b = g.balls[0];
const err = Math.hypot(b.x - pts[f].x, b.y - pts[f].y);
maxErr = Math.max(maxErr, err);
checked++;
}
const pass = checked >= 10 && maxErr < 2;
console.log((pass ? 'PASS ' : 'FAIL ') + 'angle=' + ang + ' checked=' + checked + ' maxErr=' + maxErr.toFixed(2) + 'px');
ok = pass && ok;
}
process.exit(ok ? 0 : 1);