HUD cooldown bars are visual elements in game that don't necessarily belong to the game's world, but are an indication for the player of a period of time during which she can or cannot perform an action.
In role-playing games, multiplayer online battle arenas (like League of Legends or DOTA), or even real-time strategy games, these indicators are often critical to the player.
In this tutorial, we will look at how to implement those cooldown bars, whatever your coding language or tool is, relying on pseudo-code and breaking down the mechanics used. The tutorial does not claim to show the best or the only way to implement cooldown bars, but simply analyses and displays a working, practical way to do so.
Let's dive in.
The Basic Cooldown Mechanic
A cooldown bar is mostly a visual feedback for the cooldown mechanic itself, and the cooldown mechanic is basically a timer. Consider an action that a character performs. The moment the action is performed, a timer starts, and while this timer counts down, the character cannot perform the action again. That is the cooldown.
From a code perspective, to prevent the action being performed during the cooldown period, a Boolean variable is set to
true when the action is performed. When trying to perform your action, the code checks that the value of the Boolean variable is
false, and does not allow the action to be performed otherwise. At the end of the timer, the Boolean variable is set back to
false, allowing the action to be performed again.
Consider the following example as an illustration of this concept:
Once you click the Action button, the character performs an action, and the Action button is disabled. During the cooldown, at regular intervals the time remaining in the cooldown is displayed. At the end of the cooldown, the character is ready to perform the action again, so the Action button is re-enabled.
Let's have a look at the pseudo-code:
//An object Character has a boolean variable "Cooldown", a numeric variable "cTimer" and another numeric variable "cEndTime" On clicked Button txtHistory.text = txtHistory.text & newline & "The character performs an action" Character.cTimer = 0 Character.cEndTime = txtTimer.text //The text object "Cooldown duration" Character.Cooldown = True Button.Enabled = False If Character.Cooldown = True Character.cTimer = Character.cTimer + dt If Character.cTimer >= Character.cEndTime txtHistory.text = txtHistory.text & newline & "The character is ready to perform an action" Character.cTimer = -1 Character.Cooldown = False Button.Enabled = True Else & Every 0.5 seconds txtHistory.text = txtHistory.text & newline & "The action is on cooldown. " & Character.cEndTime - Character.cTimer & " seconds of cooldown remaining."
On clicked Button function can only be executed if the button is enabled, and its code is only executed once after the click. That is the user action that starts the timer and sets
Cooldown to be
When the button is clicked, the
Character.cEndTime variable is the time when the cooldown period will finish; this value is set based on the value in the
txtTimer text object, seen next to the Action button.
Also at this point, the
cTimer value is "reset" to
0 since it is a "new" timer, and
Cooldown is set to
true to allow the second part of the code to kick in. Finally, we disable the button. (We could simply leave it enabled and add another condition to our
On clicked Button function checking whether the value of
false before continuing, but disabling the button feels like better feedback.)
Note: In the example, and this pseudo-code, there is no error catching to prevent you from entering something other than a number in that text object. Entering anything else will effectively set
cEndTime to be
0—so, basically, no cooldown at all.
Line 10 of the above pseudo-code is executed every tick; it checks whether the value of
true and, if so, adds the value of
dt to the current value of
dt, short for "delta time", is a system variable that returns the time that has elapsed between the rendering of the previous frame and the rendering of the current frame. This means that, however powerful the player's computer is, and whatever framerate the game runs at, we can ensure that the cooldown period lasts the same amount of time. (If we defined the cooldown period in terms of a number of ticks or frames that elapsed, the length of the period in seconds would vary on different machines.) The name of this
dt variable or its usage may differ according to your coding engine.
If the cooldown is still active, we check whether the current value of
cTimer is greater than or equal to
cEndTime; if so, we must have reached the end of the cooldown period. We display a bit of feedback, and set
false so that this section of code won't execute again until the user clicks on the Action button. We also re-enable the Action button.
If the cooldown is still active, we display feedback explaining this instead. This specific bit of feedback is actually our "cooldown bar" for this text-based example.
So that's a basic cooldown mechanic based on a basic timer. For the rest of this article, let's focus on the cooldown bars themselves, and see how to implement them.
A Basic Cooldown Bar
A cooldown bar is really just a sprite that changes size or visibility over time, during a cooldown period. It is a feedback mechanic for the player to let her know when she'll be able to perform the action again.
Consider the following example :
Click anywhere on the screen to perform the action. Note that the green bar turns red during the cooldown, and grows from a width of
0 back to its original width. As in the basic textual example, you can set the cooldown duration.
In this example, the bar (named
CooldownBar) is nothing more than a colored sprite that is stretched to a width of 100 pixels. When the action is performed, its width is set to 0 pixels. Then, every tick that the
Cooldown variable is
true, the width is set based on the current value of
Let's have a look at the pseudo-code:
//Using the same "Character" object as in the basic example, this time the object is visible on screen On any mouse click & Character.Cooldown = False Character.cTimer = 0 Character.cEndTime = txtEndTimer.text Character.Cooldown = True CooldownBar.Width = 0 CooldownBar.AnimationFrame = 1 If Character.Cooldown = True Character.cTimer = Character.cTimer + dt CooldownBar.Width = (CooldownBar.MaxWidth / Character.cEndTime) * Character.cTimer If Character.cTimer >= Character.cEndTime Character.cTimer = -1 Character.Cooldown = False CooldownBar.Width = CooldownBar.MaxWidth CooldownBar.AnimationFrame = 0
The cooldown mechanic itself is pretty similar to the one described in the previous example, so let's focus on the
CooldownBar itself. The object has two animation frames: a green 32x32px square and a red 32x32px square. It also has a
MaxWidth numeric instance variable which is set to
100 (pixels), the actual maximum width of the bar.
Each tick, if
CooldownBar.width is set to a fraction of
CooldownBar.MaxWidth. We determine this fraction by dividing the maximum width of the bar by the cooldown ending time, and then multiplying this result by the current
At the start and end of the cooldown period, we also make sure to change the animation frame accordingly: to red, when the cooldown starts, and then back to green once the cooldown is done.
Improving the Design
We could go a bit further on the visual aspect. Here are some thoughts:
The origin point of
CooldownBar is set at its centre, which
gives it the feeling of overall growth. If you prefer, you could set this origin point at the left or the right edge of the object, to give it a more "linear"
This example is very basic; the bar itself is only composed of two frames of different color to reinforce the cooldown aspect. As long as the bar is red, the user understands the action cannot be performed, as red is generally a colour used to mean "stop". But don't forget your colour-blind players! Make sure to use colours that are really different so that even they can tell the difference, or use another method of visual feedback besides the colour change.
You could also add an outline to the bar, a fixed rectangle that would allow the user to better estimate the time remaining in the cooldown period.
Here is a quick illustration of the previous points :
It is still a very basic refilling bar, and there's even more you could add to the visuals. The bar could consist of an animation instead of just two colored frames. The sprite under the bar could be stylized in such a way that its background appears transparent, or you could even add another sprite over it to give a "glass" impression. There are many ways to stylize the cooldown bar to fit your game's design the best.
Skill Buttons Cooldown
In some games, the player has skill buttons at their disposal. These buttons don't just display the cooldown or availability of the skill; they are also an interface for the user to perform the indicated skill (often in addition to some keyboard shortcuts).
Consider this example, in which clicking on one of the buttons will throw the appropriate weapon and also display the cooldown remaining:
As you can see, each skill button will display an "unfilling" black bar and a timer during its cooldown period. The black bar is just a black colored sprite placed over the skill button with an opacity of 45%, and the timer is a text object. Each instance of the skill button has its own instance of these
This time, the
sEndTime variables are "attached" to each
SkillButton instance. Also, the origin point for the
SkillCover black sprite is at its bottom edge.
Consider this pseudo-code:
//Object "SkillButton" with variables "Cooldown" (boolean), "sTime" (numeric), "sEndTime" (numeric), and a specific animation frame to know which instance is being clicked/selected. //Object "SkillCover" with a variable "Skill" set accordingly to the animation frame of the SkillButton they are related to. //Object "txtSkillTimer" with a variable "Skill" for the same purpose as above. On SkillButton clicked & SkillButton.Cooldown = False SkillButton.sTime = 0 SkillButton.Cooldown = True Create Proj & ProjImage objects ProjImage.AnimationFrame = SkillButton.AnimationFrame //To either throw a dagger or a ninja star txtSkillTimer.Skill = SkillButton.AnimationFrame & SkillCover.Skill = SkillButton.AnimationFrame Set txtSkillTimer's position to the bottom of SkillButton Set SkillCover's position to the bottom of SkillButton Set txtSkillTimer in Front of SkillButton Set SkillCover behind txtSkillTimer //Still in front of SkillButton txtSkillTimer.Visible = True SkillCover.Visible = True SkillCover.Height = SkillButton.Height For each SkillButton & SkillButton.Cooldown = True SkillButton.sTime = SkillButton.sTime + dt txtSkillTimer.Skill = SkillButton.AnimationFrame & SkillCover.Skill = SkillButton.AnimationFrame txtSkillTimer.text = SkillButton.sEndTime - SkillButton.sTime SkillCover.height = SkillButton.Height - ((SkillButton.Height / SkillButton.sEndTime) * SkillButton.sTime) If SkillButton.sTime >= SkillButton.sEndTime SkillButton.sTime = -1 SkillButton.Cooldown = False txtSkillTimer.Skill = SkillButton.AnimationFrame & SkillCover.Skill = SkillButton.AnimationFrame txtSkillTimer.Visible = False SkillCover.Visible = False
Here, we select the correct instance of
SkillCover . (This is a Construct 2 technique; we determine the correct instances according to the value of
Skill, which should correspond to the animation frame of the current
SkillButton that was either clicked or selected in the
For each loop.)
Unlike with our previous cooldown bars,
SkillCover starts out "full", covering the whole height of the
SkillButton, and then, during the cooldown, slowly decreases, revealing the image of the button.
To do this, we we give
SkillCover a height that matches that of
SkillButton to begin with, and then, each frame, subtract
(SkillButton.Height / SkillButton.sEndTime) * SkillButton.sTime from this full height. It's basically the same formula we used before to calculate the fraction of the cooldown period that has elapsed, but in reverse.
Some games will format the time differently and allow the player to configure the display she prefers. For example, one minute and forty seconds could be displayed as 1:40 or as 100s. To apply this in your own game, run an
If check, before displaying the text of
txtSkillTimer, to see what format the player has selected, and format the text accordingly. Some games or players even prefer not to display the time as text at all.
There's more you could do with the
SkillCover. You could play with its opacity to obscure the button more or less than 45%. Since it's a sprite that covers another image, you could also play with its blend mode—for example, to desaturate the underlying image and actually reveal its colors more and more as the cooldown passes. You could even consider adding webGL or shader effects to it to fit the rest of your UI or design. As for the cooldown bar, it's up to your imagination and artistic direction.
We've seen that a cooldown bar is a visual feedback for a simple mechanic that prevents an action from being performed for a certain amount of time.
You can use simple sprites and stretch their width or height over time to signal your user that a cooldown is going on. You can display the remaining time in plain text, formatting it either in minutes or in seconds. You can even apply any kind of animation, blend mode or shader effect that will suit the artistic direction of your game.
If you think about it for a second, you can also use this method to control the rate of fire for a weapon: as long as the gun is on cooldown, it won't shoot another projectile, even if the Fire key is down; at the moment the cooldown is complete, another projectile may be fired. No cooldown bar is required in this case.
I hope you found this article interesting, and I'm looking forward to seeing your own designs of cooldown bars.
- Battle Backgrounds from Trent Gamblin - http://opengameart.org/content/12-battle-backgrounds-240x110
- Character sprites by Antifareas - http://opengameart.org/content/antifareas-rpg-sprite-set-1-enlarged-w-transparent-background-fixed
- Pixel Art Icons for RPGs from 7SoulDesign - http://7soul1.deviantart.com/art/420-Pixel-Art-Icons-for-RPG-129892453
- Health or mana UI bars by Mumu - http://opengameart.org/content/health-or-mana-ui-bars
- Enemy Health bars by Paul Wortmann - http://opengameart.org/content/enemy-health-bars
- [LPC]LifeBars! by Nushio - http://opengameart.org/content/lpc-lifebars