返回博客

Godot 4 2D 角色移动:从输入到物理的全流程实现

2026/9/63 分钟阅读

Godot 4 2D 角色移动:从输入到物理的全流程实现

Godot 4 中,2D 角色移动最稳健的方案是使用 CharacterBody2D 配合 move_and_slide() 方法。我将输入向量标准化后乘以速度系数,并在 _physics_process 中应用该速度,这样可以完美处理平台跳跃、碰撞检测以及摩擦力模拟,避免角色穿透墙壁或在地面滑行过远。

核心节点选择:为什么是 CharacterBody2D?

很多人会问能不能用 Node2DRigidBody2D 自己做移动。老实说,如果是简单的背景物体或者完全受物理引擎控制的弹球,这两种确实合适。但一旦涉及到“角色”——需要响应玩家输入、有明确的上下方向、需要防止穿墙——CharacterBody2D 是唯一的选择。

我一般会把根节点设为 CharacterBody2D,因为它的物理步进由游戏循环主动驱动,而不是像刚体那样被动接受物理世界的冲量。这意味着我在每一帧都能精确控制角色的速度,而不是被物理引擎“带跑偏”。

输入配置与速度控制

在 Godot 4 中,建议使用新的 InputMap 系统来绑定按键。比如我定义了一个名为 move_right 的动作,绑定键盘的 D 键和方向键右。

在脚本中,我不会直接在 _process 里写死按键检测,而是创建一个可配置的移动速度变量。我倾向于将最大移动速度和加速度分开设置,这样手感更细腻。

extends CharacterBody2D

@export var move_speed: float = 400.0
@export var friction: float = 10.0

func _physics_process(delta: float) -> void:
	var direction := Input.get_axis("move_left", "move_right")
	
	# 只有当玩家有输入时才改变水平速度
	if direction != 0:
		velocity.x = lerp(velocity.x, direction * move_speed, friction * delta)
	else:
		# 没有输入时,应用摩擦力让角色慢慢停下
		velocity.x = move_toward(velocity.x, 0, friction * delta)
	
	move_and_slide()

这里我用 lerp 来平滑速度变化,相比直接赋值,角色启动和停止时会有更自然的加减速感。如果你追求复古的街机手感,直接 velocity.x = direction * move_speed 会更干脆。

跳跃与重力的正确处理

2D 平台游戏中,重力处理是关键。Godot 4 默认会将 Gravity Scale 应用于 Y 轴,所以我通常只处理水平移动,垂直方向交给重力。

为了确保角色只能在地面跳跃,我需要在代码中检测是否接地。is_on_floor()CharacterBody2D 提供的一个便捷方法,它在碰撞检测返回 COLLISION_FLOOR 时生效。

@export var jump_force: float = -800.0

func _physics_process(delta: float) -> void:
	# ... 水平移动代码保持不变 ...
	
	if Input.is_action_just_pressed("jump") and is_on_floor():
		velocity.y = jump_force
	
	move_and_slide()

值得注意的是,move_and_slide() 必须在所有速度修改之后调用。如果你在修改垂直速度之前先调用了它,角色可能会因为当帧已经处理完物理步进而无法正确响应跳跃输入。我在调试时经常遇到这种“跳不起来”的问题,最后发现都是调用顺序搞错了。

常见陷阱:速度溢出与地面粘连

新手最容易犯的错误是直接对 global_position 进行赋值操作,比如 global_position += Vector2.RIGHT * speed * delta。这种做法完全绕过了物理引擎,角色会无视碰撞体直接穿墙。我见过太多这样的案例,最后不得不重写整个移动逻辑。

另一个坑是“地面粘连”。如果碰撞体的材质摩擦系数设置得过高,或者在地面上水平速度没有正确归零,角色停手后还会继续滑行。解决这个只需确保在非水平输入时,水平速度能迅速衰减至零,就像我在上面代码示例中用 move_toward 处理的那样。

下一步优化方向

掌握了基础移动后,你可以尝试加入斜向移动的速度缩放(防止斜向跑得更快),或者引入 AnimationTree 来根据速度状态切换行走、奔跑和待机动画。对于更复杂的平台动作,还可以进一步研究 snap_velocity 来处理边缘对齐问题。

原文出处

本文首发于 Godot 4 2D 角色移动:从输入到物理的全流程实现https://lyxq.com.cn/zh/blog/godot-4-2d-character-movement

转载或引用请注明出处,商业使用请联系作者获得授权。