Examining the Logic for the Thrusters Slider Bar UI in my Unity “Space Shooter” Game Project.
Objective: dedicate an article to step through the logic I used to implement very specific behavior in the scaling “health bar” in my Unity game project UI to visualize the impact of using thrusters, or letting the system “cool down”.
Welcome to Part 2! Yay!
For those who missed it, “Part 1” can be found here!
Let’s start with a quick recap of the declared variables surrounding the “thruster core”.
Private integer coreTempDecrease adjusts the rate at which the thrusters core temperature will decrease over time once the Left-Shift key is released.
Boolean values _hasPlayerThrustersCooledDown and canPlayerUseThrusters checks if the Player has exceeded the maximum core temperature (which would render the Player vulnerable by shutting down its thrusters and weapon systems temporarily), while _coreTempCooledDown lets us know if the core temperature is back to safe levels.
We also need to cache a reference to the ThrustersCoreTemp script in order to get access to its void SetCoreTemp() method. This sets the starting core temperature at 0 (currentCoreTemp). We also set the maxCoreTemp to 1000 in order to cap the high limit of the slider value.
Since the ThrustersCoreLogic() is called from the Update() function, resetExceededCoreTempWarning is used to prevent the aural sound clip from repeatedly being triggered. This boolean value is set to False by default, gets switched to True when the core exceeds a value of 750 but remains below 1000, and calls the coroutine that plays the audio clip. Once the audio clip has finished playing, then the bool returns to False and is ready to be triggered once more when the slider value reaches 750+ again.
Section 1 — Laying out the visual and aural cues!
And since I tend to run down rabbit holes, I felt it was necessary to add some sort of audio clip and visual cues to warn the Player that the core temperature has reached one of three states:
temperature has reached a critical level (warning);
temperature has exceeded safe limits (overheating, systems shutting down); and
temperature has cooled down to a safe level (everything back in the green).
Let’s declare the following three AudioClip variables to store the desired aural warnings. I opted to find open-source software to digitize a text message into an audio clip, and attached each of these three clips via the Inspector.
Next, in order to add some visual cues into the mix, let's add three TextMesh Pro (TMP) text fields to the UI Canvas:
Add three new TMP game objects to the Canvas and adjust the settings and text message in the Inspector as required to “capture” the state of the core. Adjust the Alpha channel to give your text some transparency as to not completely obscure the game scene action when it pops up.
Select all three of the TMP texts in the Hierarchy and ensure the TextMeshPro — Text (UI) component is disabled by removing the check from the box.
Enabling the check via code will allow for each individual message to be displayed on the game scene screen.
Now that you have set up your various “pieces”, let’s finally dig into the code that ties it all together! 😁
Section 2 — Scripting the Thruster Core Logic!
If you look back at Part 1, you will recall that the ThrusterCoreLogic() method is called in the Update() function. You are basically checking at every frame the state of the Left-Shift key via the CalculateThrustersScale(), and if nothing is detected, then the slider value will cease to be increased. Remember that this slider value is stored in the currentCoreTemp variable.
So, if the currentCoreTemp value is higher than 0, the Player’s core has remained cool (_coreTempCoolDown is True), and the Player can use its thrusters (canPlayerUseThrusters is True), only then will the current core temperature be reduced by the coreTempDecrease value and the UI slider will get updated by calling the SetCoreTemp, setting its value to the currentCoreTemp via the ThrusterCoreTemp script attached to the ThrustersCoreTempHealthBar game object in the Canvas.
Pause…read it again…
This results in the slider value automatically getting reduced when the Left-Shift key is released, allowing the core temperature to come down. As long as the Player avoids exceeding the core temperature limits, he can continue to use his thrusters in bursts, pushing up the temperature when he holds down the Left-Shift key and letting the core cool down every time that key is released.
Hitting that First Warning Threshold
When the Player holds down the Left-Shift key and conditions are met, the PlayerThrustersActivate() is called and the slider value starts increasing. Once the currentCoreTemp becomes greater than 750,… we enable the TMP text _coreTempWarning via the UIManager by flipping its state to True therefore giving the Player the visual warning across the Game Scene. As we do this, we also call the coroutine PlayWarningCoreTempCritical().
In the UIManager, we look for the CoreTempWarning boolean to flip to True in order to enable the TMP text.
Running this coroutine which resides in the PlayerScript plays the audio clip giving the Player an aural warning that the temperature of its core is reaching critical levels. Waiting for 3.0f seconds ensures the warning has a chance to play all the way through without interruption by the logic sensing the currentCoreTemp falling below 750 and back up to beyond 750 which would trigger the coroutine again before the first clip finishes.
But our Player is getting too excited. Blinded by the fierce action unfolding before his eyes, he fails to release the Left-Shift key. Things are getting too hot!
Exceeding the Core Temperature Threshold
If the Players ignores the warnings and lets the currentCoreTemp exceed 999 while still having the two booleans _coreTempCooledDown and canPlayerUseThrusters set to True, then bad things start to happen.
For starters, _coreTempCooledDown and canPlayerUseThrusters will flip over to False, and the PlayWarningCoreTempExceeded() coroutine will be called. As you may have guessed, this will trigger the aural warning, first stopping any audio clips which may be already running (core temp critical warning) to avoid clips from stepping on each other, then playing the audio clip associated with exceeding the core temperature followed by a 5.0f second delay.
We also disable the TMP text _coreTempWarning and enable the _coreShutdownText via the UIManager by flipping their states, this gives the Player the visual warning across the Game Scene that he’s mismanaged his ship and everything is shutting down.
This is where the script will call the PlayerCoreTempExceededDrifting() method…
Drifting Helplessly While the Core Cools Down
Once everything shuts down, the Player is drifting, unable to maneuver his ship or fire his weapons. This state will remain for as long as the core temperature remains over 250 and the bool _coreTempCooledDown remains False. While the ship is drifting, we update the currentCoreTemp value and update the slider value by calling the SetCoreTemp() in the ThrustersCoreTemp script. Everytime we update the currentCoreTemp, we also run the PlayerCoreTempExceededDrifting() method. All this happens once per frame.
In the PlayerCoreTempExceededDrifting() method, we “turn off” the Player's thrusters (left and right) by turning their SetActive to False. We continue to set the bool value of _hasPlayerLaserCooledDown to False to ensure the Player can’t fire his laser weapons. Because I’m a nice guy, I gave the Player a tiny bit of speed (0.25f) so he can vainly try to avoid incoming danger (false hope really!). The final piece is to set his ship rotating along its Z-axis.
Cooldown Achieved — Thrusters, Weapons, and Stabilization Systems Back Online!
We continue to monitor the decline of the core temperature. When it reaches the magic value of 250, and we confirm that we were, in fact, drifting by verifying the boolean values for _coreTempCooledDown and canPlayerUseThrusters were both False, we can begin to restore the ship’s systems.
We then flip these two booleans to True, turn off the visual warning in the UI that the core has shut down, and continue updating the slider value via the SetCoreTemp(). We also “turn on” the Player’s thrusters by turning their SetActive to True, setting his speed back to 5.0f, and finally turning on the UI visual message informing the Player that his thrusters are back online.
The last part is to verify the Player’s position along its Z-axis. We want it to be at 0, which would mean that the Player is pointing straight up. So, if it isn’t, then we run the AnimateRotationTowards() coroutine.
The AnimateRotationTowards() coroutine looks for three inputs when it’s called: the target (“from” Transform of the game object, the Player), rotation to where (“to” Transform, in this case towards (0,0,0)), over how long (duration of 1.0f seconds).
We then use the Quaternion.Slerp declaration embedded inside a while loop to smoothly rotate the Player from its current position back to (0,0,0) on its rotation axis over the set time (1.0f seconds).
It’s also in this coroutine that we play the Audio Clip advising the Player that his core temperature is “nominal” and his systems are coming back online.
I’ll be honest with you, it took me a while to find some open-source code to help me figure this out because anything that deals with Quaternions still feels like Black Magic at times. It’s worth having a quick look at the Unity Scripting API on Quaternion.Slerp here.
We finished off this coroutine by enabling the Player’s weapon systems by flipping the _hasPlayerLaserCooledDown back to True, and then turning off the UI warning text that informs the Player that his core temperature is now back to normal.
The final product looks like this:
What Happens if the Player Loses a Life?
When the Player loses a life, we don’t want him to respawn into the game in a depleted state, with systems disabled and alarms blaring. That just simply wouldn’t be fair.
In my PlayerScript script, inside its Damage() method, I check to see that the Player has lives remaining (_lives != 0). If True, two different methods and a coroutine are called to reset the state of the Player to how he was at the start of the game. Related to this article is the ResetStateOfCore() method.
As you can see, we do a few things:
we stop all audio clips;
we reset the Player’s rotation to (0,0,0);
we turn off all visual warnings in the UI;
we reset the currentCoreTemp value to 0;
we reset the slider in the UI to its minimum value;
we reset the boolean _coreTempCooledDown to True; and
we make sure the thruster game objects are turned back on.
With all these parameters reset, the Player can happily continue fighting off another wave of angry alien invaders!
To help with clarity, I’ve included the entire void ThrusterCoreLogic() method below:
This concludes Part 2 of my articles on how I implemented a “health bar” slider in my UI to represent the status of the “core” temperature as the player engages its thrusters.
Along the way, we went down a couple of rabbit burrows and tossed in visual and aural warnings to cue the Player, and we found a way to penalize the Player by disabling temporarily its propulsion and weapons systems.
I hope that you have found this article helpful and that it will assist you as you implement various features into your own Unity game project. Thanks for reading :)