十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Godot 4 C# 实战:7个项目掌握2D游戏开发核心

Godot 4 C# 实战:7个项目掌握2D游戏开发核心 这类教程最怕的就是只讲概念不给能跑起来的代码和配置。如果你已经跟着上篇把 Godot 4 和 C# 环境搭好了那这篇就是带你从“能跑”到“会做”的关键一步。我会直接跳过所有泛泛而谈用七个从简到繁的实战项目把引擎基础、C# 脚本、节点系统和物理交互这些核心概念串起来。目标很明确让你在动手的过程中真正理解 Godot 4 和 C# 配合开发 2D 游戏的完整工作流。适合谁看已经安装好 Godot 4 和 .NET SDK想通过实际项目巩固 C# 脚本编写、理解节点树操作和掌握物理引擎用法的开发者。无论是刚入门的新手还是从其他引擎转过来的老手这套实战拆解都能帮你快速建立 Godot 的开发直觉。1. 环境复查与项目初始化别在第一步卡住在动手写任何代码之前先确保你的环境是“干净”且“对齐”的。很多后续的诡异报错根源都在这里。1.1 版本对齐Godot、.NET 与编辑器首先确认你安装的 Godot 4 版本支持 C#。官方下载页面通常有标注选择带有.NET或Mono后缀的版本。我建议使用当前最新的稳定版比如 Godot 4.2.x。接着是 .NET SDK。Godot 4 的 C# 支持基于 .NET 6 或 .NET 8。打开终端或命令行输入dotnet --info查看已安装的 SDK 版本。确保你安装的版本与 Godot 项目设置中的目标框架一致。通常新建一个 Godot C# 项目时它会自动匹配一个可用的 .NET 版本。最后是代码编辑器。虽然 Godot 内置编辑器能写 C#但功能有限。更推荐使用 Visual Studio Code 或 JetBrains Rider。以 VS Code 为例你需要安装 C# 扩展由 Microsoft 发布和 Godot 工具扩展。安装后在 VS Code 中打开 Godot 项目文件夹它应该能自动识别.csproj文件并提供智能提示、代码补全和调试支持。注意如果你在 Godot 编辑器中打开 C# 脚本时编辑器提示“找不到 C# 编辑器”或脚本无法高亮通常是因为外部编辑器路径没设置对。去 Godot 的编辑器设置 - 文本编辑器 - 外部编辑器里正确配置你的 VS Code 或 Rider 的可执行文件路径。1.2 创建第一个 C# 项目理解关键文件打开 Godot 编辑器选择“新建项目”。项目名和路径起个名字比如GodotCSharpLab路径不要有中文和特殊字符。渲染器2D 项目选择“兼容性”或“移动端”渲染器通常就够用兼容性更好。版本控制元数据如果你是 Git 用户可以勾选创建.gitignore。最关键的一步在“高级选项”中将“项目类型”从默认的 GDScript 切换为C# (.NET)。Godot 会自动为你生成 C# 项目所需的文件结构。创建完成后观察项目文件树你会看到几个关键文件project.godotGodot 项目配置文件。YourProjectName.csprojC# 项目文件定义了编译目标、依赖等。YourProjectName.slnVisual Studio 解决方案文件如果用 VS 或 Rider 会用到。一个名为Nodes的文件夹里面可能有一个默认的Main.cs脚本。现在尝试在 Godot 编辑器中运行这个空项目按 F5。如果控制台没有报错并且弹出了一个灰色窗口说明基础环境是通的。2. 项目一可控角色移动输入处理与脚本绑定我们从最基础的开始用键盘控制一个精灵在屏幕上移动。这个项目会教会你如何创建节点、附加 C# 脚本、处理输入事件以及每帧更新逻辑。2.1 场景搭建与节点创建在场景面板中点击“其他节点”按钮或按 CtrlA搜索并添加一个CharacterBody2D节点。将其重命名为Player。CharacterBody2D是专门用于需要自定义移动逻辑如平台跳跃的角色它自带碰撞和移动方法。选中Player节点再次添加一个子节点类型为Sprite2D。这个节点将用来显示角色的图像。我们需要一张图片。可以在项目文件系统中右键选择“新建 - 资源文件夹”命名为Assets。找一张小图片比如 64x64 像素的方块或角色图拖进去。然后选中Sprite2D节点在检查器面板的Texture属性中点击下拉箭头选择“快速加载”找到你刚放入的图片。为了让角色有物理体积还需要一个碰撞形状。选中Player节点添加一个CollisionShape2D子节点。在它的Shape属性中新建一个RectangleShape2D并调整矩形的大小使其大致匹配精灵图片的轮廓。现在你的场景树应该类似这样- Main (Node2D) - Player (CharacterBody2D) - Sprite2D - CollisionShape2D2.2 编写第一个 C# 移动脚本右键点击Player节点选择“附加脚本”。在弹出窗口中确保“语言”选择了C#脚本名称可以保持为Player.cs然后点击“创建”。Godot 会生成一个基本的 C# 脚本模板。我们将其修改为如下内容using Godot; public partial class Player : CharacterBody2D { // 定义移动速度可以在编辑器中调整 [Export] public int Speed { get; set; } 400; // 每帧调用的物理处理函数 public override void _PhysicsProcess(double delta) { // 1. 获取输入向量 Vector2 inputDirection Input.GetVector(ui_left, ui_right, ui_up, ui_down); // 2. 计算速度 Velocity inputDirection * Speed; // 3. 执行移动并处理碰撞 MoveAndSlide(); } }代码拆解[Export]属性这是一个 Godot C# 特有的特性。它将Speed变量暴露给 Godot 编辑器。保存脚本后你可以在Player节点的检查器面板中直接看到并修改Speed的值无需重新编译。这是 Godot 可视化工作流的核心。_PhysicsProcess方法这是 Godot 的物理帧回调函数以固定的时间间隔默认每秒 60 次调用。所有与物理、移动相关的逻辑应该放在这里。Input.GetVector一个非常方便的方法它根据你配置的输入映射如“ui_left”对应 A 键或左箭头返回一个归一化的二维向量。例如同时按住右和下会返回(1, -1)。VelocityCharacterBody2D类自带的属性表示当前的速度向量。MoveAndSlide()CharacterBody2D的核心方法。它会根据Velocity移动角色并自动处理与环境中其他CollisionObject2D如墙壁、地面的碰撞。碰撞后速度会被适当调整例如撞墙后水平速度归零。保存脚本回到 Godot 编辑器。选中Player节点你应该能在检查器底部看到Script Variables折叠栏展开后可以看到Speed属性。尝试修改它的值比如改成 200 或 600。现在运行游戏F5。你应该可以用方向键或 WASD 控制你的角色在窗口中自由移动了。如果撞到窗口边缘角色会停住因为窗口边界默认没有碰撞体。恭喜你完成了第一个交互式项目3. 项目二平台跳跃与重力模拟物理参数与状态管理上一个项目是自由移动现在我们来做一个经典的平台跳跃。这需要引入重力、跳跃力并处理角色是否在地面上的状态判断。3.1 扩展 Player 脚本我们修改Player.cs脚本增加跳跃和重力using Godot; public partial class Player : CharacterBody2D { [Export] public int Speed { get; set; } 300; [Export] public int JumpVelocity { get; set; } -400; // 向上跳Y轴负方向 [Export] public int Gravity { get; set; } 1000; // 重力加速度 public override void _PhysicsProcess(double delta) { Vector2 velocity Velocity; // 1. 应用重力如果不在空中则重置垂直速度 if (!IsOnFloor()) { velocity.Y Gravity * (float)delta; } // 2. 处理跳跃输入仅在地面时允许跳跃 if (Input.IsActionJustPressed(ui_accept) IsOnFloor()) { velocity.Y JumpVelocity; } // 3. 处理水平移动 float direction Input.GetAxis(ui_left, ui_right); velocity.X direction * Speed; // 4. 将计算好的速度赋值并执行移动 Velocity velocity; MoveAndSlide(); } }关键点解析JumpVelocity是负值在 Godot 的 2D 坐标系中Y 轴向下为正。所以要向上跳需要给 Y 速度一个负值。Gravity是正值因为重力是向下的力所以每帧在 Y 速度上增加一个正数。IsOnFloor()这是CharacterBody2D在调用MoveAndSlide()后更新的一个状态。如果上一帧移动后角色底部与“地板”发生了碰撞这个方法就返回true。这是我们判断能否跳跃的关键依据。Input.IsActionJustPressed(“ui_accept”)检测“ui_accept”这个输入动作默认是空格键或回车键是否在当前帧刚刚被按下。这避免了长按空格连续跳跃。Input.GetAxis获取两个动作如左和右之间的一个标量值。按右返回 1按左返回 -1都不按返回 0同时按也返回 0。比分别判断两个键更简洁。3.2 创建测试平台光有角色还不行我们需要地板和平台让他跳。在场景中删除默认的Main节点下的所有子节点如果有的话。创建一个新的StaticBody2D节点重命名为Ground。StaticBody2D用于静止的、不会移动的碰撞体如地面、墙壁。为Ground添加一个CollisionShape2D子节点。将其Shape设置为RectangleShape2D。在 2D 视图中将这个矩形拉长并移动到窗口底部作为地面。同样方法再创建一两个StaticBody2D作为空中平台放在地面之上。运行游戏。现在你的角色应该会受重力下落站在地面上按空格键可以跳跃并且可以左右移动。尝试跳到空中平台上。实测注意Gravity和JumpVelocity的值需要根据你的角色大小和游戏感觉进行微调。Gravity太大下落太快手感沉重太小则感觉轻飘飘。JumpVelocity决定了跳跃高度。多调几次找到你觉得舒服的数值。4. 项目三发射子弹与实例化场景实例化与信号接下来我们让角色可以发射子弹。这会涉及到场景实例化 (Instancing)和信号 (Signals)这两个 Godot 核心概念。4.1 创建子弹场景在 Godot 中可重用的对象如子弹、敌人、道具通常被制作成独立的“场景”(Scene)。点击场景面板顶部的“新建场景”按钮或按 CtrlN。创建一个Area2D节点作为根节点重命名为Bullet。Area2D用于检测区域重叠非常适合子弹击中敌人的检测。为Bullet添加Sprite2D设置子弹图片和CollisionShape2D设置碰撞形状子节点。选中根节点Bullet点击检查器面板顶部的“脚本”图标为其创建一个新的 C# 脚本命名为Bullet.cs。编辑Bullet.csusing Godot; public partial class Bullet : Area2D { [Export] public int Speed { get; set; } 800; public override void _PhysicsProcess(double delta) { // 让子弹向右移动 Position new Vector2(Speed * (float)delta, 0); // 如果子弹飞出屏幕则销毁它优化性能 if (Position.X 1000) // 1000是一个示例值应大于你的屏幕宽度 { QueueFree(); } } // 当子弹与其他物体发生面积重叠时触发 private void OnBodyEntered(Node2D body) { // 这里可以添加击中效果比如播放动画、音效 GD.Print($Bullet hit: {body.Name}); // 击中后销毁子弹 QueueFree(); } }我们需要将代码与信号连接。在 Godot 编辑器中选中Bullet根节点切换到检查器的“节点”选项卡。你会看到Area2D自带一个body_entered信号。双击body_entered信号在弹出的连接窗口中确保“从节点”是Bullet方法名保持为OnBodyEntered然后点击“连接”。Godot 会自动在Bullet.cs中生成一个带有[Signal]特性的方法存根我们已经提前写好了。保存这个场景命名为Bullet.tscn。4.2 修改 Player 脚本以发射子弹回到Player.cs脚本我们需要做两件事加载子弹场景、在按下射击键时创建子弹实例。using Godot; public partial class Player : CharacterBody2D { // ... 之前的 Speed, JumpVelocity, Gravity 属性保持不变 ... // 1. 声明一个字段来存储子弹场景 private PackedScene _bulletScene; public override void _Ready() { // 2. 在节点进入场景树时加载子弹场景资源 _bulletScene GD.LoadPackedScene(res://Bullet.tscn); } public override void _PhysicsProcess(double delta) { // ... 之前的移动和跳跃逻辑保持不变 ... // 3. 处理射击输入 if (Input.IsActionJustPressed(ui_select)) // ui_select 默认是 Ctrl 键 { Shoot(); } // ... MoveAndSlide() 调用保持不变 ... } private void Shoot() { // 4. 实例化子弹场景 Bullet bulletInstance (Bullet)_bulletScene.Instantiate(); // 5. 设置子弹的初始位置例如从玩家中心偏右发射 bulletInstance.GlobalPosition GlobalPosition new Vector2(20, 0); // 6. 将子弹实例添加到当前场景树中 GetTree().CurrentScene.AddChild(bulletInstance); } }核心概念解析PackedScene这是一个资源类型代表一个已保存的场景文件.tscn。你可以把它理解为一个“预制体”或“模板”。GD.LoadT(“路径”)Godot 的静态方法用于从资源路径加载资源。PackedScene指定了加载的类型。_Ready()当节点及其所有子节点都进入场景树时调用。通常用于初始化操作比如加载资源、获取节点引用。Instantiate()根据PackedScene创建一个新的、独立的场景实例。这个实例拥有原场景的所有节点和属性。AddChild()将一个节点实例添加到另一个节点下使其成为子节点。只有添加到场景树中节点才会被处理绘制、更新、参与物理等。GetTree().CurrentScene获取了当前运行的主场景的根节点。运行游戏。现在控制角色移动和跳跃同时按 Ctrl 键你应该能看到子弹从角色右侧射出并向右飞行。如果子弹碰到之前创建的StaticBody2D地面或平台控制台会打印击中信息然后子弹消失。5. 项目四敌人 AI 与简单状态机继承与行为逻辑现在我们来创建一个简单的敌人。它会来回巡逻碰到玩家则“攻击”这里我们先打印日志。这个项目会引入继承和简单的状态机思想。5.1 创建敌人基类与巡逻状态首先创建一个敌人的场景。新建场景根节点为CharacterBody2D重命名为Enemy。添加Sprite2D和CollisionShape2D。附加 C# 脚本Enemy.cs。编辑Enemy.csusing Godot; public partial class Enemy : CharacterBody2D { [Export] public int PatrolSpeed { get; set; } 150; [Export] public Vector2 PatrolDirection { get; set; } Vector2.Right; [Export] public float PatrolDistance { get; set; } 100; private Vector2 _startPosition; private float _traveledDistance 0; public override void _Ready() { _startPosition GlobalPosition; } public override void _PhysicsProcess(double delta) { Patrol(delta); MoveAndSlide(); } private void Patrol(double delta) { // 计算本帧移动量 Vector2 movement PatrolDirection * PatrolSpeed * (float)delta; // 更新已移动距离 _traveledDistance movement.Length(); // 如果移动距离超过设定值则掉头 if (_traveledDistance PatrolDistance) { PatrolDirection * -1; // 反转方向 _traveledDistance 0; // 重置距离计数 // 可选在这里可以更新精灵朝向 // Scale new Vector2(-Scale.X, Scale.Y); } Velocity movement; } }这个敌人会从起始点开始沿PatrolDirection方向移动PatrolDistance像素然后掉头返回如此循环。5.2 添加玩家检测与“攻击”状态我们需要让敌人检测玩家。使用Area2D作为检测区域是个好方法。在Enemy场景中添加一个Area2D子节点重命名为DetectionZone。为DetectionZone添加一个CollisionShape2D形状可以比敌人的碰撞体大一圈。为Enemy脚本添加状态管理和检测逻辑。修改Enemy.csusing Godot; public enum EnemyState { Patrol, Chase } public partial class Enemy : CharacterBody2D { // ... 之前的巡逻相关属性 ... [Export] public int ChaseSpeed { get; set; } 250; private EnemyState _currentState EnemyState.Patrol; private Area2D _detectionZone; private Node2D _targetPlayer; public override void _Ready() { _startPosition GlobalPosition; _detectionZone GetNodeArea2D(DetectionZone); // 连接检测区域的信号 _detectionZone.BodyEntered OnDetectionZoneBodyEntered; _detectionZone.BodyExited OnDetectionZoneBodyExited; } public override void _PhysicsProcess(double delta) { switch (_currentState) { case EnemyState.Patrol: Patrol(delta); break; case EnemyState.Chase: Chase(delta); break; } MoveAndSlide(); } private void Patrol(double delta) { // ... 同之前的巡逻逻辑 ... } private void Chase(double delta) { if (_targetPlayer ! null) { // 计算朝向玩家的方向 Vector2 direction (_targetPlayer.GlobalPosition - GlobalPosition).Normalized(); Velocity direction * ChaseSpeed; GD.Print(Enemy is chasing player!); } else { // 如果目标丢失回到巡逻状态 _currentState EnemyState.Patrol; } } private void OnDetectionZoneBodyEntered(Node2D body) { // 假设玩家节点的名称包含 Player if (body.Name.ToString().Contains(Player)) { _targetPlayer body; _currentState EnemyState.Chase; GD.Print(Player detected! Start chasing.); } } private void OnDetectionZoneBodyExited(Node2D body) { if (body _targetPlayer) { _targetPlayer null; _currentState EnemyState.Patrol; GD.Print(Player lost. Back to patrol.); } } }代码要点状态机使用enum定义状态巡逻、追逐在_PhysicsProcess中用switch根据当前状态执行不同逻辑。这是一种清晰管理复杂行为的方式。信号连接C# 风格在_Ready中我们使用操作符将 C# 事件处理程序连接到 Godot 信号上。BodyEntered和BodyExited是Area2D提供的信号。这是 Godot 4 C# 中推荐的连接方式比编辑器可视化连接更利于代码管理。目标获取OnDetectionZoneBodyEntered中我们通过检查进入区域的物体名称是否包含 “Player” 来判断是否是玩家。在实际项目中你可能会使用分组Groups或自定义层Layers来更可靠地识别对象。追逐逻辑Chase方法计算从敌人位置指向玩家位置的向量归一化后乘以追逐速度得到速度向量。将Enemy.tscn保存然后拖入主场景中。运行游戏控制玩家角色进入敌人的检测区域敌人会停止巡逻并朝玩家移动玩家离开区域后敌人会恢复巡逻。6. 项目五UI 界面与分数系统场景切换与全局数据一个完整的游戏需要界面。我们来创建一个简单的 UI显示分数并在玩家死亡或到达目标时切换场景。6.1 创建 UI 场景新建场景根节点选择CanvasLayer重命名为UILayer。CanvasLayer是专门用于 UI 的节点它独立于游戏世界可以确保 UI 始终显示在最上层。在UILayer下添加一个Control节点作为容器然后添加以下子节点Label重命名为ScoreLabel用于显示分数。Button重命名为RestartButton文本设为“重新开始”。另一个Label重命名为GameOverLabel文本设为“游戏结束”初始隐藏。调整这些 UI 元素的位置和样式字体、颜色等。为UILayer附加脚本UI.csusing Godot; public partial class UI : CanvasLayer { private Label _scoreLabel; private Button _restartButton; private Label _gameOverLabel; private int _score 0; public int Score { get _score; set { _score value; UpdateScoreDisplay(); } } public override void _Ready() { // 获取节点引用 _scoreLabel GetNodeLabel(Control/ScoreLabel); _restartButton GetNodeButton(Control/RestartButton); _gameOverLabel GetNodeLabel(Control/GameOverLabel); // 连接按钮信号 _restartButton.Pressed OnRestartButtonPressed; UpdateScoreDisplay(); _gameOverLabel.Hide(); _restartButton.Hide(); } private void UpdateScoreDisplay() { _scoreLabel.Text $Score: {_score}; } public void ShowGameOver() { _gameOverLabel.Show(); _restartButton.Show(); } private void OnRestartButtonPressed() { // 重新加载当前场景 GetTree().ReloadCurrentScene(); } }6.2 在游戏场景中集成 UI 并修改分数在主场景中实例化UILayer.tscn。然后我们需要修改Player.cs和Enemy.cs来与 UI 交互。这里我们使用 Godot 的自动加载AutoLoad功能来方便地访问 UI。设置自动加载将UI.tscn保存后进入 Godot 编辑器菜单项目 - 项目设置 - 自动加载。在“路径”中找到你的UI.tscn文件点击“添加”。Godot 会建议一个名称比如UI。这样游戏一启动UI场景就会被自动加载并成为根节点的子节点可以在任何脚本中通过GetNodeUI(/root/UI)访问。修改 Player 脚本收集分数假设子弹击中敌人得分。修改Bullet.cs的OnBodyEntered方法不再只是打印而是通知 UI 加分。// 在 Bullet.cs 的 OnBodyEntered 方法中 private void OnBodyEntered(Node2D body) { if (body.IsInGroup(enemies)) // 给敌人节点添加“enemies”分组 { // 获取全局 UI 实例并增加分数 UI ui GetNodeUI(/root/UI); if (ui ! null) { ui.Score 10; // 假设击中一个敌人得10分 } // 播放击中特效... QueueFree(); } // 击中其他物体如墙壁也销毁子弹 QueueFree(); }给敌人添加分组在编辑器中选中Enemy场景的根节点在检查器面板的“节点”选项卡中找到“分组”部分输入“enemies”并点击“添加”。游戏结束逻辑修改Player.cs当玩家碰到敌人时触发游戏结束。// 在 Player 节点下添加一个 Area2D 子节点命名为 HurtBox并设置碰撞形状覆盖玩家。 // 在 Player.cs 中 private Area2D _hurtBox; public override void _Ready() { // ... 其他初始化 ... _hurtBox GetNodeArea2D(HurtBox); _hurtBox.BodyEntered OnHurtBoxBodyEntered; } private void OnHurtBoxBodyEntered(Node2D body) { if (body.IsInGroup(enemies)) { GD.Print(Player hit by enemy! Game Over.); UI ui GetNodeUI(/root/UI); if (ui ! null) { ui.ShowGameOver(); } // 可选禁用玩家控制 SetPhysicsProcess(false); } }现在运行游戏你可以射击敌人得分碰到敌人则游戏结束并显示 UI。7. 项目六音效与粒子效果资源管理与即时反馈视听反馈对游戏体验至关重要。我们来为子弹发射和敌人被击中添加音效和粒子效果。7.1 添加音效准备音效文件.wav或.ogg格式放入项目的Assets文件夹。在Bullet.tscn场景中为根节点Bullet添加一个AudioStreamPlayer2D子节点重命名为ShootSound。在检查器中将它的Stream属性设置为你的发射音效文件。取消勾选Autoplay。修改Bullet.cs的_Ready方法在创建后播放音效。private AudioStreamPlayer2D _shootSound; public override void _Ready() { _shootSound GetNodeAudioStreamPlayer2D(ShootSound); _shootSound.Play(); }同样可以在Enemy.tscn中添加一个AudioStreamPlayer2D用于被击中音效在Bullet.cs的OnBodyEntered中击中敌人时播放敌人的音效。7.2 添加粒子效果在Bullet.tscn中添加一个GPUParticles2D节点作为Bullet的子节点重命名为TrailParticles。选中TrailParticles在检查器中配置粒子属性Process Material新建一个ParticleProcessMaterial可以调整方向、扩散、重力等。Draw Passes-Pass 1设置一个简单的纹理如白色小点。Amount粒子数量。Lifetime粒子存活时间。Explosiveness设为 0让粒子持续发射。One Shot取消勾选。调整粒子位置让它看起来像是从子弹尾部发出。在Bullet.cs的_Ready中也可以启动粒子发射。对于击中效果可以创建一个独立的HitEffect.tscn场景根节点为Node2D包含一个播放一次爆炸动画的AnimatedSprite2D或一个GPUParticles2D勾选One Shot。当子弹击中时实例化这个效果场景到击中位置播放完后自动QueueFree。8. 项目七数据持久化与设置ConfigFile 与自定义资源最后我们实现一个简单的系统来保存最高分和游戏设置。8.1 使用 ConfigFile 保存最高分修改UI.cspublic partial class UI : CanvasLayer { // ... 其他字段和属性 ... private const string SAVE_PATH user://highscore.cfg; private const string SECTION game; private const string KEY_HIGHSCORE high_score; private int _highScore 0; public override void _Ready() { // ... 其他初始化 ... LoadHighScore(); UpdateHighScoreDisplay(); } private void LoadHighScore() { var config new ConfigFile(); Error err config.Load(SAVE_PATH); if (err Error.Ok) { _highScore (int)config.GetValue(SECTION, KEY_HIGHSCORE, 0); } } private void SaveHighScore() { var config new ConfigFile(); config.SetValue(SECTION, KEY_HIGHSCORE, _highScore); config.Save(SAVE_PATH); } private void UpdateHighScoreDisplay() { // 假设你有一个 HighScoreLabel // _highScoreLabel.Text $High Score: {_highScore}; } // 在分数更新时检查并保存最高分 public int Score { get _score; set { _score value; UpdateScoreDisplay(); if (_score _highScore) { _highScore _score; SaveHighScore(); UpdateHighScoreDisplay(); } } } }user://是 Godot 的用户数据目录跨平台且有写入权限。8.2 创建自定义资源管理游戏设置对于更复杂的配置如音量、按键映射可以创建自定义资源。在脚本编辑器中创建一个新的 C# 脚本命名为GameSettings.cs但不继承Node而是继承Resource。using Godot; [GlobalClass] // 这个特性让该类在编辑器中可作为资源创建 public partial class GameSettings : Resource { [Export] public float MasterVolume { get; set; } 1.0f; [Export] public float MusicVolume { get; set; } 0.8f; [Export] public float SfxVolume { get; set; } 0.8f; // 可以添加更多设置... }在 Godot 编辑器的文件系统中右键 - 新建资源搜索GameSettings创建一个新的资源文件命名为default_settings.tres。你可以在检查器中修改它的默认值。在你的主场景或一个全局管理脚本中加载这个资源并应用到游戏里如设置AudioServer的总线音量。通过这七个项目你实际上走完了一个小型 2D 动作游戏的核心开发循环从角色控制、物理交互、对象生成、AI 行为、UI 反馈、视听效果到数据管理。每个项目都聚焦于 Godot 4 与 C# 配合下的一个关键技能点并且代码和配置都是可运行、可扩展的。真正掌握这些你就有了独立开发更复杂 2D 游戏的坚实基础。接下来要做的就是把它们组合起来并填充你自己的游戏创意了。
返回列表