在 Godot 中的第一个游戏

2025年3月17日 | 阅读 8 分钟

本教程将指导我们制作我们的第一个 Godot 项目。我们将学习 Godot 编辑器的工作方式,如何构建项目以及构建一个 2D 游戏。

本项目是对 Godot 引擎的介绍。它假定我们已经有一些编程经验。如果我们完全是编程新手,我们应该从这里开始。

游戏名为"躲避怪物!"我们的角色必须移动并尽可能长时间地避开敌人。这是最终结果的预览

First Game in Godot
First Game in Godot

为什么选择 2D?

3D 游戏比 2D 游戏复杂得多。在我们对游戏开发过程有很好的理解之前,我们应该坚持使用 2D

项目设置

启动 Godot 并创建一个新项目。然后,下载 dodge_assets.zip,即我们将用于制作游戏的图像和声音。将这些文件解压缩到我们的项目文件夹中。

这个游戏将使用纵向模式,所以我们需要调整游戏窗口的大小。单击项目 -> 项目设置 -> 显示 -> 窗口,并将“宽度”设置为 480,将“高度”设置为 720

组织项目

在这个项目中,我们将制作三个独立的场景:Player、MobHUD,我们将它们组合到游戏的主 main 场景中。在一个更大的项目中,制作文件夹来保存各种视图及其脚本可能很有用,但对于这个相对较小的游戏,我们可以将场景和脚本保存在根文件夹中,该文件夹称为 res://。我们可以在左上角的 FileSystem Dock 中看到项目文件夹

First Game in Godot

玩家场景

我们将制作的第一个场景定义了 Player 对象。创建单独的 Player 场景的好处之一是,我们可以单独测试它,即使在我们创建游戏的其他部分之前。

节点结构

首先,单击添加/创建新节点”按钮,并将 Area2D 节点添加到场景中

First Game in Godot

使用 Area2D,我们可以检测到与玩家重叠或碰撞的对象。通过单击节点的名称将它的名称更改为 Player。这是场景的根节点。我们可以向玩家添加额外的节点以添加功能。

在我们向 Player 节点添加任何子节点之前,我们要确保我们不会通过单击它们来意外地移动或调整它们的大小。选择该节点,然后单击锁右侧的图标;其工具提示显示“确保对象的子对象不可选择”。

First Game in Godot

保存场景。单击“场景”->“保存”,或在 Windows/Linux 上按 Ctrl+S,或在 Mac 上按 Command+S

注意
对于此项目,我们将遵循 Godot 命名约定。类(节点)使用 ParcalCase,变量和函数使用 snake_case,常量使用 ALL_CAPs

精灵动画

单击 Player 节点,并将 AnimatedSprite 节点添加为子节点。 AnimatedSprite 将处理我们玩家的外观和动画。请注意,节点旁边有一个警告符号。 AnimatedSprite 需要一个 SpriteFrames 资源,这是一个可以显示的动画列表。要创建一个,请在检查器中找到 Frames 属性,然后单击“<null>” -> “NewSpriteFrames”。接下来,在相同的位置,单击“<null>” -> “NewSpriteFrames”。接下来,在相同的位置,单击 <SpriteFrames> 以打开 “SpriteFrames” 面板

First Game in Godot

左侧是动画列表。单击 “default”,然后将其重命名为“right”。然后单击“添加”按钮以创建第二个名为“up”的动画。将每个动画的两个图像(名为 playerGrey_up[1/2]playerGrey_walk[1/2])拖到面板的“动画帧”一侧

First Game in Godot

玩家图像对于游戏窗口来说有点太大了,所以我们需要缩小它们。单击 AnimatedSprite 节点,并将 Scale 属性设置为 (0.5,0.5)。我们可以在检查器中的 Node2D 标题下找到它。

First Game in Godot

最后,添加一个 CollisionShape2D 作为 Player 的子节点。它将决定玩家的“hitbox”,即其碰撞区域的边界。对于这个角色, capsuleShape2D 节点提供了最佳的拟合,所以在检查器中 “Shape” 旁边,单击 “<null>””->” New CapsuleShape2D”。调整形状的大小以覆盖精灵

First Game in Godot

不要缩放形状的轮廓!仅使用尺寸手柄(红色圈出)来调整形状!

完成后,我们的 Player 场景应该看起来像这样

First Game in Godot

移动玩家

现在我们需要添加一些我们无法从内置节点获得的功能,所以我们将添加一个脚本。单击 Player 节点,然后单击“添加脚本”按钮;

First Game in Godot

在脚本设置窗口中,我们可以保留默认设置。只需单击“创建”

注意:如果我们正在创建 C# 脚本或其他语言,请在点击创建之前从语言下拉菜单中选择语言。

First Game in Godot

如果这是您第一次接触 GDScript,请在继续之前阅读 scripting。

首先声明此对象需要的成员变量

在第一个变量 speed 上使用 export 关键字允许我们在检查器中设置其值。对于我们希望能够调整的值,这非常方便,就像节点的内置属性一样。单击 Player 节点,并将 speed 属性设置为 400。

警告

如果我们使用 C#,我们需要暂时重新启动 Godot 编辑器才能在编辑器中看到导出的变量,直到它被修复。

First Game in Godot

当节点进入场景树时,会调用 _ready() 函数,这是查找游戏窗口大小的好时机

GDScript

现在我们可以使用 _process() 函数来定义玩家将要做什么。 _process() 每帧调用一次,因此我们将使用它来更新游戏的元素,我们预计这些元素会经常更改。在这里我们这样做

  • 检查输入
  • 在给定的方向上移动。
  • 播放适当的动画。

首先,我们必须检查输入——玩家是否正在按键?对于游戏,我们有四个输入方向要检查。输入操作在项目设置的“输入映射”下定义。我们可以描述自定义事件并为它们分配不同的键、鼠标事件或其他输入。对于此演示,我们将使用附加到键盘上箭头键的默认事件。

我们可以使用 Input.is_action_pressed() 检测是否按下了一个键,如果按下则返回 true,如果没有按下则返回 false。

GDScript

我们检查每个输入并加/减速度以获得总方向。例如,如果我们同时按住向右和向下键,则产生的速度向量将为 (1,1)。在这种情况下,由于我们添加了水平垂直移动,玩家的移动速度将比仅水平移动更快。

如果我们对速度进行归一化,我们可以防止这种情况发生,这意味着我们将它的长度设置为 1,然后乘以所需的速度。这意味着没有更快的对角线运动。

小费

如果我们以前从未使用过向量数学,或者需要复习一下,我们可以在 vector math 中看到 Godot 中向量用法的解释。 了解它是很好的,但对于本教程的其余部分来说不是必需的。

我们还检查玩家是否正在移动,以便我们可以启动或停止 AnimatedSprite 动画。

$ 返回此节点相对路径上的节点,如果未找到该节点,则返回 null。由于 AnimatedSprite 是当前节点的子节点,我们可以使用 $AnimatedSprite

$ 是 get_node() 的简写形式。因此,在上面的代码中, $AnimatedSprite.play()get_node("AnimatedSprite").play() 相同。

现在我们有了移动方向,我们可以更新 Player 的 位置,并使用 clamp() 来防止它离开屏幕,方法是将以下内容添加到 _process 函数的底部

GDScript

小费

钳制一个值意味着将其限制在给定的范围内。

单击“PlayScene”(F6) 并确认我们可以将玩家在屏幕上向各个方向移动。

警告

如果我们在“调试器”面板中收到一个引用“null 实例”的错误,这可能意味着我们错误地拼写了节点名称。节点名称区分大小写,并且 $NodeNameget_node("NodeName") 必须与我们在场景树中看到的名称匹配。

选择动画

我们需要根据方向更改 AnimatedSprite 正在播放的动画。我们有一个“right”动画,应该使用 flip_h 属性水平翻转以进行向左移动,还有一个“up”动画,应该使用 flip_v 垂直翻转以进行向下移动。让我们将此代码放在 _process() 函数的末尾

GDScript

再次播放场景,并检查每个方向上的动画是否正确。当我们确定移动工作正常时,将此行添加到 _ready() 中,以便在游戏开始时隐藏玩家

GDScript

准备碰撞

我们希望 Player 检测到何时被敌人击中,但我们还没有制造任何敌人!没关系,因为我们将使用 Godot 的信号功能来实现它。

在脚本顶部,在 extends Area2D: 之后添加以下内容:

GDScript

这定义了一个名为 "hit" 的自定义信号,当我们的玩家与敌人发生碰撞时,我们将发出(发送)该信号。我们将使用 Area2D 来检测碰撞。选择 Player 节点,然后单击检查器选项卡旁边的 “节点” 选项卡,以查看玩家可以发出的信号列表。

First Game in Godot

注意,我们的自定义信号 "hit" 也在那里!由于我们的敌人将是 RigidBody2D 节点,我们需要 body_entered(Object body) 信号;当一个 body 接触到玩家时,将发出此信号。单击 “连接”,然后在 “连接信号” 窗口中再次单击 “连接”。我们不需要更改任何这些设置 - Godot 将自动在我们的玩家脚本中创建一个名为 _on_Player_body_entered 的函数。

在连接信号时,我们也可以指定要将信号链接到的现有函数的名称,而不是让 Godot 为我们创建一个函数。

将此代码添加到函数中

GDScript

注意
禁用 Area 的碰撞形状意味着它不会检测到碰撞。 通过将其关闭,我们确保不会多次触发 hit 信号。

我们玩家的最后一部分是添加一个函数,我们可以在开始新游戏时调用它来重置玩家。

GDScript

敌人场景

现在是时候创建我们的玩家必须躲避的敌人了。 它们的行为不会很复杂:怪物会随机地在屏幕边缘生成,并沿直线以随机方向移动,然后在 离开屏幕消失

我们将把它构建到一个 Mob 场景中,然后实例化它以在游戏中创建任意数量的独立怪物。


下一个主题游戏的节点设置