Powerups could not resist this player's keypress. Click here to learn the secret!
This next challenge was both fun and interesting. The idea being when the player pressed the c key, all the powerups would fly to the player until they were absorbed or shot by an enemy on the way.
The most obvious method to solve this was to use an event, or something called the observer pattern. An event is a way to broadcast that something’s happened, be it a keypress, a function, or any kind of action to any object that’s subscribed to seeing that event happen. In our case, we’re going to press the C key, and whenever it’s pressed, powerups will float towards the player.
To have an event, you need a delegate. What’s a delegate? Think of a delegate as variables for functions. instead of putting a value or a string of letters into a variable, you’re putting an entire function into a delegate.
The cool thing about delegates is you can assign more than one function to them, so when you call the delegate, you can run a whole chain of functions all at once, and it works like a mailing list where you subscribe functions to delegates and this subscription pattern is just what we need to tell our powerups to float towards the player.
So in the Player.cs script, we create a delegate called PowerupMagnet(). Notice there are no parameters in the delegate. That means we can only subscribe to methods that have no parameters. That’s another small-print rule about them. The functions you’re assigning to delegates must match the return type and parameters. So since our delegate is void with no parameters, any function we subscribe to must be the same.
Ok, now for the really cool part! We now create an event. We define it as a public event since we want anyone to subscribe, and we want it static, which means this event will no longer be tethered to the class, it will be available throughout the entire game/program. It will be of the function type we just created, PowerupMagnet, and we’ll call it powerupMagnet with a lower p. The important thing to remember now is that this variable *IS* the function. it’s pointing to the memory address of where PowerupMagnet is, we’re just making it available to everyone, anywhere.
Now that we’ve set the foundation, let’s build the actual event:
Still, in the player script, let’s create a function called CallPowerups().
We’ll check for the keypress, and first, we do a check to see if anyone is subscribing to the actual event itself. If there’s no one subscribing, it will skip the brackets and nothing will happen but if there happens to be a powerup on the screen that does happen to be subscribing to the event, then we’ll activate it with powerupMagnet(). tl;dr: Press C, announce powerupMagnet().
Of course, for CallPowerups to work, we’ll need to place it in Update so it’s constantly called along with the other methods that need constant updating.
Believe it or not, that’s all the code we need for the player! Let’s go to the powerup code now.
This may look like a lot, but it’s really pretty short and direct. Let’s take a look:
We create a boolean called CPressed which will always be set to false until the player presses C, which it will then be set to true. Easy enough!
OnEnable is a function that runs before the start and is immediately called whenever a gameObject is instantiated, so it’s here where we’ll subscribe to the event. We’re accessing the powerupMagnet delegate directly through the Player. We did this when we made the delegate public and static. No more dragging the player object into a variable holder! We can just call it anytime!
And just as we subscribe to the event, best practices tell us we need to unsubscribe to the event at some point to free up memory, so we do that in the OnDisable function which gets run when the object is destroyed.
Ok! So the event is announced! Our Powerup is subscribing to it! We now see the event is subscribed/attached to a function called HeadsTowardPlayer! Let’s see what it does!
Well that’s a bit anti-climactic. Well, consider this a butterfly flap that makes some big effects in another function!
Here in the main Update function, we originally just told the powerup to float down with the transform.Translate function. But with the addition of the event, I wrapped that code in brackets and made it an else statement. Now the code checks to see if the CPressed boolean is true, and now that it is, it will take note of the players location, place the now familiar direction algorithm into the _direction variable, and we’ll change the powerup speed to add a smidge more oomf to the powerups pace.
After the check, it will drop down to the tranform.Translate where it will move the powerup towards the player, the rest of the code is for when the player lets go of the c key, the powerup will continue to move down, and if it hits the bottom, gets destroyed and of course we reset the CPressed value to false so the powerups can behave normally and float down.
And that’s all there is to it! Delegates and events can be intimidating but it’s important you learn them as soon as possible as they can and will improve your game programming experience!
I’ve found some of the best information on Delegates and Events come from Unitys own programming series on Youtube.
GameDevHQ is also home to some of the best explained Unity videos on the internet, I highly suggest subscribing.