Godot 4 CharacterBody2D 角色移动:输入、碰撞与八方向控制实战 📅 2026/7/28 17:25:02 Godot 4 CharacterBody2D 角色移动输入、碰撞与八方向控制实战刚接触 Godot 4 时很多人会直接修改Sprite2D.position来移动玩家。画面确实动了但角色遇到墙体时仍会穿过去因为精灵只负责显示不负责物理运动。这篇文章从一个最小的俯视角角色场景出发使用CharacterBody2D、CollisionShape2D和Input.get_vector()完成方向输入、等速斜向移动以及滑动碰撞。最终代码可以直接作为 RPG、射击或探索类 2D 游戏的移动基础。一、先分清三种物理主体Godot 4 中常见的二维物理主体有三种CharacterBody2D速度由玩家代码或 AI 决定适合角色。StaticBody2D提供固定阻挡适合墙壁、地面和不可移动障碍。RigidBody2D主要由重力、碰撞与外力推动适合箱子等物理对象。关键不在于对象看起来会不会动而在于“谁决定它如何运动”。玩家角色需要稳定、可预测的输入响应因此这里选择CharacterBody2D。二、搭建玩家场景新建一个二维场景将根节点设为CharacterBody2D命名为Player。添加两个子节点Player (CharacterBody2D) ├── AnimatedSprite2D └── CollisionShape2DAnimatedSprite2D负责画面CollisionShape2D负责物理轮廓。两者应当分离头发、武器和披风等装饰像素通常不该参与阻挡否则玩家会觉得“明明没碰到墙却被卡住”。在CollisionShape2D的Shape属性中创建矩形、圆形或胶囊形状优先覆盖角色的主体区域。俯视角角色没有明确的地面方向可以把CharacterBody2D的Motion Mode设为Floating。三、配置输入动作打开Project → Project Settings → Input Map建立四个动作动作名推荐按键move_leftA、左方向键move_rightD、右方向键move_upW、上方向键move_downS、下方向键代码只依赖动作名不直接依赖某个键。以后接入手柄或允许玩家改键时不必重写移动逻辑。四、编写八方向移动代码给Player创建并附加player_controller.gdextends CharacterBody2D export var speed: float 240.0 func _physics_process(_delta: float) - void: var input_direction : Input.get_vector( move_left, move_right, move_up, move_down ) velocity input_direction * speed move_and_slide()这段代码只有三个关键步骤Input.get_vector()把四个动作合成为一个Vector2。方向向量乘以speed得到角色速度。move_and_slide()提交当前物理帧的速度并处理滑动碰撞。不要再额外写position velocity * delta。CharacterBody2D的运动应交给move_and_slide()否则可能避开预期的碰撞处理。五、为什么斜着走不会更快如果分别判断四个按键再把 X、Y 速度都设为speed角色斜向移动时的合速度会大于水平速度。Input.get_vector()会把最终向量长度限制在 1 以内因此右下方向大约是(0.707, 0.707)乘以速度后仍保持统一的最大移动速度。这也是它比手工堆叠四个if更适合八方向控制的原因。六、添加可碰撞的障碍在测试场景中添加StaticBody2D并给它添加Wall (StaticBody2D) ├── Sprite2D └── CollisionShape2D运行后让玩家斜着撞向墙角。正确结果是角色不会穿过墙体仍有切向速度时角色会沿墙滑动松开输入后角色立即停止。如果角色直接穿墙依次检查玩家和墙体是否都有可用的CollisionShape2DShape 是否为空玩家与墙体的 Collision Layer 和 Mask 是否互相匹配是否错误地手动修改了positionmove_and_slide()是否在_physics_process()中执行。七、加入平滑加速与减速即时停止适合强调精准操作的游戏。如果希望移动更柔和可以让速度逐步接近目标值extends CharacterBody2D export var max_speed: float 240.0 export var acceleration: float 1200.0 export var deceleration: float 1600.0 func _physics_process(delta: float) - void: var input_direction : Input.get_vector( move_left, move_right, move_up, move_down ) var target_velocity : input_direction * max_speed var rate : acceleration if not input_direction.is_zero_approx() else deceleration velocity.x move_toward(velocity.x, target_velocity.x, rate * delta) velocity.y move_toward(velocity.y, target_velocity.y, rate * delta) move_and_slide()move_toward()按固定变化率逼近目标速度delta用来抵消帧率差异。加速度和减速度分开后可以做出“起步柔和、松手迅速”的手感。八、常见错误错误一用Sprite2D当角色根节点它可以显示和移动但不会自动获得角色碰撞运动能力。需要把CharacterBody2D作为物理主体。错误二碰撞轮廓完全包住装饰像素过大的形状容易让角色在狭窄通道和墙角处被卡住。物理轮廓应服务于玩法手感而不是逐像素描边。错误三一个物理帧多次调用move_and_slide()先计算完整速度再调用一次即可。把不同方向拆成多次移动会让碰撞结果难以预测。错误四把velocity再乘一次deltavelocity的单位是每秒像素数move_and_slide()会按物理步处理。只有加速度的变化量需要乘delta。九、知识主线与参考本文的节点选型、碰撞轮廓、Floating 运动模式和物理移动方法来自《大鹏 Godot 4 游戏开发入门》第 5 章中“配置可移动物理角色”与“编写物理角色移动代码”两节。文章把这些知识整理成一个可独立复现的俯视角控制器没有把同题搜索结果当作技术事实。十、完整验收清单单独按 W、A、S、D 时方向正确。同时按两个方向时速度没有变快。松开输入后按预期立即停止或平滑减速。碰到墙体不会穿透。斜撞墙体时可以沿墙滑动。调整窗口刷新率后移动速度基本一致。总结完成这些检查后一个可复用的 Godot 4 二维角色移动底座就建立好了。下一步可以把velocity交给AnimatedSprite2D让站立和移动动画随真实运动状态自动切换。