Boss Fight Implementation Part 5: Movement Behaviors

Now that the boss creature in my game can do pretty much everything except move, it is finally time to mobilize this giant anglerfish! My objective for this article is to implement all of the movement behavior for my boss…and more!

Starting in the Anglerfish class, which is the script attached to my main boss game object, I add a handful of variables. A trio of float variables are stored to handle cruising, battling and ramming speeds. A quartet of bool variables will be used to check a variety of conditions. Four Vector3 variables are used to store position locations for movement. Lastly, a variable for the Player script is created.

The Player script is found and grabbed via GetComponent in void Start.

I now use some brute force in void update to get all of my boss movement working, by checking a variety of conditions throughout a mess of if else statements. Checking all of these conditions every frame update is going to be taxing for the computer, so rather than break down what is happening in this quick but sloppy update method, I will break down the smaller bits as I move them into coroutines. Once I am finished here, I will be able to delete the update method entirely as it will no longer be needed.

Backpedaling a little, I revisit the variables on the Anglerfish class and add some handles to the AnglerfishLantern and UI Manager scripts, as well as the Animator on the Anglerfish Jaw game object.

Void Start connects the bits and pieces. I finish by assigning the current speed of the boss to be the battle speed value, starting a coroutine for the entrance behavior, and then calling a method on the UI Manager to show the player some related text elements.

The entrance movement coroutine uses a while loop to run as long as some conditions are met. The boss moves towards the stored entrance position at the designated cruising speed. Once the entrance position is achieved, the has entered bool flips to true, the boss fight text routine displays and another coroutine is started for the battle ready routine.

Here is a clip of the boss moving with the entrance routine.

The battle ready coroutine works in the same way, only moving towards the designated battle position for as long as the isBattleReady bool is set to false. Once the boss arrives at the battle position, isBattleReady is set to true. The nextPosition variable is assigned a position value using two local variables to store random values on the X and Y axis, and then the hasNextPosition variable is set to true. A coroutine for the battle movement is started and the lantern game object is contacted to start it’s firing method.

Here is the boss moving towards it’s battle ready position in the battle ready routine.

The battle movement coroutine runs in another while loop for as long as it has a next position and the boss is not ramming the player. The end of the previous routine gave the boss an initial next position to move towards. Once the next position is met again, the hasNextPosition bool is set back to false, a new next position is assigned using the same technique, and then the hasNextPosition bool is set back to true. Now the boss will continuously generate new random locations for it to move towards, within a designated boundary.

Here is the boss moving using the battle movement routine.

The ramming routine is triggered after the jaw has opened and the player has had time to fire at the target. The animator on the jaw is called to set the IsChomping bool to true, which starts the chomping teeth animation. While the isRamming bool is set to true, the boss will move quickly to the left at the designated ramming speed, damaging the player on contact. As soon as the boss visually dashes herself off the screen to the left, the isRamming bool resets to false, and the boss is repositioned to the stored respawn position (off the right of the game scene). The animator on the jaw is contacted again to stop the chomping teeth animation and the coroutine for the battle movement is started again.

Here is the boss ramming the player (lucky avoid) at the end of the attack cycle, and then returning to fight some more!

The ramming anglerfish public method sets isRamming to be true and then starts the ramming coroutine above. This method is currently being called by the AnglerfishLantern class shortly after the Jaw closing animation is triggered.

These methods are also called by the AnglerfishLantern class. The SpeedDown method will slow the boss down to cruisingSpeed when the jaw is open and the player can shoot at the target. Conversely, the SpeedUp method will bring the boss back to normal battle speed once the jaw has closed.

The public IncrementSpeeds method is called by the AnglerfishTarget class, which is what is handling all of the health and damage. If the health dips below 50%, the first call is made to increase all speed values by 1. If the health dives below 20% the second call is made for the final incrementation. This will make the lantern and the target the hardest to hit at the end of the fight!

Thanks for reading along while I get my boss creature moving correctly! I hope you join me in my next article where I add some on death and a winning game over behavior. Happy coding!

I am an artist and musician, that is currently diving headfirst into game development with C# and Unity3D.