跳跃手感:8 个参数,和它们为什么这样取值

土狼时间、跳跃缓冲、可变跳跃高度、上升下降重力差、顶点悬停、落地压缩、尘土与停顿——每个参数给一个起始值,并解释它解决的是什么问题。

手感物理Godot

「手感」不是玄学,它是一串可以量化的宽容度。玩家按下跳跃键的那一刻,输入是离散的,物理是连续的,中间那层翻译决定了游戏跟不跟手。

下面 8 个参数是像素猫小屋最终采用的数值,来自三十多次试玩调整。它们不是标准答案,但每一个都对应一个具体的失败体验。

参数表

参数取值解决的问题
土狼时间0.10 s走出平台边缘后仍能起跳
跳跃缓冲0.12 s落地前按下跳跃,落地瞬间自动起跳
起跳速度-330 px/s跳跃高度约 56 px,等于 3.5 个猫身高
上升重力980 px/s²上升过程偏轻
下降重力1500 px/s²下落更快,避免发飘
松键截断速度乘 0.45点按小跳,长按大跳
顶点悬停0.08 s,重力乘 0.6最高点停留,给玩家判断时间
落地停顿0.06 s落地瞬间的重量感

为什么是这几个数

土狼时间 0.1 秒大约是 6 帧。低于 0.05 秒玩家感知不到,高于 0.15 秒会出现「明明已经掉下去却又跳起来」的诡异感。

跳跃缓冲 0.12 秒比土狼时间稍长,因为玩家的容错心理是「我按了就该算」。这两个值不需要相等,但差距不要超过 2 倍。

下降重力是上升的 1.5 倍,这是最划算的一条:上升慢让玩家看清落点,下降快让落地干脆。多数游戏落在 1.2 到 2.0 之间,超过 2.2 会像掉进水里。

代码:一次写对

gdscript
extends CharacterBody2D

@export var jump_velocity := -330.0
@export var gravity_up := 980.0
@export var gravity_down := 1500.0
@export var coyote_time := 0.10
@export var jump_buffer := 0.12
@export var apex_threshold := 60.0
@export var apex_gravity_scale := 0.6

var coyote := 0.0
var buffer := 0.0

func _physics_process(delta: float) -> void:
    if is_on_floor():
        coyote = coyote_time
    else:
        coyote = maxf(coyote - delta, 0.0)

    if Input.is_action_just_pressed("jump"):
        buffer = jump_buffer
    else:
        buffer = maxf(buffer - delta, 0.0)

    if buffer > 0.0 and coyote > 0.0:
        velocity.y = jump_velocity
        buffer = 0.0
        coyote = 0.0
        squash(0.8, 1.2)

    # 松键截断:只在上升段生效
    if Input.is_action_just_released("jump") and velocity.y < 0.0:
        velocity.y *= 0.45

    var g := gravity_up if velocity.y < 0.0 else gravity_down
    if absf(velocity.y) < apex_threshold:
        g *= apex_gravity_scale
    velocity.y += g * delta
    velocity.y = minf(velocity.y, 900.0)

    move_and_slide()

    if is_on_floor() and velocity.y >= 0.0:
        squash(1.15, 0.85)

注意两个细节:松键截断只作用在上升段,否则会把下落也截断;顶点悬停用「接近 0 的速度」判断,而不是固定高度,这样小跳和大跳都有悬停。

视觉:手感的一半在动画里

数值只解决跟手,重量感要靠动画补:

  • 起跳:纵向拉伸 1.2 倍,横向压缩 0.85,持续 0.08 秒
  • 下落:轻微拉长,随速度增加
  • 落地:先压扁到 0.8,再 0.1 秒回弹到 1.05,最后回 1
  • 尘土:落地时在脚下生成 3 到 5 个粒子,向左上、正上、右上散开,寿命 0.25 秒
  • 相机:落地时向下偏移 2 px,0.12 秒回位;不要做整屏震动,会很廉价

两个反直觉的结论

不要给跳跃加加速度曲线。 很多人想在起跳瞬间做缓入,结果玩家觉得按键有延迟。起跳必须是瞬时速度赋值,宽容度交给缓冲和截断。

不要做二段跳,除非关卡为它设计。 二段跳会让所有平台间距失去意义,第一版我加了,第二天就删了——它让土狼时间变得没必要,也让坠落不再有惩罚。

怎么验证

把游戏给你自己玩 10 分钟,只看一件事:有没有哪次死亡你觉得「不是我的错」? 有,就是某个参数还不够宽容。记录下来,一次只调一个,调完再玩 10 分钟。