How I created a “Tractor Beam” scaling bar HUD for my Unity game project.
Objective: create a scaling “health bar” in your Unity game project UI to visualize the “drain” on your tractor beam, or letting the system “replenish”.
In my game project, I envisioned the following:
I wanted a scaling bar in my HUD that dropped for as long as the tractor beam was activated (T-key held down by the player).
The slider color is a non-gradient blue.
If the Player deactivates his tractor beam (releases the T-key), the scaling bar climbs back up to indicate a full charge (replenished).
If the tractor beam runs out of juice, it simply deactivates.
Step 1 — Setting up the scaling bar elements
For this, I needed to first find (or design) a couple of sprite images. The first sprite represents the border of my “health bar”, while the second sprite is an image that tries to convey to the Player what the scaling bar means. For the border, I found a rectangle with a transparent center and rounded ends, and I then used the sprite of my tractor beam as a “label” for the scaling bar.
Edit: the “border” image is optional. Setting it up with the “fill” in the background gives your game a bit more polish. You can opt to simply use a fill bar with your “thruster label”.
For the border, Right-Click on your Canvas and select UI /Image. Select F in the Scene view to find the newly created Image and view the entire Canvas, and center the Image on the Canvas. This Image will become the border of your scaling bar, so rename it to “Border”, drag into it the source image border sprite, and select Set Native Size.
Right-Click on your Canvas and select Create Empty. Using the Rect Tool, resize the empty object so it fits inside the Border sprite, and rename it to “TractorBeamHealthBar”. You then drag your Border (child) into this empty object (parent).
Right-Click on TractorBeamHealthBar, and select UI / Image. Rename the Image to “Fill”, resize it so it’s slightly smaller than the Border sprite, and change its order to the top in the children so it shows up behind the Border. The last element is to add a final Image, rename it “BeamImage” and change its Source Image to the TractorBeamImage sprite image. Adjust the Scale as required to fit your needs. Your Hierarchy should look like this:
Select TractorBeamHealthBar, and Add Component / Slider. Drag the Fill image into the Fill Rect field, and configure the rest of the Slider parameters in the Inspector as shown below:
To ensure the Fill bar scales with the TractorBeamHealthBar, select the Border and set its Rect Transform Anchor Presets as shown below:
Scale and fine-tune as required for the visual positioning that you want. In my case, I opted to set everything up in the top left corner of my UI, just below my “thruster health bar”.
At this point, we’re pretty much ready to code some behavior to the “health bar” so it reflects when the Player uses the tractor beam. Let’s work on a script to control the level of the bar.
Step 2 — Attach a script to control the slider
Create a new script, call it “TractorBeam” and attach it to the TractorBeamHealthBar in the UI. Set up two public variables, one to hold the Slider game object (TractorBeamHealthBar), and the other to hold the slider fill image game object (Fill).
We then need to create two public methods to set the maximum value of the slider as well as the current value of the slider. The goal is to call these methods from the Player script to set the max value (SetMaxTractorBeam), and to change the current value based on the duration that we use our tractor beam. The longer we continuously use the tractor beam, the lower the value (SetTractorBeam), and the shorter the slider becomes. By manipulating the values of the TractorBeam script, we allow these changes to be represented in the UI.
The effect, once connected to the T-key and called by the user, should look like this:
Step 3 — Connecting the T-key
Let’s now take the time to set up the required variables to achieve the desired behaviors. For now, we’re just going to concentrate on the ones required to move the UI scale when the tractor beam is turned on/off by the player.
_tractorBeam stores the tractor beam game object (animated sprite), with SetActive false by default. Bools _canPlayerUseTractorBeam and _isTractorBeamOn are used to determine the logic for when the player can use the tractor beam during the game. tractorBeam stores a reference to the TractorBeam script. minTractorBeam and maxTractorBeam are used to cap the max and min limit (length) of the tractor beam health bar. _scaleChangeRate and _scaleChange are used to change the speed and scale of the tractor beam game object between two hard-coded limits.
We use the Start() method to preset the _scaleChangeRate to -0.25f and set the _scaleChange Vector3 values. We then set the currentTractorBeam to 1000, to adjust the position of the slider bar by passing that value to the TractorBeam() script, and to initially turn off the player’s ability to use the tractor beam (in my version of the Space Shooter project, this allows for a “countdown” message to be displayed while the Player game object remains at its default starting position in the game scene).
In Update(), we call ActivateTractorBeam() to detect inputs from the T-key by the player, and ReplenishTractorBeam(int tractorBeamDecrease) to recharge the tractor beam to its full capacity.
ActivateTractorBeam() waits for the player to hold down the T-key. Once this is detected, two conditions must be met before turning “on” the tractor beam. The player must be in a game state which permits them to use the tractor beam (i.e.: after the initial countdown or when the player is reset after dying), and the currentTractorBeam value must be higher than the minTractorBeam value (the health bar must be above the min value). If these two conditions are met, we let the TractorBeamCollectPwrUps script (attached to the “friendly” power-up elements) know that the tractor beam is activated, we set the SetActive to true so we can see the tractor beam, flip the _isTractorBeamOn to true, and call the PlayerTractorBeamActivate(int tractorBeamDecrease). Releasing the T-key hides the tractor beam game object and flips the required variables back to false.
Int tractorBeamDecrease sets the rate over time that the slider decreases in value (from 1000 to 0). So every time PlayerTractorBeamActivate() is called, currentTractorBeam is decreased by the value of tractorBeamDecrease, which then calls the SetTractorBeam method in the tractorBeam (referenced to the TractorBeam script attached to the TractorBeamHealthBar UI element).
This is where we check to see if the currentTractorBeam has exceeded the minTractorBeam value (declared earlier at 0), and if it has, we cap the value at 0 (by setting it to the value of the minTractorBeam).
If currentTractorBeam equals minTractorBeam, we again “shut down” the tractor beam and stop the power-ups from drifting towards the player.
If _isTractorBeamOn is true, we check to see that the _scaleChangeRate is not set to 0, and if it is, we bump it up to 0.1f. This prevents the game object’s local scale from freezing up. We then change the tractor beam game object’s scale between 4.0f and 40.0f, flipping the _scaleChange value every time one of these limits is reached. Unity documentation explores this further at the following link.
By default, when the T-key is released, the tractor beam health bar is “replenished” at a rate set of 2 (called in the Update() method).
The entire effect can be seen below. When the T-key is held down, the tractor beam (blue sphere) turns on, and its scale varies between set values. Power-ups are then pulled toward the player. Once the tractor beam is depleted, it turns off, and once the T-key is released, its health bar is replenished automatically.
Step 4— Attraction matters ~ Adding the required Script to your Power-Ups
This last part explores how we get the power-up game objects to drift toward the player when the tractor beam is activated.
The script above is attached to the power-up game objects that you want your player to have the capability to collect. Declare private game object _player, and cache into it a reference to the player by looking for its tag (there should be only one player!). You also need to declare a bool, false by default, as a condition to call the MoveTowardsPlayer() method.
As the power-up collectible game objects drift down, they look for two conditions: is the Player alive (!= null), and is the tractor beam turned on (true)? Once these conditions are both met, MoveTowardsPlayer() is called.
MoveTowardsPlayer() updates the transform position of the power-up to Lerp from its own position toward the player position at a set rate (2.5f). This results in the power-up smoothly moving to the player until a collision is detected (power-up collected).
And we’re done!
I sure hope you’ve enjoyed this article and have found it useful as you implement your own “Space Shooter” genre game project. Thanks for reading :)