通过制作2D平台学习Godot 4-第7部分:炸弹设置
之前我们停在了创建游戏的前两个关卡的地方。在这一部分中,我们将创建炸弹,当炸弹生成器生成炸弹时,炸弹会在场景中移动。我们将在下一部分中创建炸弹生成器。您可以将炸弹想象成《大金刚》中的桶,将炸弹生成器想象成愤怒的大猩猩!
您将在本部分中学习到的内容:
如何使用 StaticBody2D 节点。
如何使用queue_free()从场景中删除节点。
让我们创建一个以 Area2D 节点为根的新场景。它应该有以下子节点:AnimatedSprite2D、CollisionShape2D(已为其分配 CircleShape2D)和 Timer 节点。这些节点将允许我们检查碰撞是否与我们的玩家发生碰撞,如果是,它应该播放动画并从我们的场景中移除炸弹。如果炸弹没有与我们的玩家发生碰撞,它应该在几秒钟后“自毁”
让我们为场景分配一个新脚本并将其保存在脚本文件夹下。
然后,将您的 Timer 节点timeout()信号以及您的 Area2D 节点body_entered()信号连接到您的脚本。
在开始编码之前,让我们设置一些动画。在我们的 AnimatedSprite2D 节点中,让我们创建一个新的 SpriteFrames 资源,其中包含两个动画:“移动”和“爆炸”。
对于移动动画,请导航至“res://Assets/Kings and Pigs/Sprites/09-Bomb/Bomb On (52x56).png”,并将所有四帧分配给动画。您现在可以将循环和 FPS 保留为默认值。
对于爆炸动画,请导航至“res://Assets/Kings and Pigs/Sprites/09-Bomb/Boooooom (52x56).png”,并将所有六帧分配给动画。您现在可以将循环和 FPS 保留为默认值。
在您的脚本中,当炸弹进入游戏场景时,让我们将移动动画设为默认动画。
### Bomb.gd
extends Area2D
#default animation on spawn
func _ready():
$AnimatedSprite2D.play("moving")
在我们的func _on_body_entered(body):中,我们需要检查玩家是否正在进入炸弹场景的碰撞形状,如果是,我们应该播放爆炸动画并启动计时器。计时器将允许我们在从场景中移除炸弹之前延迟 1 秒的动画。
### Bomb.gd
extends Area2D
#default animation on spawn
func _ready():
$AnimatedSprite2D.play("moving")
func _on_body_entered(body):
#if the bomb collides with the player, play the explosion animation and start the timer
if body.name == "Player":
$AnimatedSprite2D.play("explode")
$Timer.start()
然后,在timeout()函数中,我们需要从游戏场景树中删除场景。要从场景中删除节点,我们使用对象queue_free()。这是从场景树中删除或“销毁对象”的最标准化方式。还有free(),它们之间的主要区别在于queue_free() 会在下一帧被调用。如果 Bomb 场景有效(即存在),我们才会删除 Bomb 场景。
### Bomb.gd
extends Area2D
#older code
#remove the bomb from the scene only if the Bomb exists
func _on_timer_timeout():
if is_instance_valid(self):
self.queue_free()
现在,如果你运行主场景并实例化炸弹,当玩家撞到它时,它就会爆炸并从场景中移除。
我们还希望炸弹在到达路径末端时爆炸。我们将在下一部分中设置此路径,但简单地说,此路径将从炸弹生成器的位置延伸到玩家的起始位置。一旦它到达末端且未与玩家发生碰撞,它就会爆炸。
我们可以通过一个新场景来实现这一点,这个场景将充当我们的墙壁,或者我们可以引用我们的“关卡”Tilemap 节点作为主体。这意味着如果炸弹与关卡图块地图中的图块发生碰撞,它就会爆炸。这样做的缺点是,你在创建路径时必须非常小心——因为与你的 Tilemap 的任何碰撞都会导致炸弹爆炸。我将向你展示这两种方法。
选项 1:使用 Tilemap 引爆炸弹
如果炸弹与主场景(和 Main_2)中的“Level”Tilemap 节点发生碰撞,则为了引爆炸弹,我们可以简单地扩展现有的炸弹功能,如下所示:
### Bomb.gd
#older code
func _on_body_entered(body):
#if the bomb collides with the player, play the explosion animation and start the timer
if body.name == "Player":
$AnimatedSprite2D.play("explode")
$Timer.start()
#if the bomb collides with our Level Tilemap (floor and walls).
if body.name == "Level":
$AnimatedSprite2D.play("explode")
$Timer.start()
现在,只要炸弹与 Level 节点上的图块发生碰撞,它就会爆炸。请记住,炸弹只有在与墙壁或地板(任何指定了碰撞的图块)发生碰撞时才会爆炸。您的背景和装饰应该是安全的。将炸弹移到图块上,看看这是否有效。
选项 2:使用碰撞场景引爆炸弹
如果您希望炸弹仅在到达特定区域时爆炸,则必须创建一个新场景。创建一个以StaticBody2D节点为根的新场景,并向其添加 CollisionShape2D 节点。您可以将碰撞的形状设为 RectangeShape2D,然后将其向下拖动成一个长形。StaticBody2D 节点是静态的 2D 物理的物理体。它适用于地板、墙壁、拾取物,以及我们例子中的碰撞。炸弹场景中的 Area2D 节点将能够与 StaticBody2D 节点发生碰撞。
将根重命名为“Wall”,并将场景保存在 Scenes 文件夹下。
现在,只需在主场景中实例化您的墙场景。您可以通过缩放模式工具更改墙的 x 和 y 比例。将此墙放置在您想要爆炸区域的位置。这样您就可以将墙做成任何您想要的尺寸。对我来说,这将是我们场景的起点。
在我们的脚本中,我们现在可以检查炸弹是否与墙壁相撞。我们将使用字符串的begins_with方法来检查名称是否以“Wall”开头。因此,如果我们在主场景中多次实例化我们的墙壁场景,即使名称是“Wall”、“Wall2”、“Wall_x”等,它也会爆炸。
### Bomb.gd
#older code
func _on_body_entered(body):
#if the bomb collides with the player, play the explosion animation and start the timer
if body.name == "Player":
$AnimatedSprite2D.play("explode")
$Timer.start()
#if the bomb collides with our Wall scene, explode and remove
if body.name.begins_with("Wall"):
$AnimatedSprite2D.play("explode")
$Timer.start()
现在如果你把炸弹放在墙壁区域并运行场景,它就会爆炸!
如果您有多面墙,您可以在 Node2D 节点中组织它们。
您的最终代码应如下所示。
恭喜您创建了炸弹和炸弹触发器!在下一部分中,我们将创建一个炸弹生成器,它将生成炸弹并沿着特定路径移动。每次炸弹爆炸并从场景中移除时,它都会不断生成。
现在是保存项目并备份的好时机,这样如果出现任何破坏游戏的错误,您就可以恢复到此部分。在继续本系列之前,请回顾并复习您学到的知识,一旦您准备好,我们将在下一部分与您见面!