让扒墙更顺:默认贴墙 + 多段跳的扩展

2026-09-05 · unity

续《墙滑与墙跳》的一次手感改造。原来墙滑是”主动贴墙”——要按住朝墙方向才扒得上去;我改成”默认贴墙”——扒上墙后只要不按远离墙的方向,就持续扒着缓慢下落,不用按住朝墙也能跳。这篇记三处判定改动、一个 ||/&& 的逻辑坑,以及这次改动顺手想清楚的多段跳设计(它和冲刺次数的系统是同一个套路)。

为什么改

原手感烦的点:墙在右边,得一直按住 D 才扒着;一旦松键就掉下去;想墙跳还得按住朝墙方向再按跳。对”贴着墙观察/等时机”这种动作很不宽容。 再次体验了Celeste和灾厄逆刃,墙爬还是得爽,有些机能不能限制太狠了,只会一味限制只能说明我对自己搭关卡没信心。

因此本篇讲的就是改成如下墙爬:

  1. 扒上墙后,松手也扒着,缓慢下落。
  2. 想走开才需要按远离墙的方向。
  3. 扒着的时候,不用特意按朝墙方向,按跳就是墙跳。

贴墙是默认状态,离开是主动动作

三处判定改动

全部在 PlayerController.cs,每处一行的规模。

方向约定:墙在左 wallSlide = -1,朝墙方向就是 wallSlide,远离墙方向是 -wallSlide。

① 进入墙滑:从”按住朝墙”改成”碰到就贴”

// 旧:if (wallSlide != 0 && horizontalMoveLastFrame == wallSlide)
if (wallSlide != 0)   // 下落中碰到墙就贴,不再要求按住朝墙

② 留在墙滑:从”松键就走”改成”按反方向才走”

// 旧:if (wallSlide == 0 || horizontalMoveLastFrame != wallSlide)
if (wallSlide == 0 || horizontalMoveLastFrame == -wallSlide)   // 没墙 或 按了远离墙 → 才脱落

③ 墙跳:从”按住朝墙”改成”没按远离墙就行”

// 旧:if (wallSlide != 0 && (horizontalMoveLastFrame == wallSlide || wallJumpGraceTimer > 0f))
if (wallSlide != 0 && horizontalMoveLastFrame != -wallSlide)   // 挨着墙 且 没按远离墙 → 可墙跳

|| 写成了该 &&

改动时把 ③ 想错了一个符号:

if (wallSlide != 0 || horizontalMoveLastFrame != -wallSlide)  

现象:玩家按住 A/D(任意方向),就能无限起跳。

为什么 || 会这样:|| 是”两个条件满足一个就算”。

修复:|| 改回 &&(有墙 且 没按反方向):

if (wallSlide != 0 && horizontalMoveLastFrame != -wallSlide)

这种bug只能靠亲身测试出来,且很容易出这种逻辑错误。每行判定代码的改动都得想清楚再改。

多段跳?

这次改动让我重新看了跳跃的部分,多段跳其实不需要一堆参数,只需要和冲刺次数一模一样的”上限 + 剩余”模式:

1. PlayerStats 加上限:

public int maxJumps = 1;   // 1 = 单段;以后改成 2 就是双段跳

2. PlayerController 记录下:

private int maxJumps;    // 上限,每次 RecalculateStats 重算
private int jumpsLeft;   // 当前还剩几次可跳

3. 充能与消耗三处:

4. 物品加成:想在 SO 物品系统里加”额外跳跃”,和 dashBonus 一字不差:

// ItemDefinition / IItemEffect 加 int JumpBonus
// RecalculateStats:maxJumps = baseStats.maxJumps; ... maxJumps += e.JumpBonus;

这个扩展不是”加 N 个布尔/每个额外跳一个字段”,而是把”跳跃”从”一次性的地面事件”升级成”可消耗的次数资源”。这类”次数型能力”(dash、未来的跳跃、甚至受击无敌次数)都该用这一个模式——SO 存上限、账本存剩余、效果用加法叠上限。系统统一。

反思与总结