完成
你已经创造了一个有效可玩的游戏,但它仍然可以让你感觉更刺激一些。游戏开发者使用术语juicy来描述让游戏感觉良好的东西。juicy可以包括声音,视觉效果或任何其他添加物,增加玩家的乐趣,而不必改变游戏的本质。
在本节中,你将添加一些小的juicy且有趣的功能来完成游戏。
视觉效果
当你拿起硬币时,它们就会消失,这不是很吸引人。添加视觉效果将使收集大量硬币时更加令人满足。
首先将Tween节点添加到Coin场景。
什么是tween?
tween(补间)是一种使用特定函数随时间(从起始值到结束值)内插入(逐渐改变)某个值的方法。例如,您可以选择一个稳定更改值的函数,或者一个开始缓慢但速度加快的函数。补间有时也称为easing(缓冲)。
在Godot中使用Tween节点时,可以指定它来更改节点的一个或多个属性。在这种情况下,你将增加硬币的图形比例,并使用Modulate属性使其产生淡出效果。
将此行添加到Coin的_ready()
函数:
$Tween.interpolate_property($AnimatedSprite, 'scale',
$AnimatedSprite.scale,
$AnimatedSprite.scale * 3, 0.3,
Tween.TRANS_QUAD,
Tween.EASE_IN_OUT)
interpolate_property()
函数使Tween更改节点的属性。有七个参数:
- 要影响的节点
- 要改变的属性
- 该属性的初始值
- 该属性的结束值
- 持续时间(以秒为单位)
- 使用的功能
- 方向
当玩家拿起硬币时,补间应该开始播放。替换pickup()
函数中的queue_free()
:
func pickup():
monitoring = false
$Tween.start()
将monitoring设置为false可确保在补间动画期间玩家触摸硬币时不会发出area_enter()
信号。
最后,当动画结束时应删除硬币,因此连接Tween节点的tween_completed()
信号:
func _on_Tween_tween_completed(object, key):
queue_free()
现在,当你运行游戏时,你应该看到硬币在被拿起时变大了。这很好,但是当同时应用于多个属性时,补间会更有效。您可以添加另一个interpolate_property()
,这次更改精灵的不透明度。这是通过更改modulate属性(一个Color对象)并将其alpha通道从1(不透明)更改为0(透明)来完成的。请参阅以下代码:
$Tween.interpolate_property($AnimatedSprite, 'modulate',
Color(1, 1, 1, 1),
Color(1, 1, 1, 0), 0.3,
Tween.TRANS_QUAD,
Tween.EASE_IN_OUT)
文档
tween
声音
声音是最重要但经常被忽视的游戏设计之一。良好的声音设计可以为您的游戏增加大量的 juice,只需很少的付出。声音可以给予玩家反馈,将他们情感连接到角色,甚至成为游戏玩法的一部分。
对于这个游戏,你将添加三个声音效果。在Main场景中,添加三个AudioStreamPlayer节点,并将它们命名为CoinSound,LevelSound和EndSound。将每个声音从audio文件夹(您可以在FileSystem中的资源下找到)拖动到每个节点的相应Stream属性中。
要播放声音,请调用play()
函数。将$CoinSound.play()
添加到_on_Player_pickup()
函数,将$EndSound.play()
添加到game_over()
函数,将$LevelSound.play()
添加到spawn_coins()`函数。
能力提升 - 道具
新场景将与您已创建的Coin场景非常相似,因此请单击您的Coin场景并选择Scene | Save Scene As将其另存为Powerup.tscn。将根节点的名称更改为Powerup,然后单击清除脚本按钮删除脚本(下方截图)。在Groups选项卡中,通过单击删除按钮(它看起来像垃圾桶)删除硬币组,然后将其添加到名为powerups的新组中。
在AnimatedSprite中,将图像从硬币更改为powerup,您可以在res://assets/pow/文件夹中找到该图像。
单击以添加新脚本并从Coin.gd脚本中复制代码。连接area_entered信号。请记住,此功能名称将由信号连接窗口自动选择。
接下来,添加名为Lifetime的Timer节点。这将限制对象保留在屏幕上的时间。将Wait time设置为2,将One Shot和Autostart都设置为On。连接其超时信号,以便在该时间段结束时将其删除:
func _on_Lifetime_timeout():
queue_free()
现在,转到Main场景并添加另一个名为PowerupTimer的Timer节点。将其One Shot属性设置为On。您可以使用另一个AudioStreamPlayer添加音频文件夹中的Powerup.wav声音。
连接timeout()
信号并添加以下代码以生成Powerup:
func _on_PowerupTimer_timeout():
var p = Powerup.instance()
add_child(p)
p.screensize = screensize
p.position = Vector2(rand_range(0, screensize.x),
rand_range(0, screensize.y))
需要通过添加变量来链接Powerup场景,然后将场景拖动到Inspector中的属性中,就像之前使用Coin场景一样:
export (PackedScene) var Powerup
道具的出现应该是不可预测的,因此每当您开始新的关卡时,都需要设置PowerupTimer的等待时间。使用spawn_coins()
生成新硬币后,将其添加到_proces()
函数:
$PowerupTimer.wait_time = rand_range(5, 10)
$PowerupTimer.start()
现在你的道具出现了,最后一步是在收集一个道具时给玩家一些奖励时间。目前,玩家脚本假设它遇到的任何东西都是硬币或障碍物。更改Player.gd中的代码以检查已击中的对象类型:
func _on_Player_area_entered( area ):
if area.is_in_group("coins"):
area.pickup()
emit_signal("pickup", "coin")
if area.is_in_group("powerups"):
area.pickup()
emit_signal("pickup", "powerup")
if area.is_in_group("obstacles"):
emit_signal("hurt")
die()
请注意,现在你使用命名对象类型的附加参数发出拾取信号。现在可以更改Main.gd中的相应函数以接受该参数并使用match语句来决定要采取的操作:
func _on_Player_pickup(type):
match type:
"coin":
score += 1
$CoinSound.play()
$HUD.update_score(score)
"powerup":
time_left += 5
$PowerupSound.play()
$HUD.update_timer(time_left)
match语句是if语句的有用替代语句,尤其是当您有大量可能的值要测试时。
尝试运行游戏并收集道具。确保声音播放,计时器时间增加了五秒钟。
硬币动画
当你创建Coin场景时,曾添加了一个AnimatedSprite,硬币动画显示出光穿过硬币表面的shimmer(闪烁)效果。如果所有硬币同时显示,它看起来太有规律,因此每个硬币在动画中需要一个小的随机延迟。
首先,单击AnimatedSprite,然后单击Frames资源。确保将Loop设置为Off并将Speed设置为12*。
将Timer节点添加到Coin场景,并将此代码添加到_ready()
:
$Timer.wait_time = rand_range(3, 8)
$Timer.start()
现在,连接Timer的timeout()信号并添加:
func _on_Timer_timeout():
$AnimatedSprite.frame = 0
$AnimatedSprite.play()
尝试运行游戏并观察硬币动画。只需很少的改动就可以获得很好的视觉效果。在专业游戏中你会注意到很多这样的效果。虽然非常微妙,但视觉吸引力使得体验更加愉悦。
前面的Powerup对象具有类似的动画,您可以以相同的方式添加。
障碍
最后,通过引入玩家必须避免的障碍,可以使游戏更具挑战性。碰触到障碍将结束游戏。
为仙人掌创建一个新场景并添加以下节点:
- Area2D (命名为Cactus)
- Sprite
- CollisionShape2D
将仙人掌纹理从FileSystem侧边栏拖动到Sprite的Texture属性。将RectangleShape2D添加到碰撞形状并调整其大小,使其覆盖图像。还记得你在Palyer脚本中添加了area.is_in_group("obstacles")吗?使用Node选项卡(Inspector旁边)将Cactus主体添加到 obstacles组。
现在,将Cactus实例添加到Main场景并将其移动到屏幕上半部分的位置(远离Play产生的位置)。玩游戏,看看当你遇到仙人掌时会发生什么。
您可能已经发现了一个问题:硬币会在仙人掌后面产生,使它们无法拾取。放置硬币时,如果检测到硬币与障碍物重叠,则需要移动硬币。连接硬币的area_entered()信号并添加以下内容:
func _on_Coin_area_entered( area ):
if area.is_in_group("obstacles"):
position = Vector2(rand_range(0, screensize.x), rand_range(0, screensize.y))
如果您添加了前面的Powerup对象,则需要对其area_entered信号执行相同操作。