基于C#的Godot游戏开发学习:含FPS控制器等技术问询
针对C#开发者的Godot FPS开发指南
一、核心概念先吃透
1. 节点(Node)
- 所有Godot对象的基础单元,每个节点拥有父/子层级关系,C#中继承自
Godot.Node类 - FPS开发常用节点类型:
CharacterBody3D:FPS角色的核心载体,自带物理碰撞与移动逻辑Camera3D:场景视角控制器,负责渲染画面CollisionShape3D:绑定碰撞形状(如CapsuleShape3D),实现角色碰撞检测Node3D:通用3D节点,用于挂载脚本或作为场景容器
- 高频使用方法:
GetNode<T>(string path):泛型方式获取子节点,类型更安全AddChild(Node child):向当前节点添加子节点Process(double delta):每帧执行的非物理逻辑PhysicsProcess(double delta):物理帧触发,处理移动、碰撞等物理相关操作
2. 向量(Vector2/Vector3)
- 3D开发核心用
Vector3,用于存储位置、方向、速度等数据 - 常用操作:
- 归一化:
vector.Normalized():得到单位向量(方向不变,长度为1,适合计算移动方向) - 点积:
vector.Dot(other):判断两个向量的夹角,可用于视野检测、坡度判断 - 叉积:
vector.Cross(other):生成垂直于两个向量的新向量,用于旋转计算 - 方向转换:
Transform.Basis * localDir:将本地方向向量转换为世界方向向量
- 归一化:
二、C#开发常用函数与工具
1. 核心函数/方法
- 输入获取:
Input.GetAxis("move_left", "move_right"):获取水平轴输入值(范围-1到1)Input.IsActionJustPressed("jump"):检测按键单次按下事件
- 物理移动:
CharacterBody3D.MoveAndSlide(velocity, Vector3.Up):处理带碰撞的角色移动,自动适配斜坡、台阶
- 旋转控制:
Node3D.RotateY(float angle):绕Y轴旋转(角色左右转向)Camera3D.RotateX(float angle):绕X轴旋转(视角抬头低头)
- 场景与调试:
GetTree().ChangeSceneToFile("res://scenes/Level.tscn"):加载指定场景GD.Print("Debug info"):输出调试日志到编辑器控制台
2. 必备工具
- Godot编辑器:自带场景编辑器、节点面板、属性编辑器,可拖拽搭建FPS场景框架
- C# IDE:Visual Studio或Rider,Godot会自动生成.csproj项目,支持智能提示与断点调试
- 编辑器调试面板:
Debug面板:查看日志输出Remote面板:实时查看运行中节点的属性值
三、Camera3D工作原理
Camera3D是场景的"渲染窗口",只有设置为当前相机(通过MakeCurrent()或勾选Current属性)才会输出画面- FPS视角核心配置:
- 将
Camera3D作为CharacterBody3D的子节点,实现视角与角色同步移动 - 限制相机X轴旋转角度(通常设为-89°到89°),避免视角翻转
- 将
- 关键逻辑:
- 通过鼠标输入控制相机旋转:用
InputEventMouseMotion获取鼠标相对位移,转换为旋转角度 - 角色转向跟随相机Y轴旋转,相机自身单独处理X轴旋转(抬头低头)
- 通过鼠标输入控制相机旋转:用
四、自定义FPS控制器实现(C#)
1. 节点结构
CharacterBody3D (命名为Player) ├─ Camera3D (命名为PlayerCamera) └─ CollisionShape3D (绑定CapsuleShape3D)
2. C#脚本代码(挂载于Player节点)
using Godot; public partial class Player : CharacterBody3D { [Export] public float MoveSpeed = 5.0f; [Export] public float JumpForce = 4.5f; [Export] public float MouseSensitivity = 0.1f; [Export] public Camera3D PlayerCamera; private float _cameraXRotation = 0.0f; public override void _Ready() { // 锁定鼠标到窗口中心并隐藏光标 Input.MouseMode = Input.MouseModeEnum.Captured; // 设置当前相机 PlayerCamera.MakeCurrent(); } public override void _Input(InputEvent @event) { // 处理鼠标旋转输入 if (@event is InputEventMouseMotion mouseMotion) { // 角色绕Y轴左右转向 RotateY(-mouseMotion.Relative.X * MouseSensitivity * 0.01f); // 相机绕X轴抬头低头,并限制角度 _cameraXRotation -= mouseMotion.Relative.Y * MouseSensitivity * 0.01f; _cameraXRotation = Mathf.Clamp(_cameraXRotation, -Mathf.Pi / 2, Mathf.Pi / 2); PlayerCamera.Rotation = new Vector3(_cameraXRotation, 0, 0); } } public override void _PhysicsProcess(double delta) { // 获取移动输入 float inputX = Input.GetAxis("move_left", "move_right"); float inputZ = Input.GetAxis("move_backward", "move_forward"); // 将本地移动方向转换为世界方向 Vector3 moveDir = (Transform.Basis * new Vector3(inputX, 0, inputZ)).Normalized(); Vector3 velocity = Velocity; // 处理移动速度 if (moveDir != Vector3.Zero) { velocity.X = moveDir.X * MoveSpeed; velocity.Z = moveDir.Z * MoveSpeed; } else { // 平滑减速 velocity.X = Mathf.MoveToward(Velocity.X, 0, MoveSpeed); velocity.Z = Mathf.MoveToward(Velocity.Z, 0, MoveSpeed); } // 跳跃逻辑 if (IsOnFloor() && Input.IsActionJustPressed("jump")) { velocity.Y = JumpForce; } // 应用重力 if (!IsOnFloor()) { velocity.Y -= 9.8f * (float)delta; } Velocity = velocity; // 执行带碰撞的移动 MoveAndSlide(); } }
3. 关键细节
- 用
_Input处理鼠标旋转,避免物理帧延迟导致的视角卡顿 IsOnFloor()检测角色是否接触地面,防止多次跳跃Transform.Basis * moveDir确保移动方向随角色转向同步变化- 限制相机X轴旋转角度,避免视角翻转到角色背部
内容的提问来源于stack exchange,提问作者Tatar
相关产品推荐
相关产品推荐

