如何实现Godot角色平滑跳跃?解决角色瞬移升空后缓慢下落问题
嘿,我来帮你搞定这个角色瞬移+下落诡异的问题!先拆解下你当前代码里的核心问题:
- 两次调用
move_and_slide:第一次你用direction * 100直接推角色,这相当于瞬间给了一个超大速度,直接把角色“甩”到空中;第二次又用speed再推一次,完全打乱了正常的移动逻辑。 - 重力处理错误:你直接给
direction减去transform.basis.y(也就是向下的方向),这不是真实的重力——重力应该是持续的加速度,而不是瞬间改变方向。 - 跳跃逻辑混在方向里:把跳跃的向上方向和移动方向混在一起计算,导致速度叠加混乱,出现瞬移。
下面是优化后的代码,完全解决这些问题,实现平滑的移动和跳跃:
# 先在脚本顶部定义可调整的参数,方便你根据游戏需求微调 @export var move_speed: float = 5.0 # 地面移动速度 @export var gravity: float = 12.0 # 重力加速度 @export var jump_force: float = 5.0 # 跳跃初始速度 var velocity: Vector3 = Vector3.ZERO # 用单独变量管理速度,保留帧间状态 func _physics_process(delta: float) -> void: # 1. 处理重力:只有不在地面时,持续叠加重力加速度 if not is_on_floor(): velocity.y -= gravity * delta # 2. 处理前后移动输入 var input_dir: Vector3 = Vector3.ZERO if Input.is_action_pressed("mf"): input_dir -= transform.basis.z # 向前 elif Input.is_action_pressed("b"): input_dir += transform.basis.z # 向后 # 归一化输入方向,避免斜向移动(如果后续加左右键)速度过快 if input_dir.length() > 0.01: input_dir = input_dir.normalized() # 设置水平方向的速度 velocity.x = input_dir.x * move_speed velocity.z = input_dir.z * move_speed else: # 没有输入时重置水平速度,防止角色一直滑动 velocity.x = 0.0 velocity.z = 0.0 # 3. 处理跳跃:只有在地面时才能触发跳跃,直接给向上的初始速度 if Input.is_action_pressed("JUMP") and is_on_floor(): velocity.y = jump_force # 4. 只调用一次move_and_slide,它会自动处理碰撞、地面检测,并返回更新后的速度 velocity = move_and_slide(velocity, Vector3.UP)
关键优化点解释:
- 用
velocity变量管理速度:这样能保留上一帧的速度状态,比如重力会持续让角色下落速度越来越快,而不是瞬间改变方向。 - 重力采用加速度方式:每帧叠加
gravity * delta,让下落过程是平滑的加速,符合真实物理逻辑。 - 跳跃直接设置y轴速度:给一个瞬间的向上初始速度,这样跳跃的手感会很自然,不会出现瞬移。
- 单次调用
move_and_slide:这个函数内部已经处理了碰撞修正、地面检测等逻辑,多次调用会导致速度叠加异常。 - 输入归一化:避免斜向移动时速度翻倍,同时无输入时重置水平速度,防止角色“滑溜溜”停不下来。
你可以根据自己的游戏风格调整顶部的参数数值,比如增大jump_force让跳得更高,减小gravity让下落更慢。另外要确保你的角色有正确的碰撞体(比如CapsuleShape3D),这样is_on_floor()才能准确检测到地面。
内容的提问来源于stack exchange,提问作者Rares Cosma




