Godot 4 角色移动为什么要用 CharacterBody2D?从 Input Map 到碰撞滑动一次讲透

OK,OK,大家好,欢迎大家来到大鹏 AI 教育,我是张大鹏。

很多同学第一次做角色移动,会直接修改 position。角色确实动了,但遇到墙会穿过去,斜向移动还可能更快。问题不是少写了一句代码,而是从一开始就绕开了 Godot 的输入和物理系统。

这篇文章只解决一个完整问题:让 2D 角色接受键盘输入,保持统一速度,并能沿障碍物自然滑动。

先看完整思路

角色移动可以拆成四步:

  • 🎮 Input Map 把具体按键抽象成动作
  • 🧭 Input.get_vector() 把四个动作合成为方向向量
  • 🚀 把方向乘以速度,写入 velocity
  • 🧱 move_and_slide() 完成移动、碰撞与滑动

这四步分别解决输入配置、方向计算、速度控制和物理碰撞。职责分开后,键盘改成手柄时,角色脚本几乎不用动。

第一步:不要在脚本里写死按键

打开"项目 > 项目设置 > 输入映射",创建下面四个动作:

  • ⬅️ move_left
  • ➡️ move_right
  • ⬆️ move_up
  • ⬇️ move_down

然后分别绑定方向键或 W、A、S、D。

为什么要多做这一层?因为脚本关心的是"向左移动"这个意图,不应该关心它来自 A 键、左方向键还是手柄摇杆。

第二步:选择 CharacterBody2D

创建角色根节点时选择 CharacterBody2D

它适合由脚本直接控制的角色。常见的三个物理节点可以这样理解:

  • 🧍 CharacterBody2D:玩家、敌人等主动移动的角色
  • 🧱 StaticBody2D:墙、地面等不主动移动的障碍
  • 📦 RigidBody2D:箱子、球等主要由物理引擎推动的物体

角色下还需要可视节点和 CollisionShape2D。碰撞形状尽量贴合角色身体,不要把透明留白也包进去,否则玩家会感觉"还没碰到墙就被挡住了"。

第三步:用一个向量处理四方向输入

把脚本挂到 CharacterBody2D

gdscript 复制代码
extends CharacterBody2D

@export var speed: float = 200.0

func _physics_process(_delta: float) -> void:
    var direction := Input.get_vector(
        "move_left",
        "move_right",
        "move_up",
        "move_down"
    )

    velocity = direction * speed
    move_and_slide()

Input.get_vector() 会返回长度不超过 1 的向量。只按右键时大约是 (1, 0),同时按右键和下键时会得到归一化后的斜向量。

这正好解决了常见的"斜向移动更快"。如果分别给 x、y 都赋值为 speed,斜向速度会变成 speed × √2。使用 get_vector() 后,方向长度受到限制,再乘速度即可保持各方向一致。

第四步:让角色碰墙后继续滑动

场景里放一个 StaticBody2D,为它添加 CollisionShape2D。它就是角色要碰撞的墙。

关键不是自己计算"撞墙后退多少",而是调用:

gdscript 复制代码
move_and_slide()

它会读取当前 velocity,移动角色,处理碰撞,并保留沿碰撞表面的有效分量。所以角色斜着撞墙时,不会僵在原地,而会顺着墙继续滑动。

注意,Godot 4 的 CharacterBody2D.move_and_slide() 不需要把 velocity 当参数传入。velocity 是节点属性,方法会直接使用并在碰撞后更新它。

停止移动时要不要减速

上面的写法松开按键后立即停止,适合响应直接的俯视角角色。如果想做带惯性的移动,可以把赋值改为逐渐逼近:

gdscript 复制代码
@export var acceleration: float = 1200.0

func _physics_process(delta: float) -> void:
    var direction := Input.get_vector(
        "move_left",
        "move_right",
        "move_up",
        "move_down"
    )
    var target_velocity := direction * speed
    velocity = velocity.move_toward(target_velocity, acceleration * delta)
    move_and_slide()

这里的 delta 很重要。它让加速度按时间计算,不会因为电脑帧率不同而明显改变手感。

最容易踩的四个坑

  • ❌ 在 _process() 里处理物理移动

    ✅ 放到 _physics_process(),让移动与固定物理帧同步。

  • ❌ 直接修改 position

    ✅ 给 velocity 赋值并调用 move_and_slide()

  • ❌ Input Map 名称和代码不一致

    ✅ 动作名逐字核对,大小写也要一致。

  • ❌ 墙只有图片,没有碰撞形状

    StaticBody2D 和角色都必须具有有效的 CollisionShape2D

验收清单

  • ✅ W、A、S、D 和方向键都能移动
  • ✅ 水平、垂直、斜向速度一致
  • ✅ 松开按键后行为符合设计
  • ✅ 角色不能穿过静态障碍
  • ✅ 斜着撞墙时能沿墙滑动
  • ✅ 修改 Input Map 后不需要改角色移动代码

小结

一套可靠的 Godot 4 角色移动,不是"坐标加减法",而是一条清楚的协作链:Input Map 表达意图,Input.get_vector() 生成方向,velocity 表达速度,move_and_slide() 负责物理结果。

你现在更想把这套移动扩展成八方向动画,还是加入加速、减速和冲刺?欢迎在评论区告诉我,我会优先拆解大家最需要的部分。

参考资料

相关推荐
Python私教2 小时前
Godot 4 TileMapLayer 入门:从图集、碰撞到可玩的 2D 关卡
godot
Python私教7 小时前
Godot图片怎么导入?PNG、压缩、Mipmap与Reimport一次讲清
游戏引擎·godot
Python私教8 小时前
Blender模型导入Godot完整教程:GLB、BLEND与继承场景怎么选
运维·godot·blender
寒水馨8 小时前
Linux下载、安装godot-4.7.1-stable(附安装包Godot_v4.7.1-stable_linux.x86_64.zip)
linux·游戏引擎·godot·游戏开发·2d游戏·3d游戏·godot engine
寒水馨11 小时前
macOS下载、安装godot-4.7.1-stable(附安装包Godot_v4.7.1-stable_macos.universal.zip)
macos·3d·游戏引擎·godot·跨平台·游戏开发·2d
Python私教1 天前
Godot怎么下载和安装?零基础完成第一次启动
人工智能·游戏·godot
Python私教6 天前
我用 AI 做出了第一个 Godot 贪吃蛇
人工智能·游戏引擎·godot
郝学胜-神的一滴9 天前
中级OpenGL教程 020:巧用数组与循环实现多点点光源渲染,告别冗余代码重构方案
c++·unity·游戏引擎·godot·图形渲染·unreal
KillJUMP14 天前
SDF函数
godot·着色器