Cleaning up the Homing Missile code
So I had working homing missiles by the end of the last article, but wow, was that an embarrassing jumble of code to get there.
I spent a couple hours cleaning it up and squashing bugs, so let’s go over it from start to finish with the new approach.
Overview of the rewritten player script for homing missiles
Never would have thought I’d need to add this many variables for this simple functionality, I’m sure even this could be cleaned up further but this is where I’m at.
The key addition here is the adding of a 2nd variable for delaying adding missiles so I could track each missiles add delay individually.
Our Update() method is currently checking whether it needs to move any active homing missiles, whether the player is trying to fire another homing missile, and if we need to delay adding a homing missile.
The issue is that when missile 1 (right side of ship) exists, missile 2 is moving towards target, and the powerup is collected to add another missile 2, well it gets assigned to the same array field for the existing missile 2.
This screws up movement of the current missile 2 and firing of the new missile 2.
So we add a delay that the new missile won’t be added to the player until missile 2 in motion has been destroyed.
The AddHomingMissile() got a complete rewrite.
Adding a second variable for the missile delays, so each missile had its own bool delay variable, made things simpler to follow along and correct for.
We start with a simple check of our homing missile counter, _currentHomingMissiles, being < 2 or = 2.
Depending on whether we determine a missile being added is trying to overwrite a current fired missile still in flight, thus not destroyed and occupying that field of the _homingMissilesGO array, we’ll either add a new missile or delay it until the current missile has been destroyed.
We’ll also increment our homing missile count when appropriate, including as soon as we set a delay.
Now, this method is not called every frame, so how will it know when to implement the delay based on checking for the current game object missile that hasn’t exploded yet to be destroyed?
Normally, AddHomingMissile() will only fire off when a powerup triggers it to.
This new DelayAddHomingMissile() method gives us a place to trigger it.
Remember, in our Update() method, which runs every frame of the game, when we know a missile is in waiting to be deployed due to _delayAddHomingMissile1 or 2, we can call this DelayAddHomingMissile() method which in turn calls AddHomingMissile() to repeatedly check when it can safely add the new missile to our player ship.
Our FireHomingMissile() method, is triggered from our Update() method when player input calls for it and _currentHomingMissiles variable is > 0.
Now, there can be several issues with losing the assigned target enemy so we always do our best to keep a current living enemy assigned as the target.
We also have a firing cooldown to prevent the mouse input from triggering both missiles due to being checked every frame so fast.
We make sure to fire the correct missile based on _currentHomingMissiles, 2 for the 2nd(left side of ship) and 1 for the first added missile (right side of ship).
We use some script scope level variables, _missileFired1 and 2, to keep track of what missile was last fired.
I’ve also added an initial forward motion with Rigidbody2D().AddForce so that the momentum from the player moving down when firing doesn’t send our missile way down before going forward.
Note that the x value is set, not the y value. That is because our sprite is not oriented vertically as it should be, so it has a rotation in game that makes it look vertical.
That rotation changes what axis controls the “up” direction as it were.
If possible, always use a sprite that is correctly oriented to begin with, much less of a headache.
We decrement our _currentHomingMissiles counter and start the FireMissileCooldown() coroutine to prevent double firing missiles.
After we’ve fired the appropriate missile at an appropriate target we pop out of that if else statement and set our _moveHomingMissiles = true so that it will trigger in our Update() method and begin actively moving the fired missile towards its target.
In the last article, this MoveHomingMissiles() method had a lot of copy paste code.
It has been rewritten to call another method with that code in MoveHomingMissile() (closely named, one ends with an s and one does not).
So, now this is more for the logic of are we moving something and if so what is the target.
Did the target die before the missile reached it?
Create a new target.
We’ve also moved the Enemy List and target priority code into its own method.
This code hasn’t changed much from when it was in the MoveHomingMissiles() method.
It gets all the enemies, compares the strength level, and returns the strongest nearest enemy game object to whatever called it.
Our new MoveHomingMissile() method, no s on the end, takes all of that copy paste code we originally had and reformats it to take the current missile and missile target and then move based on this.
Additionally had some older code determining direction competing with some newer code that also determined direction.
I simply removed that and used the direction variable being generated in the rotate code.
We also still have EnableHomingMissileFiring() which can be called from the enemy script once a missile collides with it.
Enemy script OnTriggerEnter2D
So here we show that we reenable HomingMissileFiring when a missile hits this enemy as the missile game object has been destroyed in the line above, Destroy(other.gameObject);.
And that’s it, that’s our redesigned Homing Missile code in working order.