Recreating the destiny 2 health bar and recovery system using materials, UMG and GAS.
In this article I will show and explain how the healthbar system from Destiny 2 was recreated in Unreal Engine to give the following result.
The visual effects are all carried out in a single material within the user widget, while the health recovery is managed using gameplay abilities.
In Destiny 2, the healthbar UI is hidden until a player takes damage. Once damage occurs, the healthbar immediatly appears and displays the damage dealt, staying up in the HUD until a players health is fully recovered. The actual healthbar is split into two main sections, the player’s Shield
and the player’s Health
.
The Shield
makes up the first 70% of a players health bar. When the Shield
is damaged but not fully depleted, the bar’s colour remains white. However when the Shield
is broken (apart from audio, visual effects and other potential gameplay related effects triggering), the healthbar becomes red and flashing (When a player’s Health
is full but the Shield
is depleted, the flashing effect stops but the color remains red). After a few seconds of not taking damage the player will start regenerating their Health
and a few seconds after that the Shield
will start regenerating. Any further damage taken will stop the regeneration and start the timer again. The rate of regeneration and the waiting time since the last damage was taken all depend on the player’s Recovery
stat. The Recovery
stat goes from 0 to 100, increasing its efficacy every 10 levels. For example a player with 0 recovery will back to full healthbar in 9 seconds after being damaged while a player with 100 recovery will achieve the same in 6 seconds.
The first step was to create a material that would manage the health bar depleting and regenerating based on two float values, HealthPercent
and ShieldPercent
which should be between 0 and 1. To emulate the behaviour explained above the following constraints had to be followed:
Health
must occupy the first 30% of the material and the Shield
the last 70%ShieldPercent
> 0, then the material colour must be white.ShieldPercent
= 0 and HealthPercent
= 1, then the material colour must be redHealthPercent
< 1, then the material colour must be red with a flashing effect for the Health
section and a darker semi-transparent flashing red should also occupy the rest of the material.Since the material is to be used in the UI, first the Material Domain
was set to User Interface
in the details tab of the material. Then the material was created as follows:
Next, to create the small border that goes around the main health bar, a material using the SDF box function from the UI Material Lab project from Epic Games.
A User Widget blueprint was created as seen below. Each component was placed inside a grid panel with the main two being images for the border and health bar. Then an extra horizontal box with images was placed to match the decoration ornaments around the Destiny 2 health bar.
For the health bar widget image, a dynamic material instance is created on the widgets pre-construct event, and then it is immediatly asigned to it. A widget animation was created for the health bar fadeout and then the functionality was created using four similar functions seen in the image below. The FadeOutHealthBar
function gets called from C++ when a delegate that monitors the status of the health and shield attributes of the player is fired when they are full and plays the fade out widget animation. The functions which set the value of the ShieldPercent
and HealthPercent
parameters in the dynamic material get called from C++ when an OnGameplayAttributeValueChanged()
delegate for the respective attributes is fired. These functions also call the ShowHealthBar
function which instantly shows the health bar on the players HUD (doing the opposite of the FadeOutHealthBar function but faster)
The health recovery system as well as most of the gameplay logic of this project uses Unreal’s Gameplay Ability System. (A very good starting resource can be found in Tranek’s GAS documentation).
First, the recovery system becomes functional thanks to the GA_RecentlyDamaged
and GA_OnShieldBroken
Gameplay Abilities GA
(These are triggered from events that are handled by the Damage Pipeline). Their main functionality is to apply a Gameplay Effect GE
that applies the State.Combat.RecentlyDamaged
and State.Combat.ShieldBroken
gameplay tags to the player damaged respectively.
The State.Combat.ShieldBroken
is applied by an infinite GE
that will later be removed within the GA_Recovery
gameplay ability.
The State.Combat.RecentlyDamaged
is applied by a duration GE
, which determines its duration using the player’s Recovery
attribute and a curve table as follows:
Once the State.Combat.RecentlyDamaged
is applied to a player, the GA_Recovery
ability is automatically activated and handles the rest of the recovery system.
The GA_Recovery
ability is set up to activate when the State.Combat.RecentlyDamaged
is added to the player’s Ability System Component (ASC
). Once the ability is activated it starts up an ability task which will wait for the tag to be removed (which will happen a few seconds after the player stops taking damage depending on the Recovery
attribute).
If at any point the player receives damage and the tag is newly added, the ability will cancel, cancelling the main timer handle and will start from the beggining (wait for the tag to be removed …etc).
The main recovery tick event gets executed once every 16ms from the Set Timer by Event
node set to looping. On every execution, the health recovery instant GE
is applied to the player, which increments the player’s Health
attribute by a small amount depending on Recovery
attribute. This small amount is obtained from the curve table shown previously. On the first execution of the RecoveryTick
event, if the State.Combat.ShieldBroken
tag is present, a timer (whose duration again is extracted from the recovery curve table) will be started after which the GE
that added that tag will be removed from the player and thus removing that tag. After that tag is removed, every further execution of the event will also apply an instant GE
which increments the player’s Shield
attribute.
At the end of each execution, the current value of the Health
and Shield
attributes are compared to the MaxHealth
and MaxShield
attributes to determine if the health bar is completely full, at which point the gameplay ability will end.
While the main functionality of the health bar is finished, a few improvements to the damage taking system will still be made. Currently, a Gameplay Cue GC
is executed every time a player takes damage to perform a small screen shake, however this feedback will be eventually improved to add the following: