HOME / 第 5 部分 · 3D 游戏开发 / 第 51 课
MODULE 5 · 3D 游戏开发

第 51 课 · 3D 角色控制:第一人称

⏱ 预计时长 40 分钟📊 难度 进阶📚 模块 第 5 部分 · 3D 游戏开发

🎯 本课学习目标

本课做出经典 FPS 手感:鼠标转头 + WASD 移动 + 空格跳跃。

📖 详细教学步骤

创建玩家场景搭建

  1. 新建场景,根节点 CharacterBody3D,命名 Player,保存 player3d.tscn
  2. 子节点:CollisionShape3D(胶囊形 CapsuleShape3D,高约 1.8 米)
  3. 子节点 Camera3D 放在眼睛高度(约 Y=1.6)
  4. 挂脚本 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:W
  • move_back:S
  • move_left:A
  • move_right:D
  • jump:空格

💡 Input.get_vector 用两对左右/上下动作返回 2D 向量。

测试测试

  1. 场景里放地面(StaticBody3D + BoxShape3D)和几个立方体
  2. F5 运行:鼠标被捕获 → 移动鼠标转头 → WASD 走 → 空格跳
  3. 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 角色。