Adventures in GameDev with GameDevHQ! Day 23: Creating modular powerup systems.
As we have several powerups in our Galaxy Shooter game, would it make sense to write a seperate script for each one of them depending on their behavior? Obviously not! That’s a lot of unnecessary work, we can create a modular system within one script by assigning each powerup a number and then have the main powerup script behaving accordingly according to the number it’s given. So let’s say 0 is tripleshot, 1 is speed, and 2 are shields.
First, we’ll set up a variable for this id, and we’ll begin to work with it.
While we’re in the Powerup script, Let’s write some pseudocode inside of the OnTriggerEnter function.
Ok, we basically wrote the Tripleshot code yesterday, now all we need to do is wrap it in an if statement.
Well that was easy, let’s continue and do the other ones. We’ll write the actual functions later.
“Oh, come on! it can’t be this easy, can it?” You ask.
Yes. Yes it can.
So let’s write the rest of the function in the player script
SpeedBoost
Since we want our player to move twice as fast, we’ll be multiplying our speed by 2 when speedboost is activated. But just to be safe, let’s put it in a descriptive variable:
We’ll put it after a SerializeField. Now if there’s any teammate or producer or game designer wants to fiddle around with the number to get just that perfect feel, they’ll be able to do so direct from Unitys interface.
Now just like the tripleshot, we’ll create a public function accessible from the powerup to activate the speedBoost.
Ok, we’re just assigning a number to _speedBoost, surely there’s more?
Well, yeah. We’re starting a Coroutine to finish the speedboost after a few seconds just like we did the Triple laser!
Ok, you just changed the _speedBoost variable aga..Ohhhhhhhh!
Right! Let’s go to our player movement!
We already covered player movement on day one so I’m just going to focus on the important line:
Seems like a lot to take in, but we’re just directly taking the horizontal and vertical input of the player and directly sticking them in the x and y slots of a new Vector3. Then we just multiply it by _speed and Time.deltaTime like before with the small exception of adding _speedBoost to the mix! When it’s activated, you’re moving twice the speed, when it’s off, it returns to being 1 and anything multiplied by 1 is of course, itself, so speed is no longer affected!
Shields
The shields are just as simple to implement. There’s a bit of a cheat when creating an animation and that’s just dragging all the frames into the scene and Unity will put them all together for you. You just need to give it a name.
Next, child the shield to the player and set the x and y to 0. Also be sure to set the sorting layer to foreground so it doesn’t appear behind the galaxy backdrop. Now when you move the player, the shield will move with it. Much easier than doing it via code, Let Unity do the work!
One final thing, we want to turn off the shield, that part we will turn on via code when we get our powerup. Go ahead and prefab the player, just to be safe. or override if you already did.
Now we’ll want to give it a variable in the player code.
Enter the prefab and drag the shield into the variable. Believe me, if you do it this way, you’ll save yourself a lot of headaches.
Ok, now we’ll create the final public function the powerup will call for shields:
Why no coroutine? You get to keep the shield forever until another ship hits it. Good deal, no? So now that it’s set up. Let’s create that boolean for the shield since we didn’t really create it.
We’re hopping around, but this is what programming is sometimes like. You create things out of sequence depending on the need. That said, we’re almost finished! Since we want our shields to protect us from damage, it makes the most sense to put our code in the Damage() section. So let’s write some pseudocode.
So if our shields have been activated and they’re hit by an enemy ship, don’t do anything to the ship. The ship is safe. just turn the shields off and give control back to the program. do not pass go, do not delete one life.
so if the shield is active, when an enemy hits, _isShieldActive returns to false meaning this particular set of code won’t run again until it’s activated again. the graphic of the shield is also turned off using SetActive(false).
Return; breaks out of the function and tells unity to ignore everything after it. Particularly the _playerLives being reduced by one. Your ship is now protected with shields!
We’re almost finished! Now the only thing we need to do is put all of our powerup gameobjects into our spawnmanager and have it randomly choose one of them every few seconds:
We’re going to make a minor change, instead of powerUp, we’re going to change our variable to powerUps and we’re going to add some brackets to make it an array.
An array is a set list of items in your code. once you have a size for it, it’s set in stone. You can’t make it bigger or smaller. Lists however are a little more forgiving, you can change the size of a list. There are advantages to both, but that’s a story for another time.
Now select the spawner and in the script, you’ll see a plus sign below the powerups. Hit it a couple times so you have 3 spaces. It’s important that you drag the powerups in this order because you’ll notice there’s slot numbers where you’re dragging the powerups into. We’re putting Tripleshot into 0, speed into 1, and shield into 2.
Remember when we were giving IDs to powerups? Now you’re gonna see something really cool. These slots numbers are the positions in the array that the powerups are in. So
_powerUps[0] is…you guessed it, Tripleshot!
_powerUps[1] is speed and _powerUps[2] is shield.
Now we’ll spawn them randomly using Random.Range(1,3) !
Remember Random.Range subtracts 1 from ints.
This is the same instantiate code from yesterday but the only difference is _powerUps[] is choosing a random number between 0 and 2 and depending what number it chooses, the appropriate powerup will be spawned!
Tomorrow, we’ll go over the switch statements to make our code even more sleek!