14. 玩家角色创建与控制
2026/4/14大约 5 分钟
玩家角色创建与控制
玩家角色是游戏的核心
玩家角色就像游戏世界里的"你"。玩家通过控制这个角色来体验游戏——移动、跳跃、攻击、探索。一个手感好的角色控制,能让玩家沉浸其中;手感差的控制,会让玩家立刻放弃游戏。
所以,玩家角色的控制是整个游戏开发中最值得花时间打磨的部分。
创建玩家场景
在 Godot 里,玩家角色通常由以下节点组成:
各节点的作用:
- CharacterBody3D:专门为"可以移动的角色"设计的节点,内置了移动和碰撞处理
- MeshInstance3D:显示角色的 3D 模型(外观)
- CollisionShape3D:定义角色的碰撞范围(物理边界,看不见但很重要)
- Camera3D:摄像机,决定玩家看到的视角
- AnimationPlayer:控制角色的动画(走路、跳跃、攻击等)
创建步骤
- 在场景面板点击 "+" 新建场景
- 选择
CharacterBody3D作为根节点,重命名为Player - 添加子节点
MeshInstance3D,在属性面板选择一个 Mesh(比如CapsuleMesh) - 添加子节点
CollisionShape3D,选择CapsuleShape3D - 保存为
Player.tscn
输入处理
Godot 使用输入映射(Input Map)来处理玩家操作。你可以在"项目设置 → 输入映射"里定义动作名称,然后在代码里检测这些动作。
常用的输入检测方法:
| 方法 | 说明 | 适用场景 |
|---|---|---|
Input.IsActionPressed("action") | 持续按住时返回 true | 移动、持续射击 |
Input.IsActionJustPressed("action") | 刚按下那一帧返回 true | 跳跃、单次攻击 |
Input.IsActionJustReleased("action") | 刚松开那一帧返回 true | 蓄力释放 |
推荐的输入映射配置
在"项目设置 → 输入映射"里添加以下动作:
move_left:键盘 A 或 左方向键move_right:键盘 D 或 右方向键move_up:键盘 W 或 上方向键(俯视游戏用)move_down:键盘 S 或 下方向键(俯视游戏用)jump:键盘 空格 或 手柄 A 键attack:键盘 J 或 鼠标左键
2.5D 移动控制
2.5D 游戏有两种常见的移动方式:
横版游戏移动(左右 + 跳跃)
就像魂斗罗、超级马里奥——角色只能左右移动,可以跳跃。
俯视游戏移动(上下左右)
就像3D割草、塞尔达传说——角色可以向四个方向移动,没有跳跃。
横版角色控制器完整代码
C#
using Godot;
public partial class Player : CharacterBody3D
{
// 移动速度(单位:米/秒)
[Export] public float MoveSpeed = 5.0f;
// 跳跃力度
[Export] public float JumpVelocity = 8.0f;
// 重力加速度(向下)
private float _gravity = ProjectSettings.GetSetting("physics/3d/default_gravity").AsSingle();
// 当前动画状态
private string _currentAnimation = "idle";
private AnimationPlayer _animPlayer;
public override void _Ready()
{
_animPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
}
public override void _PhysicsProcess(double delta)
{
var velocity = Velocity;
// 1. 应用重力(如果不在地面上,就往下掉)
if (!IsOnFloor())
{
velocity.Y -= _gravity * (float)delta;
}
// 2. 处理跳跃(只有在地面上才能跳)
if (Input.IsActionJustPressed("jump") && IsOnFloor())
{
velocity.Y = JumpVelocity;
}
// 3. 处理左右移动
float direction = 0;
if (Input.IsActionPressed("move_right")) direction += 1;
if (Input.IsActionPressed("move_left")) direction -= 1;
velocity.X = direction * MoveSpeed;
// 4. 更新速度并移动
Velocity = velocity;
MoveAndSlide();
// 5. 更新动画
UpdateAnimation(direction);
}
private void UpdateAnimation(float direction)
{
string newAnim;
if (!IsOnFloor())
newAnim = "jump";
else if (direction != 0)
newAnim = "walk";
else
newAnim = "idle";
if (newAnim != _currentAnimation)
{
_currentAnimation = newAnim;
_animPlayer?.Play(_currentAnimation);
}
}
}GDScript
extends CharacterBody3D
# 移动速度(单位:米/秒)
@export var move_speed: float = 5.0
# 跳跃力度
@export var jump_velocity: float = 8.0
# 重力加速度
var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
var current_animation: String = "idle"
@onready var anim_player = $AnimationPlayer
func _physics_process(delta):
# 1. 应用重力(如果不在地面上,就往下掉)
if not is_on_floor():
velocity.y -= gravity * delta
# 2. 处理跳跃(只有在地面上才能跳)
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = jump_velocity
# 3. 处理左右移动
var direction = 0.0
if Input.is_action_pressed("move_right"): direction += 1
if Input.is_action_pressed("move_left"): direction -= 1
velocity.x = direction * move_speed
# 4. 移动
move_and_slide()
# 5. 更新动画
update_animation(direction)
func update_animation(direction: float):
var new_anim: String
if not is_on_floor():
new_anim = "jump"
elif direction != 0:
new_anim = "walk"
else:
new_anim = "idle"
if new_anim != current_animation:
current_animation = new_anim
if anim_player:
anim_player.play(current_animation)俯视角色控制器完整代码
C#
using Godot;
public partial class PlayerTopDown : CharacterBody3D
{
[Export] public float MoveSpeed = 5.0f;
private AnimationPlayer _animPlayer;
private string _currentAnimation = "idle";
public override void _Ready()
{
_animPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
}
public override void _PhysicsProcess(double delta)
{
// 获取输入方向(返回一个 -1 到 1 之间的向量)
var inputDir = Input.GetVector("move_left", "move_right", "move_up", "move_down");
// 将 2D 输入方向转换为 3D 移动方向(俯视游戏在 XZ 平面移动)
var direction = new Vector3(inputDir.X, 0, inputDir.Y).Normalized();
if (direction != Vector3.Zero)
{
// 移动
Velocity = direction * MoveSpeed;
// 让角色朝向移动方向
LookAt(Position + direction, Vector3.Up);
UpdateAnimation("walk");
}
else
{
// 减速停止(平滑停止)
Velocity = Velocity.Lerp(Vector3.Zero, 0.2f);
UpdateAnimation("idle");
}
MoveAndSlide();
}
private void UpdateAnimation(string animName)
{
if (animName != _currentAnimation)
{
_currentAnimation = animName;
_animPlayer?.Play(_currentAnimation);
}
}
}GDScript
extends CharacterBody3D
@export var move_speed: float = 5.0
var current_animation: String = "idle"
@onready var anim_player = $AnimationPlayer
func _physics_process(delta):
# 获取输入方向(返回一个 -1 到 1 之间的向量)
var input_dir = Input.get_vector("move_left", "move_right", "move_up", "move_down")
# 将 2D 输入方向转换为 3D 移动方向(俯视游戏在 XZ 平面移动)
var direction = Vector3(input_dir.x, 0, input_dir.y).normalized()
if direction != Vector3.ZERO:
# 移动
velocity = direction * move_speed
# 让角色朝向移动方向
look_at(position + direction, Vector3.UP)
update_animation("walk")
else:
# 减速停止(平滑停止)
velocity = velocity.lerp(Vector3.ZERO, 0.2)
update_animation("idle")
move_and_slide()
func update_animation(anim_name: String):
if anim_name != current_animation:
current_animation = anim_name
if anim_player:
anim_player.play(current_animation)动画状态说明
一个完整的玩家角色通常需要以下动画:
| 动画名称 | 触发条件 | 说明 |
|---|---|---|
idle | 站立不动 | 待机动画,轻微呼吸感 |
walk | 水平移动中 | 走路循环动画 |
run | 快速移动 | 跑步循环动画(可选) |
jump | 离开地面 | 跳跃起始动画 |
fall | 下落中 | 下落动画(可选) |
land | 刚落地 | 落地动画(可选) |
attack | 按下攻击键 | 攻击动画 |
hurt | 受到伤害 | 受击动画 |
die | 血量归零 | 死亡动画 |
动画的创建
在 Godot 里,动画通过 AnimationPlayer 节点创建。你可以在编辑器底部的"动画"面板里录制关键帧,或者导入外部 3D 模型自带的动画。
小结
| 知识点 | 说明 |
|---|---|
| CharacterBody3D | 专为可移动角色设计的节点 |
| MoveAndSlide | 处理移动和碰撞的核心方法 |
| IsOnFloor | 检测是否站在地面上 |
| Input.GetVector | 获取四方向输入,适合俯视游戏 |
| AnimationPlayer | 控制角色动画的节点 |
玩家角色做好了,接下来我们来创建游戏里的"对手"——敌人!
