HOME / 第 5 部分 · 3D 游戏开发 / 第 51 课
MODULE 5 · 3D 游戏开发
第 51 课 · 3D 角色控制:第一人称
🎯 本课学习目标
- 用 CharacterBody3D 做 FPS 角色
- 实现鼠标视角旋转
- 实现 WASD 移动与跳跃
本课做出经典 FPS 手感:鼠标转头 + WASD 移动 + 空格跳跃。
📖 详细教学步骤
创建玩家场景搭建
- 新建场景,根节点
CharacterBody3D,命名 Player,保存 player3d.tscn - 子节点:
CollisionShape3D(胶囊形 CapsuleShape3D,高约 1.8 米) - 子节点
Camera3D放在眼睛高度(约 Y=1.6) - 挂脚本 player3d.gd
移动与重力代码
与 2D 角色类似,但用 Vector3:
GDSCRIPTextends CharacterBody3D
@export var speed: float = 6.0
@export var jump_velocity: float = 4.5
var gravity = ProjectSettings.get_setting(
"physics/3d/default_gravity") # 默认 9.8
func _physics_process(delta):
# 重力
if not is_on_floor():
velocity.y -= gravity * delta
# WASD 相对相机朝向移动
var input_dir = Input.get_vector("move_left", "move_right",
"move_forward", "move_back")
var dir = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
velocity.x = dir.x * speed
velocity.z = dir.z * speed
# 跳跃
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = jump_velocity
move_and_slide()
鼠标视角旋转(转头)代码
用鼠标移动控制视角:
GDSCRIPT@export var mouse_sensitivity: float = 0.002
func _unhandled_input(event):
if event is InputEventMouseMotion:
# 水平旋转身体(Y 轴)
rotate_y(-event.relative.x * mouse_sensitivity)
# 垂直旋转相机(X 轴,限制俯仰范围防倒立)
$Camera3D.rotate_x(-event.relative.y * mouse_sensitivity)
$Camera3D.rotation.x = clampf($Camera3D.rotation.x,
-1.2, 1.2) # ±70°左右
锁定鼠标实操
FPS 需要鼠标锁定在窗口中央:
GDSCRIPTfunc _ready():
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED # 捕获鼠标
func _unhandled_input(event):
# Esc 释放鼠标
if event.is_action_pressed("ui_cancel"):
if Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
else:
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
输入映射补充操作
新增输入动作:
move_forward:Wmove_back:Smove_left:Amove_right:Djump:空格
💡 Input.get_vector 用两对左右/上下动作返回 2D 向量。
测试测试
- 场景里放地面(StaticBody3D + BoxShape3D)和几个立方体
- F5 运行:鼠标被捕获 → 移动鼠标转头 → WASD 走 → 空格跳
- Esc 释放鼠标
🎉 FPS 手感达成!
⚠️
鼠标转头方向反了?
rotate_y 的正负号调一下:负号 → 向左转。按手感微调。
⚠️
角色飞出世界/掉出?
需要地面 StaticBody3D + 碰撞形状。3D 里 CollisionShape3D 配 BoxShape3D/WorldBoundaryShape3D。
⚠️
相机穿墙?
高级问题:需要射线检测相机碰撞。先了解,后续优化。
🧪 动手试一试
🏋️ 课后练习
完善 FPS:加上下视角限制、鼠标捕获与释放切换、地面 + 障碍物可走可跳。
clampf 限制俯仰;Input.MOUSE_MODE_CAPTURED 捕获。
💡
胶囊碰撞体高度 = 角色身高,相机放眼睛高度。
💡
Input.get_vector 返回 2D 输入向量,转成 3D 用 transform.basis 乘。
🎓 本课小结
CharacterBody3D + 重力 + WASD 相对相机移动 + 鼠标 rotate 转头 + clampf 限俯仰 + 捕获鼠标 = 完整 FPS 角色。