Making a Unit Frame

While ROBLOX provides a healthbar by default, you can implement one of your own if it fits the visual style of your game better. In this tutorial we will cover how to use the Scale property of UDim2's to make a unit frame that shows the player's name, avatar, and health.

Adding the Frame[edit]

Let's start with the container for the unit frame. In your ScreenGui, insert a new Frame and name it UnitFrame. To push it a little bit away from the edge of the screen, set the position to {0, 10,},{0, 10}. Set the size to {0.3, 0},{0.15, 0}. We now have a box in the upper left where our unit frame will go :

UnitFrame Frame.png

It is tempting to set the size in raw pixels, just like we did for the margin from the edge of the screen. But we have to consider the players of our game and the devices they are using. Consider the following example:

Here is the Unit Frame we will make in this tutorial as it would be seen on an average laptop. The unit frame's size was set via offset to be 410px x 115px:

UnitFrameScale1366x768.png

Looks to be a pretty good size until you see how it would look on an iPhone6:

UnitFrameOffsetiPhone6.png

Now the unit frame is taking up most of the screen! Not to mention that the player's thumbs will be covering up the lower corners, leaving very little room to actually see anything. If instead the unit frame's size was set via scale to .3 x .15 (30% of the screen wide and 15% tall), the unit frame looks exactly the same on the laptop, and looks much better on the iPhone:

UnitFrameScaleiPhone6.png

Adding the LocalScript[edit]

Before we go further let's add a LocalScript so we can add functionality to our frame as we go. Insert a LocalScript into UnitFrame. In this script let's declare variables for the player and for the frame itself, both of which we will use later.

local player = game.Players.LocalPlayer
local unitFrame = script.Parent

Player Avatar[edit]

Now let's insert an ImageLabel into the UnitFrame and name it Avatar. This label will be used for the avatar of the player. Again, because we want our unit frame to scale nicely, we'll use just the Scale component of the Size. Set the Size of the ImageLabel to {0.25, 0},{0.9, 0}. Here it is important to know that the Scale property sets the dimension based on the size of the parent element. Until now, the parent of all the 2D elements we have been adding has been a ScreenGui, so setting the scale would scale these elements relative to the screen. In this case however, we set the width of the ImageLabel to .25, which means that it will be 25% the width of the Frame we inserted it into.

To move the ImageLabel to the right of the frame, set it's position to {0.75, 0}, {0,0}. We know the ImageLabel will be 25% the width of the Frame, so setting the position to 75% will move it all the way over to the right of the frame.

UnitFrame ImageLabel.png

What image should we use for the ImageLabel? It would be nice to use the actual avatar of any player who joins our game. Since we can't know the player ahead of time, let's add code to our script to fetch the avatar thumbnail of the player and put it in the ImageLabel.

local player = game.Players.LocalPlayer
local unitFrame = script.Parent
 
unitFrame:WaitForChild("Avatar").Image = "http://www.roblox.com/Thumbs/Avatar.ashx?x=100&y=100&username=" .. player.Name
Notice how we used WaitForChild to access Avatar. When a ROBLOX game starts up, all of the contents of StarterGui are copied into the player's PlayerGui. This copy does not happen instantaneously nor all at once. It is entirely possible for this LocalScript to copy over and start executing before the other GuiElements have copied. The solution for this is WaitForChild. This function pauses until the child object actually exists. Keep in mind you don't have to use this function every time you access a GUI element, but it is useful for code that executes when a script first runs.

Player Name[edit]

To display the player's name, insert a TextLabel into the UnitFrame. Name this label PlayerName. It's fine to leave this label on the left of the frame, so the Position can remain at {0, 0},{0, 0}. We do want to stretch the label so it fills the rest of the space in the frame, so set the Size to {0.75, 0},{0.9, 0}. Also, set the TextScaled property of the label to true so that the text also stretches.

UnitFrame NameLabel.png

In our LocalScript let's add a line of code to fill our TextLabel with the name of the player.

local player = game.Players.LocalPlayer
local unitFrame = script.Parent
 
unitFrame:WaitForChild("Avatar").Image = "http://www.roblox.com/Thumbs/Avatar.ashx?x=100&y=100&username=" .. player.Name
unitFrame:WaitForChild("PlayerName").Text = player.Name

Player Health[edit]

The last thing we need are elements for the health bar and code to make it change. Insert a new Frame into UnitFrame and name it HealthBarContainer. Set the Position to {0, 0},{0.9, 0} and the Size to {1, 0},{0.1, 0}. To make sure that it draws over the border of the TextLabel, set the ZIndex of HealthBarContainer to 2.

Insert another new Frame into the HealthBarContainer and name it HealthBar. Change the size to {1, 0},{1, 0} so that it completely fills up the HealthBarContainer (notice how setting Scale to 1 represents 100% the size of the parent element). Make sure the ZIndex for the Healthbar is also 2. To change the color of the HealthBar, click on the BackgroundColor3 and select one of the colors from the chooser.

UnitFrame HealthBar.png

Now we have to add code to change the width of the healthbar whenever the player's health changes. In our script, add a variable for the HealthBar. Then, we will bind a function to the CharacterAdded event of the player. This event fires whenever the player spawns a character and it passes the character model into the bound function. We can then get the Humanoid of that character.

local player = game.Players.LocalPlayer
local unitFrame = script.Parent
 
unitFrame:WaitForChild("Avatar").Image = "http://www.roblox.com/Thumbs/Avatar.ashx?x=100&y=100&username=" .. player.Name
unitFrame:WaitForChild("PlayerName").Text = player.Name
 
local healthBar = unitFrame.HealthBarContainer.HealthBar player.CharacterAdded:connect(function(character)	local humanoid = character:WaitForChild('Humanoid')end)

Now we can bind a function to the HealthChanged event of the Humanoid. In this function, we can get what percentage of health the character is at by dividing the current health by the maximum health. We can then use this percentage for the size of the health bar as the Scale component works off of a percentage.

local player = game.Players.LocalPlayer
local unitFrame = script.Parent
 
unitFrame:WaitForChild("Avatar").Image = "http://www.roblox.com/Thumbs/Avatar.ashx?x=100&y=100&username=" .. player.Name
unitFrame:WaitForChild("PlayerName").Text = player.Name
 
local healthBar = unitFrame.HealthBarContainer.HealthBar
 
player.CharacterAdded:connect(function(character)
	local humanoid = character:WaitForChild('Humanoid')
	humanoid.HealthChanged:connect(function(health)		local healthPercentage = health / character.Humanoid.MaxHealth		healthBar.Size = UDim2.new(healthPercentage, 0, 1, 0)	end)end)

Lastly, we can also disable the default health bar in the Core Gui as we no longer need it:

local player = game.Players.LocalPlayer
local unitFrame = script.Parent
 
unitFrame:WaitForChild("Avatar").Image = "http://www.roblox.com/Thumbs/Avatar.ashx?x=100&y=100&username=" .. player.Name
unitFrame:WaitForChild("PlayerName").Text = player.Name
 
local healthBar = unitFrame.HealthBarContainer.HealthBar
 
player.CharacterAdded:connect(function(character)
	local humanoid = character:WaitForChild('Humanoid')
	humanoid.HealthChanged:connect(function(health)
		local healthPercentage = health / character.Humanoid.MaxHealth
		healthBar.Size = UDim2.new(healthPercentage, 0, 1, 0)
	end)
end)
 
game.StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Health, false)

Now we have a functional unit frame that can be further customized to fit the style of our game!