fix: 优化跳跃和下落手感
This commit is contained in:
1 parent
ada64fe4be
commit
afe2f64b9b
25 files changed
+1197
-188
No files matched your search
+22
-7
@@ -1,7 +1,7 @@
|
||||
// 共享可达性 BFS 核心:solve.mjs 与 reach-diag.mjs 共用
|
||||
// 用真实物理常量模拟走/落/跳(含二段跳时机、空中转向、松键短跳)
|
||||
export const TILE = 32, PW = 11, PH = 21;
|
||||
export const GRAV = 0.4, MAXFALL = 9, JUMP = 8.5, DJUMP = 7.6, HSPD = 3;
|
||||
export const GRAV = 0.25, GRAV_FALL = 0.32, GRAV_DJ = 0.35, MAXFALL = 9, JUMP = 6.6, DJUMP = 6.7, HSPD = 2.6, DJ_INERTIA = 0;
|
||||
|
||||
export function setupGlobals() {
|
||||
const handlers = {};
|
||||
@@ -49,12 +49,14 @@ export function makeSim(L) {
|
||||
const overlap = (a, b) => a.x < b.x + b.w && a.x + a.w > b.x && a.y < b.y + b.h && a.y + a.h > b.y;
|
||||
|
||||
function jump(fx, fy, vx0, djump, flip, rel, targets) {
|
||||
let x = fx, y = fy - PH, vy = -JUMP, vx = vx0, t = 0, used = false;
|
||||
let x = fx, y = fy - PH, vy = -JUMP, vx = vx0, t = 0, used = false, djUp = false;
|
||||
while (t++ < 240) {
|
||||
if (djump && !used && t === djump) { vy = -DJUMP; used = true; }
|
||||
// 与 player.js 一致:上升中按二段 = 直接 -DJUMP;下落中按只抵消 DJ_INERTIA 比例的下落速度
|
||||
if (djump && !used && t === djump) { vy = Math.max(vy, 0) * DJ_INERTIA - DJUMP; used = true; djUp = vy < 0; }
|
||||
if (flip && t === flip) vx = -vx;
|
||||
if (rel && t === rel && vy < -3) vy = -3;
|
||||
vy = Math.min(vy + GRAV, MAXFALL);
|
||||
vy = Math.min(vy + (vy < 0 ? (djUp ? GRAV_DJ : GRAV) : GRAV_FALL), MAXFALL);
|
||||
if (djUp && vy >= 0) djUp = false;
|
||||
// 真实行为(player.js):本帧被墙挡住只是没推动,按住方向键下一帧 vx 仍为 ±3。
|
||||
// 绝不能把 vx 永久清零,否则"贴着墙上升、越过台面边缘后再横移"这条经典路线会丢失。
|
||||
if (vx !== 0) {
|
||||
@@ -83,7 +85,7 @@ export function makeSim(L) {
|
||||
let x = fx + dir * 3, y = fy - PH, vy = 0, t = 0;
|
||||
if (solidAt(x, y, PW, PH, false)) return null;
|
||||
while (t++ < 400) {
|
||||
vy = Math.min(vy + GRAV, MAXFALL);
|
||||
vy = Math.min(vy + (vy < 0 ? GRAV : GRAV_FALL), MAXFALL);
|
||||
const prevBottom = y + PH;
|
||||
let rem = Math.abs(vy), landed = false;
|
||||
while (rem > 0.0001) {
|
||||
@@ -107,7 +109,10 @@ export function makeSim(L) {
|
||||
|
||||
/** BFS 可达性:targets=[{rect,type,...}],onState 回调每个新状态 */
|
||||
export const DEF_DJ = [0, 6, 12, 18, 24, 30];
|
||||
export const DEF_REL = [0, 4, 8, 14];
|
||||
// 2026-10-23:加 rel=5/6。vgap 夹缝(缝高 32px、盒高 21px)要求短跳 apex 精确落在 32~43px,
|
||||
// 且上升早期要躲开地刺左坡:rel=4 apex 35.7 但 t=7 蹭坡 2.6px,rel=6 apex 44.7 但 t=11 擦垂刺尖 0.6px,
|
||||
// 只有 rel=5(apex 38.9)同时满足(j2 x16 夹缝实证);j7 顶层 x52 夹缝则要 rel=6
|
||||
export const DEF_REL = [0, 4, 5, 6, 8, 14];
|
||||
|
||||
export function reach(L, { DJSET = DEF_DJ, RELSET = DEF_REL, targets = [], onState = null, maxStates = 40000 } = {}) {
|
||||
const sim = makeSim(L);
|
||||
@@ -118,7 +123,16 @@ export function reach(L, { DJSET = DEF_DJ, RELSET = DEF_REL, targets = [], onSta
|
||||
}
|
||||
if (!start) return { err: '出生点下方找不到落脚点', states: 0, targets };
|
||||
|
||||
const key = s => `${Math.round(s.fx / 6)},${Math.round(s.fy / 6)}`;
|
||||
// 3px 状态桶:6px 桶会把"贴右腰 1~3px"的起拍/落点窗量化吞掉(j2 连续三段因此误判不可达)
|
||||
// fy 规范化:jump/fall 返回的落点常比地面高零点几 px(如 1535.5),与精确落点 1536 同桶——
|
||||
// 先占桶者赢,导致走链被错位几 px 的跳链顶掉,芝麻距离的跳跃窗口翻转(加 rel=6 后 j2 状态数反而暴跌的根因)。
|
||||
// 真实游戏里重力下一帧即把玩家按到底(地面顶 = 32 的倍数),故按 canStand 门控 snapping
|
||||
const key = s => `${Math.round(s.fx / 3)},${Math.round(s.fy / 3)}`;
|
||||
const canon = (fx, fy) => {
|
||||
const r = Math.round(fy / TILE) * TILE;
|
||||
return (r !== fy && sim.canStand(fx, r)) ? r : fy;
|
||||
};
|
||||
start.fy = canon(start.fx, start.fy);
|
||||
const seen = new Set([key(start)]);
|
||||
const q = [start];
|
||||
let n = 0;
|
||||
@@ -128,6 +142,7 @@ export function reach(L, { DJSET = DEF_DJ, RELSET = DEF_REL, targets = [], onSta
|
||||
for (const tg of targets) if (!tg.hit && sim.overlap(box, tg.rect)) tg.hit = true;
|
||||
const push = r => {
|
||||
if (!r || !sim.canStand(r.fx, r.fy)) return;
|
||||
r.fy = canon(r.fx, r.fy);
|
||||
const k = key(r);
|
||||
if (seen.has(k)) return;
|
||||
seen.add(k); q.push(r);
|
||||
|
||||
Reference in new issue
Block a user