Adding a ram attack to our boss
Not only was the ram attack one of the first ideas I had for the boss, it was the first I wanted to implement.
I knew it would have a timing operation all to itself in addition to timing all of the boss actions.
So before this script became more and more complex, I wanted to get this working correctly.
Our Boss1 script variables related to the ram attack are shown above.
We have speed setting variables as well as delay timing variables and active status variables.
Coordinating the sequence of events for the ram attack is more complex than one might initially imagine.
In the Update() method of our Boss1 script, we check for several flag variables to know if it is okay to being a new boss action.
If so, a random number determines what boss action will occur, in this case if the number is 0, 1, or 2 giving the ram player attack a 30% of happening on any given boss action.
If selected, we set our _startRamPlayer and _ramPlayerActive flag variables to true.
I need separate variables because one will initiate a sequence of events, and the other will let us know the sequence is still ongoing so that no other boss actions occur during this time.
Our Update() method checks every frame update for these flag variables and will start the ram action by calling InitiateRamPlayer() method, then setting _startRamPlayer to false so that this only occurs in one frame.
Then the Update() method checks for _moveBossForRam and if so uses transform.Translate to move the boss accordingly.
Since Update() method also calls RotateTowardsPlayer() if the flag variable is true, which it will be as seen below, the boss ship will follow the player movement until it is ready to ram.
At that point, our Translate call only needs the Vector3.down direction since our boss game object is already pointed in the direction we want it to go.
Once our Update method kicks things off it calls InitiateRamPlayer().
Here we make sure to set _rotateTowardsPlayer to true so that our boss game object will start rotating to follow the player as they move.
We then use a coroutine to delay the next step in the sequence, calling RamPlayerRoutine();
Our _bossRamDelay is set in our script variables to 3f, or 3 seconds.
After 3 seconds pass, RamPlayer() is called.
Our boss ship will stop rotating to follow the player, essentially locking in the attack trajectory at this time.
If we moved immediately the player would not be able to dodge this attack.
So we call another coroutine, RamDelay();
We don’t want to give the player too much time, so there is a slight .2 second delay and then _moveBossForRam is set to true which will trigger the movement of our boss game object in the Update() method.
Then we call the final coroutine, ReturnToStart(), which has a 5 second delay.
This ensure the boss moves off the player screen completely before resetting the boss game object a position above the screen.
To do that, we call ReturnToStartPosition() which resets our _moveBossForRam flag to false, manually sets the position and rotation of the boss game object, sets _bossAboveScreen to true and _bossActionInProgress to false.
Our Update() method sees that _bossAboveScreen is true and that our location is higher on the y axis that 5f, thus it moves the boss game object downwards using transform.Translate.
Once the boss reaches the starting position, we reset our flag variables to false and the boss will start its next boss action.
Now we should have a working ram attack, which we can test using the code previously shown in the original adding a boss wave article to trigger this attack specifically and look for any bugs or errors.