Creating a Homing Missile Weapon
The next feature we will add to Galaxy Shooter is a homing missile weapon. This will give the player a satisfying new way to blow up the enemy spaceships. It’s one thing to just wish for some new feature, but another things entirely to make it. This is definitely the most complex feature yet!
Let’s break it down into all the parts we will need to create this:
- Find a missile sprite online to use for this new projectile prefab
- Implement a new input button that allows both keyboard and controller to fire missiles
- Create a UI that shows how many missiles the player has available
- Create a new powerup that gives the player missiles
- Missiles will seek out nearby enemies (this is the tough one!)
- Polish as necessary, adding sounds and additional visual effects
Thankfully, most of these parts are things that I’ve covered before in previous articles. I’ll cover the progress just a little bit, so we can get to the juicy part.
First, the missile projectile itself. Here’s a free missile that I found on https://opengameart.org/
To make this prefab, we’ll just copy most of what we did for the laser weapon. We can add a Collider2D, and a laser script so it moves forward automatically. Then we add the ability for the player to fire missiles.
I’m using _missileOffset and _mirrorOffset in order to control where the missiles appear. I’d like for them to appear on the sides of the player, like they are coming out of missile bays.
Next is the UI. By limiting the amount of missiles and re-using the missile picture, we can use images to represent how many missiles remain.
Whenever the player’s missile count changes, we can tell the UI manager to activate or deactivate the right number of missile images.
This time for the new powerup, I decided to go with a different design that uses the missile sprite yet again, instead of having text.
Implementing it is just as easy as all the other powerups. Just add it to the enum and have it call another Player method.
Now for the hard part. We’ll want a new Missile script that will cause the missiles to seek enemies by rotating and moving toward them. This can take a lot of trial and error to set up, since dealing with rotation is tricky in any game engine, and Unity is no exception.
The main idea here is to acquire an enemy target, get the direction toward that enemy as a vector, and then use that vector to determine how the missile should rotate. By using Vector3.SignedAngle to compare the missile’s local direction to the target direction, we get some number of degrees that we want to rotate. We can then limit it by _turnDegreesPerSecond so we don’t have missiles that immediately snap towards the enemy target.
Now, how does a missile acquire targets? We can do so by getting a list of enemies, then going through all of them one at a time with a foreach loop. Inside the loop, it will compare each enemy to the closest one we have yet found. If the current enemy is even closer, it will pick that one. This will guarantee that missiles will track the closest enemies whenever they need a new target.
Now we can attach the script to the missile prefab, assign _velocity and _turnDegreesPerSecond to some reasonable values in the inspector, and then run the game to try it.
Looks pretty good, but there’s some minor problems. Both missiles tend to go after the same enemy, and when the enemy is destroyed by one missile, the other loops around the enemy explosion in an attempt to hit it.
We can at least fix the looping problem easily by giving a new variable to enemies called “_isDead”, which missiles can then use to determine that the enemy is exploding and shouldn’t be targeted.
We can use a Property to help. _isDead information is accessible by the Missile and other classes, but by including “private set”, we ensure that the Enemy is the only thing that determines if it’s dead.
Now we can use this new property to make the missiles a bit smarter. When seeking a new target, the missiles will ignore enemies that have _isDead set to true. The missiles will also save the enemy script and check if it’s dead on every update, so they know to look for a target that isn’t exploding.
Awesome! Now we have a new toy that makes blowing up enemy ships easy. There’s still a lot of polish we can do for this missile, like adding sounds, but getting the basic feature working perfectly well is a great accomplishment.