Godot的第一个游戏项目示例

本文概述

  • 为什么是2D?
  • 玩家场景
本教程将指导我们进行第一个Godot项目。我们将学习Godot编辑器的工作原理, 如何构建项目以及构建2D游戏。
该项目是Godot引擎的简介。它假定我们已经有一定的编程经验。如果我们完全不熟悉编程, 则应该在这里。
游戏称为” 躲开小兵!” 我们的角色必须移动并尽可能长时间避开敌人。这是最终结果的预览:
Godot的第一个游戏项目示例

文章图片
Godot的第一个游戏项目示例

文章图片
为什么是2D? 3D游戏比2D游戏复杂得多。我们应该坚持2D, 直到我们对游戏开发过程有了充分的了解。
项目设置
启动Godot并创建一个新项目。然后, 下载dodge_assets.zip我们将用来制作游戏的图像和声音。将这些文件解压缩到我们的项目文件夹中。
该游戏将使用人像模式, 因此我们需要调整游戏窗口的大小。单击项目-> 项目设置-> 显示-> 窗口, 然后将” 宽度” 设置为480, 将” 高度” 设置为720。
组织项目
在这个项目中, 我们将制作三个独立的场景:Player, Mob和HUD, 我们将它们合并到游戏的主场景中。在较大的项目中, 创建文件夹来容纳各种视图及其脚本可能会很有用, 但是对于这个相对较小的游戏, 我们可以将场景和脚本保存在根文件夹中, 称为res://。我们可以在左上角的FileSystem Dock中看到项目文件夹:
Godot的第一个游戏项目示例

文章图片
玩家场景 我们将创建的第一个场景定义Player对象。创建单独的Player场景的好处之一是, 即使在创建游戏的其他部分之前, 我们也可以对其进行单独测试。
节点结构
首先, 单击” 添加/创建新节点” 按钮, 然后将Area2D节点添加到场景中
Godot的第一个游戏项目示例

文章图片
使用Area2D, 我们可以检测重叠或进入播放器的对象。通过单击节点名称将其名称更改为Player。这是场景的根节点。我们可以向播放器添加其他节点以添加功能。
在将任何子代添加到” 播放器” 节点之前, 我们要确保我们不会意外地通过单击它们来移动或调整它们的大小。选择节点, 然后单击锁右侧的图标;它的工具提示中说:” 确保对象的子项不可选择。”
Godot的第一个游戏项目示例

文章图片
保存场景。单击场景-> 保存, 或者在Windows / Linux上按Ctrl + S, 在Mac上按Command + S。
注意对于此项目, 我们将遵循Godot命名约定。类(节点)使用ParcalCase, 变量和函数使用snake_case, 常量使用ALL_CAP。 雪碧动画
单击Player节点, 并将AnimatedSprite节点添加为子节点。 AnimatedSprite将为我们的播放器处理外观和动画。请注意, 节点旁边有一个警告符号。 AnimatedSprite需要SpriteFrames资源, 该资源是它可以显示的动画的列表。要创建一个, 请在检查器中找到Frames属性, 然后单击” < null> ” -> ” NewSpriteFrames” 。接下来, 在相同位置, 单击” < null> ” -> ” NewSpriteFrames” 。接下来, 在相同位置, 单击< SpriteFrames> 以打开” SpriteFrames” 面板:
Godot的第一个游戏项目示例

文章图片
左侧是动画列表。单击” 默认” , 然后将其重命名为” 正确” 。然后单击” 添加” 按钮以创建另一个名为” 向上” 的动画。将每个动画的两个图像分别命名为playerGrey_up [1/2]和playerGrey_walk [1/2]拖到面板的” 动画帧” 侧:
Godot的第一个游戏项目示例

文章图片
玩家图像对于游戏窗口而言太大了, 因此我们需要按比例缩小图像。单击AnimatedSprite节点, 然后将Scale属性设置为(0.5, 0.5)。我们可以在检查器中的Node2D标题下找到它。
Godot的第一个游戏项目示例

文章图片
最后, 添加CollisionShape2D作为Player的子代。它将确定玩家的” hitbox” 或其碰撞区域的边界。对于此角色, capsuleShape2D节点具有最佳的拟合效果, 因此在检查器中的” Shape” 旁边, 单击” < null> ” ” -> ” New CapsuleShape2D” 。调整形状大小以覆盖精灵:
Godot的第一个游戏项目示例

文章图片
不要缩放形状的轮廓!仅使用尺寸手柄(红色圆圈)来调整形状!
完成后, 我们的Player场景应如下所示:
Godot的第一个游戏项目示例

文章图片
移动播放器
现在, 我们需要添加一些无法从内置节点获得的功能, 因此我们将添加一个脚本。单击播放器节点, 然后单击” 添加脚本” 按钮;
Godot的第一个游戏项目示例

文章图片
在脚本设置窗口中, 我们可以保留默认设置。只需单击” 创建” :
注意:如果我们要创建C#脚本或其他语言, 请在点击创建之前, 从语言下拉菜单中选择语言。
Godot的第一个游戏项目示例

文章图片
如果这是我们第一次遇到GDScript, 请先阅读脚本, 然后再继续。
首先声明该对象将需要的成员变量:
GDScriptextends Area2DExport (int) var speed# How fast the player will move (pixels/sec).Var screensize# Size of the game window.

在第一个变速上使用export关键字, 使我们可以在检查器中设置其值。这对于我们希望能够调整的值非常方便, 就像节点的内置属性一样。单击” 播放器” 节点, 并将speed属性设置为400。
警告
如果使用的是C#, 则需要暂时??重新启动Godot编辑器, 以在编辑器中查看导出的变量, 直到修复为止。
Godot的第一个游戏项目示例

文章图片
节点进入场景树时, 将调用_ready()函数, 这是查找游戏窗口大小的好时机:
GDScript
func _ready():screensize=get_viewport_rect().size

现在, 我们可以使用_process()函数定义播放器将执行的操作。 _process()在每一帧都被调用, 因此我们将使用它来更新游戏元素, 我们希望它会经常更改。在这里, 我们将做到:
  • 检查输入
  • 沿给定方向移动。
  • 播放适当的动画。
首先, 我们必须检查输入-玩家是否按下了键?对于游戏, 我们有四个输入方向要检查。输入动作在项目设置中的” 输入映射” 下定义。我们可以描述自定义事件, 并为其分配不同的键, 鼠标事件或其他输入。在此演示中, 我们将使用键盘上的箭头键附带的默认事件。
我们可以使用Input.is_action_pressed()来检测是否按下了某个键, 如果按下该键, 则返回true;否则, 返回false。
GDScript
func _process(delta):var velocity = Vector2() # The player's movement vector.if Input.is_action_pressed("ui_right"):velocity.x += 1if Input.is_action_pressed("ui_left"):velocity.x -= 1if Input.is_action_pressed("ui_down"):velocity.y += 1if Input.is_action_pressed("ui_up"):velocity.y -= 1if velocity.length() > 0:velocity = velocity.normalized() * speed$AnimatedSprite.play()else:$AnimatedSprite.stop()

我们检查每个输入并从速度中加/减以获得总方向。例如, 如果我们同时按住向右和向下, 则所得的速度矢量将为(1, 1)。在这种情况下, 由于我们要添加水平和垂直移动, 因此播放器的移动速度要比仅水平移动的速度快。
如果我们对速度进行归一化, 就可以避免, 这意味着我们将其长度设置为1, 然后乘以所需的速度。这意味着没有更快的对角运动。
【Godot的第一个游戏项目示例】小费
如果我们以前从未使用过矢量数学, 或者需要复习, 则可以在Godot上的矢量数学中看到有关矢量用法的解释。知道这很高兴, 但是对于本教程的其余部分而言, 则不是必需的。
我们还检查播放器是否在移动, 以便我们可以启动或停止AnimatedSprite动画。
$返回该节点相对路径上的节点, 如果找不到该节点, 则返回null。由于AnimatedSprite是当前节点的子代, 因此我们可以使用$ AnimatedSprite。
$是get_node()的简写。因此, 在上面的代码中, $ AnimatedSprite.play()与get_node(” AnimatedSprite” )。play()相同。
现在我们有了一个运动方向, 我们可以通过将以下内容添加到_process函数的底部来更新Player的位置, 并使用clip()防止其离开屏幕:
GDScript
position += velocity * deltaposition.x = clamp(position.x, 0, screensize.x)position.y = clamp(position.y, 0, screensize.y)

小费
钳位值意味着将其限制在给定范围内。
单击” PlayScene” (F6)并确认我们可以在屏幕的各个方向上移动播放器。
警告
如果我们在” 调试器” 面板中看到一个指向” 空实例” 的错误, 则可能意味着我们将节点名称拼写错误。节点名称区分大小写, 并且$ NodeName或get_node(” NodeName” )必须与我们在场景树中看到的名称匹配。
选择动画
我们需要根据方向更改AnimatedSprite正在播放哪个动画。我们有一个” 右” 动画, 应使用flip_h属性将其水平翻转左移, 而有一个” 上” 动画, 应将其使用flip_v垂直翻转以向下移。让我们将此代码放在_process()函数的末尾:
GDScript
if velocity.x != 0:$AnimatedSprite.animation = "right"$AnimatedSprite.flip_v = false$AnimatedSprite.flip_h = velocity.x < 0elif velocity.y != 0:$AnimatedSprite.animation = "up"$AnimatedSprite.flip_v = velocity.y > 0

再次播放场景, 并检查各个方向的动画是否正确。当我们确定移动正常进行时, 请将此行添加到_ready(), 这样在游戏开始时玩家将被隐藏:
GDScript
hide()

准备碰撞
我们希望Player能够检测到敌人何时击中它, 但是我们还没有发现任何敌人!可以, 因为我们将使用Godot的信号功能使其正常工作。
扩展Area2D之后, 在脚本顶部添加以下内容:
GDScript
signal hit

这定义了一个称为” 命中” 的自定义信号, 当玩家与敌人碰撞时, 我们将使其发出(发送)。我们将使用Area2D来检测碰撞。选择” 播放器” 节点, 然后单击” 检查器” 选项卡旁边的” 节点” 选项卡, 以查看播放器可以发出的信号列表:
Godot的第一个游戏项目示例

文章图片
注意我们的自定义” hit” 信号也在那里!由于我们的敌人将是RigidBody2D节点, 因此我们需要body_entered(Object body)信号;当身体与玩家接触时会发出此信号。点击” 连接” 。然后在” 连接信号” 窗口中再次” 连接” 。我们不需要更改任何设置-Godot将自动在播放器的脚本中创建一个名为_on_Player_body_entered的函数。
连接信号时, 除了让Godot为我们创建函数外, 我们还可以提供要将信号链接到的现有函数的名称。
将此代码添加到函数中:
GDScript
func _on_Player_body_entered(body):hide() # Player disappears after being hit.emit_signal("hit")$CollisionShape2D.disabled = true

注意禁用区域的碰撞形状意味着它不会检测到碰撞。通过关闭它, 我们确保不会多次触发命中信号。 我们的玩家的最后一步是添加一个函数, 我们可以在启动新游戏时调用该函数来重置玩家。
GDScript
func start(pos):position=posshow()$CollisionShape2D.disabled=false

敌人的场景
现在该让我们的玩家必须躲避的敌人了。它们的行为不会很复杂:小生物将在屏幕边缘随机生成, 并沿随机方向沿直线移动, 然后在离开屏幕时生成。
我们将其构建到Mob场景中, 然后实例化该场景以在游戏中创建任意数量的独立Mob。

    推荐阅读