fix: 优化跳跃和下落手感
This commit is contained in:
1 parent
ada64fe4be
commit
afe2f64b9b
25 files changed
+1197
-188
No files matched your search
@@ -22,3 +22,120 @@
|
||||
- 根因:`js/ui.js` 的 `SCREENS` 数组没加 `'scr-settings'`,`UI.show('scr-settings')` 会把所有已知屏 hidden、却从不取消设置屏的 hidden——只剩画布标题背景(用户截图即此症状)。
|
||||
- 修复:SCREENS 加入 `scr-settings`(一行)。教训:**新增 screen 必须同步 SCREENS 数组**。
|
||||
- 回归:`tools/settings-test.mjs` 增加「SCREENS 含 scr-settings / 标题有设置入口」两条源码断言,防复发;settings-test 与 dom-smoke 全绿。
|
||||
|
||||
## 设置界面:确定返回上一页 + PC/移动端分设
|
||||
- 需求:① 点「确定」后返回进入设置前的界面(上一页);② 电脑端设置「键盘映射」,移动端设置「手机操作按钮」(按设备二选一显示)。
|
||||
- `js/input.js`:新增 `DEFAULT_BIND`(出厂 BIND 快照)、`export defaultBindings()`(深拷贝)、`export applyBindings(map)`(用 `{action:[code]}` 覆盖生效键位)。
|
||||
- `js/settings.js`:
|
||||
- 新增 `KEY_ACTIONS`(left/right/up/down/jump/shoot/suicide/restart/pause 共 9 项可重绑)、`keyLabel(code)`(←/→/Shift/空格等可读名)。
|
||||
- `pcMode = !isTouch`(由 `Settings.init(useTouch)` 传入);`enter()` 末尾按 `pcMode` 切换 `#set-keys-row`/`#set-touch-row` 的 hidden:PC 显键盘映射、移动端显手柄按钮。
|
||||
- `renderKeys()` 渲染每行「动作名 + 按键 chip(点×删除)+ +添加」;`wireKeys()` 点击委托 + `document` keydown 捕获下一次按键写入 `work.keys`(Esc 取消),同一动作支持多键。
|
||||
- `confirm()` 保存用户名/touch/keys 并 `applyBindings(s.keys)`;`reset()` 把 keys 也回出厂;`makeDefaults()`/`meta()` 保证 `keys` 字段齐全。
|
||||
- `wireKeys()` 加 `keysWired` 幂等保护(重复 init 不会重复绑监听)。
|
||||
- `js/main.js`:模块级 `let settingsFrom='scr-title'`;`settings` action 里 `settingsFrom = UI.cur` 后 `Settings.enter()`;`set-ok` 改为 `Settings.confirm(); UI.show(settingsFrom)`(确定后回上一页);`Settings.init(useTouch)` 传入设备检测结果。
|
||||
- `index.html`:设置屏新增 `#set-keys`(键盘映射容器)+ 两行 `#set-keys-row`/`#set-touch-row` 供切换显隐。
|
||||
- CSS:`.set-keys/.krow/.kact/.kkeys/.kchip/.krm/.kadd/.klisten` 等键盘映射样式(`blink` 动画提示监听中)。
|
||||
- 验证:`tools/settings-test.mjs` 扩到 30 断言(input API / PC·移动端面板显隐切换 / 点击 chip→keydown 重绑 / 添加 / 删除 / 确定落盘 / reset 回出厂 / main 里 set-ok 返回上一页源码断言)全过;dom-smoke、check、smoke、map、save、key、ice、solve 全绿;预览 8126 返回 200 且含 set-keys/set-keys-row/set-touch-row。
|
||||
|
||||
## 设置·键盘重绑加冲突检测(用户要求)
|
||||
- 需求:电脑端在设置里改键时,要能「检测冲突」。
|
||||
- `js/settings.js`:
|
||||
- 新增 `let conflict = null`(warning 状态)与 `conflictInfo(code, act, idx)`:遍历 `KEY_ACTIONS` 的 `work.keys`,若 `code` 已被**其它**动作(或同动作不同槽)占用则返回该动作标签;并额外检查不可重绑的系统动作 `BIND.menu`(如 KeyQ→「菜单」),避免把键绑到系统功能上。
|
||||
- `onCaptureKey()`:捕获到非 Esc 的键后先查冲突;若冲突则**拒绝写入**、置 `conflict={code,label,act}` 并 `renderKeys()`(停留在监听态,等换键或 Esc);无冲突才写入并清 `conflict`。
|
||||
- `renderKeys()`:面板顶部加 `.kwarb` 红色横幅「「X」已被【Y】占用,请换一个键(Esc 取消)」;监听行 tip 在冲突时变红显示「该键冲突,请换一个键」。
|
||||
- `enter()/reset()` 重置 `conflict=null`;`Settings` 暴露 `_conflict()/_listening()` 供测试/调试。
|
||||
- `js/input.js`:`const BIND` → `export const BIND`(供冲突检测引用 `menu` 键)。
|
||||
- CSS:`.kwarb`(红底警示横幅)、`.klisten.bad`(红字警告)。
|
||||
- 验证:`tools/settings-test.mjs` 扩到 36 断言,新增「冲突:jump 不会绑到被左移占用的 KeyA / 记录到被左移占用 / 顶部警告横幅 / 改用空闲键 KeyK 成功 / 同动作重复键不重复写入 / Esc 退出无残留 / KeyQ 被系统菜单占用」全过;dom-smoke、key、smoke、check、map、save、ice、solve 全绿。
|
||||
|
||||
## 刺改为「单三角形 + 碰撞与形状完全对应」(用户纠正)
|
||||
- 用户纠正:不要 3 个小齿刺,要**单个三角形占一格**,且**碰撞必须和三角形形状完全对应**(不是矩形近似)。
|
||||
- `js/sprites.js` `drawSpike`:由「3 个小三角」改为**一个占满整格的三角**(尖端朝 dir,底边贴相反侧),并沿底边画一条暗色基座(正好落在三角底边,不扩大判定)。`TILE=32`,故每刺格 32×32。
|
||||
- `js/level.js`:删除 `spikeBox`(旧「收窄矩形近似」),新增 `spikeTri(t,x,y)`(顶点与 `drawSpike` 完全一致)与 `triRectOverlap`(分离轴定理,凸三角×AABB 充要条件)。`deadlyRect` 改用 `spikeTri`+`triRectOverlap`(网格刺 + dropspike 都用真三角;dropspike 用 `SPIKE_L` 与其 `drawDropSpike` 的 dir=2 一致)。
|
||||
- 关键性质:底宽尖窄——底部两角现在**会致死**(旧矩形近似把它们当安全),尖顶外侧安全,与真实三角形状一致。
|
||||
- 一致性利好:game 的 `player.js`、`tools/lib-reach.mjs`(求解器)、`save-diag.mjs`、`bot.mjs` 全部直接调用 `L.deadlyRect`,改碰撞后自然统一,无需另改求解器模型。
|
||||
- 验证:新增 `tools/spike-test.mjs`(16 断言:spikeTri 四向顶点 / triRectOverlap 内-外-AABB / deadlyRect 集成上刺尖顶安全·底中致死·底左角致死·空地安全 / 与旧矩形近似在底左角结论相反的精确性对比)全过;`solve.mjs` 仍「所有关卡终点与存档点均可达」;editor-wysiwyg、dom-smoke、check、smoke、map、save、key、ice、settings 九套全绿。
|
||||
|
||||
## 编辑器所见即所得(WYSIWYG)+ 刺显示真实三角形
|
||||
- 需求:编辑器里所有方块要显示游戏内真实样子(原来用「彩色块 + 字母/箭头」表示);刺要显示成三角形(游戏里 `drawSpike` 本来就是三角,编辑器之前却画成 `↑↓←→` 箭头字符)。
|
||||
- `js/editor.js`:
|
||||
- `import * as S from './sprites.js'`;新增 `drawTileReal(ctx, ch, px, py, props, t)` 把每个字符分派到 `S.drawX`(`#/@/=/M`→drawBlock 各 variant、`%/~/-\/V/^/*/D/X/G/P/F/J/W/T/O/C` 各对应函数,`^` 按 `props.dir` 转 0/1/2/3 画三角,`S` 出生点画小人 `drawKid`);`B`/`!` 等无独立美术的保留「色块+字母」兜底 `drawMarker`。
|
||||
- `draw()` 重写:每格调用 `drawTileReal` 替代「填色块+画字母」;保留淡网格线、选中高亮;传送门额外叠加 `W{id}` 与连接状态(编辑器元数据)。
|
||||
- `buildPalette()`:`?` 工具用 ⌖ 字形,其余每个方块用 `drawTileReal` 渲染成 32×32 缩略 canvas(`class="pal-cv"`),调色板即真实预览。
|
||||
- `PALETTE` 改 `export const`(便于测试);删除不再使用的 `SPIKE_ARROW`。
|
||||
- CSS:`.pal-cv{width:26px;height:26px;...image-rendering:pixelated}`。
|
||||
- 测试:新增 `tools/editor-wysiwyg-test.mjs`(init 渲染全部调色板方块无异常 / 刺以三角形图元绘制 lineTo=6 / 方块真实纹理 fillRect / 23 种方块在画布绘制不抛异常);dom-smoke(init 跑 buildPalette 覆盖全部 25 字符分发)、check/smoke/map/save/key/ice/solve 全绿。
|
||||
|
||||
## 设置·键盘重绑面板移除「下蹲」(用户要求)
|
||||
- 需求:把「按键设置」里的下蹲(down)项去掉。
|
||||
- `js/settings.js`:`KEY_ACTIONS` 删除 `['down','下(下蹲)']`(由 9 项变 8 项)。仅影响键盘重绑面板与冲突检测范围;游戏内 `down` 逻辑(`player.js` 下蹲/下穿)与移动端触屏 `down` 按钮(`BUTTONS`/`touch.js`/`index.html` 的 `data-touch="down"`)保持不变——用户只要求移除「按键设置」里的项。
|
||||
- 测试:`tools/settings-test.mjs` 的跳跃行索引 4→3(down 移除后 jump 成为第 4 项),36 断言仍全过;dom-smoke、key、check、solve 全绿。
|
||||
|
||||
## 刺外观对齐参考图(冰蓝白渐变大三角)
|
||||
- 用户反馈「这也不是三角形呀」并给参考图:经典 I wanna 的淡蓝白渐变单三角。此前刺是灰色 `#c8c8d8` + 深色基座条,观感不像三角。
|
||||
- `js/sprites.js` `drawSpike` 重写外观:顶点不变(仍与 level.js `spikeTri` 完全一致,碰撞不动),改为冰蓝白线性渐变(尖端 `#f4f9fd` → 底边 `#a8bccf`,沿刺方向渐变)+ 淡蓝描边 `rgba(150,175,200,.9)` + 尖端附近白色高光片;删除深色基座条。
|
||||
- 删除已无引用的 `tri()` 助手;`C.spike/spikeDark` 更新为淡蓝(`#cfdde9`/`#a8bccf`)。
|
||||
- 新增 `spike-preview.html` 预览页:用真实 drawSpike/drawBlock 渲染地面刺/天花板刺/贴墙刺,供用户对照参考图。
|
||||
- 测试:spike-test(16 断言)、editor-wysiwyg、dom-smoke、solve(23 关可达)及全部回归绿。
|
||||
- 修复:上一轮 drawSpike 的「尖端高光」坐标计算错误(ax + (bx+cx)/2 把顶点当标量相加,多边形飞出格子),游戏中刺后面拉出灰色长条。已整体删除高光,只留冰蓝白渐变三角 + 淡蓝描边(与参考图一致)。全部回归绿。
|
||||
|
||||
## 冰面提速 + 删除首页操作说明 + 物理手感下调(用户要求三连)
|
||||
- **冰面最大速度阈值调大**:`js/player.js` 新增 `PHY.ICE_TOP: 1.6`(原内联 `HSPD*1.35`),冰面/滑行惯性速度上限 = HSPD×1.6;`ICE_MAX` 局部变量改由 `PHY.ICE_TOP` 计算。ice-test 注释数字同步为 4.32。
|
||||
- **删除首页操作说明**:`index.html` 去掉 scr-title 的「操作说明」按钮和整个 `#scr-help` 屏;`js/main.js` 删 `help` action;`js/ui.js` 的 `SCREENS` 删 `'scr-help'`;`css/style.css` 删 `.help-*` 规则。
|
||||
- **物理手感下调(用户:「kid移动速度减慢点,跳跃重力小一点」)**:`js/player.js` 与 `tools/lib-reach.mjs` 同步 GRAV 0.4→0.34、HSPD 3→2.7。扫描确认仅 j1/j9 终点不可达,按「调手感+重调关卡」方案修图:
|
||||
- j1 回廊:`carpet(m, 81, R-11, 15, [0, 8])` —— x89 加缺口。原因:新物理下从 x88 跳台落进 x90 时落点偏右(fx≈2895),满跳第 3 帧就蹭 x91 的「>」刺尖;有 x89 就能走进 x90 从左侧起跳越过对刺门。
|
||||
- j9 L0:`carpet(m, 5, 27, 116, [54])` —— x59 加缺口。原因:矮洞天花板(row 24, x60-75)挡住 x57→x61 四格跳的横向漂移,玩家撞顶后下坠砸原点刺;拆成 57→59→61 两个 2 格跳(短跳 apex≈43px,碰不到洞顶)。
|
||||
- j9 L1:`carpet(m, 9, 13, 108, [27])` —— x36 加缺口。原因:hgap(36,13) 的通道列 36 被 carpet 填了 '^',整门是 3 连刺,从右往左回跳被 x37 的「<」刺别住;补缺口后恢复两段式穿越。
|
||||
- 全部回归绿:solve(23 关终点+存档+苹果全可达)、check/map/smoke/dom-smoke/save/key/spike/settings/editor-wysiwyg/ice/death/jumpdist/save-diag/bot 共 15 项。
|
||||
- 教训(已入 MEMORY.md):① 4 格缺口跳在新物理下能跳但起拍位必须够靠左,跳台落点偏右是隐形杀手;② 实心天花板会挡高跳的横向漂移;③ hgap 通道列必须本身为空,carpet 缺口没对齐就会留一根 '^' 把门变成 3 连刺。
|
||||
|
||||
## 编辑器:去掉「查看属性」工具,改为任意工具点击即看属性(用户要求)
|
||||
- `js/editor.js`:`PALETTE` 删除 `['?', '查看属性', ...]`(调色板 25→24 项,全是真实方块);`buildPalette()` 删掉 '?' 的放大镜字形特例;`act()` 删掉 `sel === '?'` 分支——现在所有点击都先 `selTile = {tx,ty}` 再 `renderProps()`,配合原有「放置不覆盖」规则,拿任何非橡皮方块点击已有格子都只查看不覆盖;空格子则放置新块并显示其属性;橡皮擦与右键保持擦除语义。
|
||||
- 新增回归 `tools/editor-pick-test.mjs`(18 断言):假 DOM 的 addEventListener 真实收句柄,可模拟画布 mousedown;验证 PALETTE/UI 无 '?'、拿 ^/#/% 点 C/T 只查看不覆盖且面板渲染对应字段、拿 O 点空格放置并显属性、橡皮/右键擦除、空态引导文案。注意 renderProps 的字段是 appendChild 子行,断言要拼 `box.innerHTML + children.map(c=>c.innerHTML)`。
|
||||
- `tools/editor-wysiwyg-test.mjs` 清理 '?' 死过滤。
|
||||
- 全套 16 项回归绿(solve 23 关可达不受影响,本次只改编辑器交互)。
|
||||
|
||||
## 重力再降一档 + 去掉跳跃时 kid 身体晃动(用户要求)
|
||||
- **GRAV 0.34 → 0.33**(`js/player.js` PHY + `tools/lib-reach.mjs` 同步)。"稍微调低一点点":单跳 apex≈109px、滞空更久。扫参发现 0.32 断 j2、0.33 断 j6(非单调——6px 状态桶对齐决定窄窗存不存在),选最小步长 0.33。
|
||||
- **j6 修图**:`m.set(44, 15, '.')` 清掉 hgap(43,15) 的 '<' 刺。根因:该对刺门原本只靠「tile45.3(fx≥1448)满跳→tile41.3」这条 2px 宽起拍窗通过;'<' 刺尖会别住起跳(fx<1448 第 3 帧即死),0.33 下 hop 落点整体左移 2px 窗口够不着。清掉后留 ^(43)+>(42) 双刺门,整格起拍窗 + 左右两个方向都稳。修后 j6 状态数 535→934。
|
||||
- **去掉跳跃晃动**:删 `player.js` 起跳/二段的 `squash=1.28/1.22` 拉伸;`sprites.js` 的 `drawKid` 改 `const sq = air ? 1 : p.squash`——空中恒定原始体型,落地挤压(0.72)残余也不得带入空中。落地挤压保留(在地面,不属"跳跃时")。
|
||||
- 教训(已入 MEMORY.md):① 对刺门的侧刺('<'/'>')会把起跳/落点窗切成 2px 级窄窗,求解器 6px 状态桶的对齐就能翻转整关可解性——改物理后遇到"某一跳全灭",先查是不是侧刺别住起拍;② 追这类问题用逐帧 trace(复刻 sim.jump 主循环打印每帧 x/y/vy + deadlyRect),比手算几何可靠得多。
|
||||
- 16 项回归全绿;solve 23 关终点+存档+苹果全可达。
|
||||
|
||||
## JUMP 8.5→8.0 降低跳跃高度(用户:「跳跃的高度太高了,调低点」)
|
||||
- `js/player.js` PHY + `tools/lib-reach.mjs` 同步:JUMP 8.5→8.0。单跳 apex 109.5→97px、水平 139→131px。只降 JUMP 不动 GRAV——保留用户之前要的「小重力飘」手感。
|
||||
- 扫参定位只破坏 j8(存档#4/#5+终点不可达)。逐帧 trace 实证:j8 x83-84 台(row18)→x88-89 台(row16) 这一跳的航线正对 vgap(86,14);`spikeTri` 的 '^' 顶点在格顶 y=480(无收紧),JUMP 8.0 单跳 apex 盒底 479——只差 1px,顶点 (2768,480) 在起跳后 t=21~25 共 4 帧落在玩家盒内,SAT 铁死。JUMP 8.5 时 apex 盒底 466 从容擦过。
|
||||
- 修图(j8 两处,其余 22 关零改动):
|
||||
- `vgap(m, 86, R-8)` → `m.set(86, R-9, 'v')`:去掉 x86 地刺 '^'、保留压顶刺 'v'。试过「x88-89 台加宽到 x87-89」无效(上升段照样死,落点加宽治标不治本)。
|
||||
- x87 加 '-' 台(配合上面修完后的落点 2802 能上台)。
|
||||
- 修后 j8 状态数 307→469,23 关终点+存档+苹果全可达。
|
||||
- 16 项回归全绿。教训已入 MEMORY.md:① apex 盒底与航线 '^' 顶点差 1px 时顶点会连续 4 帧在盒内,改 JUMP/GRAV 后遇到「某一跳全灭」先算 apex 盒底对比航线刺顶点;② 逐帧 trace 复刻 sim.jump 主循环是定位这类问题的唯一可靠手段(手算 SAT 截面连错三次)。
|
||||
|
||||
## JUMP 再降一档 + 下落分手重力 + 零形变(用户三连要求)+ 求解器加固(本次会话主体)
|
||||
用户原话:「跳跃的高度太高了,调低点」→「跳跃高度再调低一点,下落时的重力加速度再明显点,而且kid落地时候依然有拉伸效果,还是不行」。
|
||||
|
||||
**物理落地**(`js/player.js` + `tools/lib-reach.mjs` 同步):
|
||||
- JUMP 8.0→7.5:单跳 apex 97→85px、水平 131→118.8px(jumpdist 实测)。
|
||||
- 新增 `GRAV_FALL: 0.55`:上升 0.33 轻、下落 0.55 重(分手重力)。落地前一帧竖直速度 8.9px/帧。
|
||||
- **squash 形变全部删除**:`player.js` 去掉 squash 字段/起跳赋值/落地挤压逻辑;`sprites.js` 的 `drawKid` 按原始 11×21 画;`editor.js` 预览桩同步删字段。用户两次强调落地拉伸也不要。
|
||||
|
||||
**求解器三个加固**(`tools/lib-reach.mjs`,solve/reach-diag 默认值同步):
|
||||
- RELSET [0,4,8,14] → [0,4,5,6,8,14]:vgap 夹缝需要"第 5/6 帧松键"的短跳(apex 32~43px 窗口)。实证:rel=4 t=7 盒右沿蹭地刺左坡 2.6px;rel=6 t=11 盒顶擦垂刺尖 0.6px;只有 rel=5 两边都躲开(j2 x16);j7 顶层 x52 夹缝则要 rel=6。
|
||||
- **fy 规范化(canon)**:落点常比地面高零点几 px(1535.5 vs 1536),与精确落点同 3px 桶——先占桶者赢,走链被错位几 px 的跳链顶掉。加 rel=6 后 j2 状态数从 1572 暴跌到 80 就是这么来的。push() 里按 canStand 门控吸附到 32 倍数。
|
||||
- 状态桶 3px(上轮已改)。
|
||||
|
||||
**关卡重调**(`js/levels/jump.js`,核心矛盾:JUMP 7.5 + GRAV_FALL 0.55 下 3 连刺=96px 的起拍窗只有 0~1 帧,实测不可玩):
|
||||
- **carpet 缺口间距 4→3**(3 连刺→2 连刺=64px,射程余量 13→55px):一行改动全局生效。
|
||||
- j2 五处显式 gaps(井口/左端出口的 3 连刺必须拆,walk 限制使起拍位比所需位窄 1~2px):
|
||||
- L0:`carpet(m, 5, 47, 50, [1, 18])` 保持(x25-27 已被间距 3 拆成 2 连刺)。
|
||||
- L2:`[1, 11, 31]` = x12 拆井口 3 连刺;x22/x42 补 hgap 夹缝通道列(原来被 carpet 填 '^',整门变 3 连刺且左侧落点是 4 格跳 128px 超射程)。
|
||||
- L3:`[0]` = x10 拆左端 3 连刺(左行跳落点盒右沿差 0.8px 蹭 x10 左坡;L1 同位置能过是因 vgap(12) 清空了 x10-14,L3 没有)。
|
||||
- L4:`[1, 41]` = x12 拆井口 3 连刺;x52 补 hgap 夹缝通道列。
|
||||
- 修后 j2 状态数 80→2421(10/10 存档+终点),23 关全可达。
|
||||
|
||||
**验证**:solve 23 关终点+存档+苹果全可达;check/map/smoke/dom-smoke/save/key/spike/settings/editor-wysiwyg/editor-pick/ice/death/jumpdist/save-diag/bot 共 15 项全绿。
|
||||
|
||||
## GRAV 0.33→0.29 上升再飘一档(用户:「跳跃的重力参数再飘点」)
|
||||
- `js/player.js` PHY + `tools/lib-reach.mjs` 同步:GRAV 0.33→0.29(仅上升段,GRAV_FALL 0.55 不变)。单跳 apex 85→91px、水平 118.8→122px。
|
||||
- 本轮零修图:23 关全可达(状态数与上轮持平微增)。原因:上轮已把 carpet 缺口间距改 3 格(2 连刺=64px),射程余量充裕,上升更飘不触任何窄窗。
|
||||
- 16 项回归全绿。至此手感链:移速 2.7 / 上升重力 0.29 / 下落重力 0.55 / JUMP 7.5。
|
||||
Reference in new issue
Block a user