Powerups

There are many possibilities for objects that give the player a small advantage or powerup. In this section, you'll add a powerup item that gives the player a small time bonus when collected. It will appear occasionally for a short time, then disappear.

The new scene will be very similar to the Coin scene you already created, so click on your Coin scene and choose Scene | Save Scene As and save it as Powerup.tscn. Change the name of the root node to Powerup and remove the script by clicking the clear script button: . You should also disconnect the area_entered signal (you'll reconnect it later). In the Groups tab, remove the coins group by clicking the delete button (it looks like a trash can) and adding it to a new group called powerups instead.

In the AnimatedSprite, change the images from the coin to the powerup, which you can find in the res://assets/pow/ folder.

Click to add a new script and copy the code from the Coin.gd script. Change the name of _on_Coin_area_entered to _on_Powerup_area_entered and connect the area_entered signal to it again. Remember, this function name will automatically be chosen by the signal connect window.

Next, add a Timer node named Lifetime. This will limit the amount of time the object remains on the screen. Set its Wait Time to 2 and both One Shot and Autostart to On.

Connect its timeout signal so that it can be removed at the end of the time period:

func _on_Lifetime_timeout():
queue_free()

Now, go to your Main scene and add another Timer node called PowerupTimer. Set its One Shot property to On. There is also a Powerup.wav sound in the audio folder you can add with another AudioStreamPlayer.

Connect the timeout signal and add the following code to spawn a 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))

The Powerup scene needs to be linked by adding a variable, then dragging the scene into the property in the Inspector, as you did earlier with the Coin scene:

export (PackedScene) var Powerup

The powerups should appear unpredictably, so the wait time of the PowerupTimer needs to be set whenever you begin a new level. Add this to the _process() function after the new coins are spawned with spawn_coins():

$PowerupTimer.wait_time = rand_range(5, 10)
$PowerupTimer.start()

Now that you will have powerups appearing, the last step is to give the player some bonus time when one is collected. Currently, the player script assumes anything it runs into is either a coin or an obstacle. Change the code in Player.gd to check for what kind of object has been hit:

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()

Note that now you're emitting the pickup signal with an additional argument naming the type of object. The corresponding function in Main.gd can now be changed to accept that argument and use the match statement to decide what action to take:

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)

The match statement is a useful alternative to if statements, especially when you have a large number of possible values to test.

Try running the game and collecting the powerup. Make sure the sound plays and the timer increases by five seconds.