Homing Missiles
This is the final powerup I’m adding to my 2D Galaxy Shooter game. This will be a rare powerup. When collected, the player will be given 3 homing missiles that can be used when they press the ‘M’ key. When launched the missile will home in on the nearest enemy and take it down.
I’ve implemented many powerups in the past. I’m not going to make that a focus of this article. Instead, I want to look at the logic that makes the homing missile behavior possible.
On the surface, this challenge seemed straight forward to solve. Get all of the enemies on the playing field, loop through them and determine which was closest and head for that enemy. However, as the number of enemies increased, it became apparent, it wasn’t that straight forward.
I have to admit that I struggled with this logic a bit. Turns out I needed to learn a little about Quaternions — specifically LookRotation and Slerp. A great article by Simon Leen brought this to my attention and helped me fill in the blanks that I was missing.
I’m not sure that this is the most optimized way of accomplishing this task, but it seems to do the trick with the relative simplicity of my 2D Galaxy Shooter game. With larger, more complex games, this might not be the most efficient implementation.
First up, I need to declare a few variables. Of note here is an array of game objects to store the enemies, a Transform to store the target enemy, a few float variables to analyze distances, a Quaternion to calculate the proper rotation of the enemy, and two variables to control the speed of the homing missile and how long the homing missile will live before destroying itself.
To latch on to the nearest enemy, I first need to get all of the enemies on the playing field. I use the FindGameObjectsWithTag method, looking for the tag of “Enemy”. If enemies are found, I run the method responsible for setting the enemy target.
In the SetEnemyTarget method, I create a variable to hold the enemy’s position and I store the current position of the homing missile. Then I loop through all of the enemies in the array of enemy game objects.
Inside the foreach loop, an if..else is used to determine if this is the first iteration of the for loop. If it is, the target enemy is set from the enemy transform currently being analyzed. The enemy’s position is stored. The enemy’s rotation is calculated using Quaternion.LookRotation. The distance to the enemy is calculated and stored and the closest enemy distance is set to the distance to the enemy being analyzed.
The else block is similar. Except we compare the distance of the next enemy to the one before it. If that enemy is closer, that enemy becomes the new target of the homing missile.
The process is repeated for all enemies on the screen. Once the for loop is exited, I move the homing missile toward the enemy, by calculating the distance to move the missile, move the missile toward the targeted enemy and adjust the rotation of the homing missile to turn it toward the enemy.
Quaternion.Slerp is what controls which direction the homing missile is pointing as it tracks the enemy and moves toward it.
The homing missile’s time to live is controlled by a coroutine that is kicked off in the Start method.
As you’ll note in the video above, when the player collects the powerup, they’re awarded with 3 homing missiles. Unlike other powerups in the game that have a cooldown, these game objects are precious so I’m letting the player decide when to use them. To launch a homing missile, the player presses the ‘M’ key. Each time they do, the count in the upper left reduces by 1.