Subaro
Terrarian
Welcome,
in this tutorial, we want to create a custom health bar and custom mana bar. I will start with an empty project.
Project ID: CustomBars
Project Name: Custom Resource Bars
1. Remove old health bar
2. Create empty interface and register it
At first, we declare our new interface in the Mod class:
Now we need to create the interface on the Load() method:
Back to our ModifyInterfaceLayers(...) methode we need to register our interface that we created. We do that directly behind layers.RemoveAt(i):
3. Create and register our UIState
Now we are ready to create our UIState. The UIState will be assigned to our interface. That will activate and recalculate the UI(and all the children) at the start.
So create a new folder called UI. Create a class that inheritance UIState and name it HealthManaBars. That class will provide only the health and mana bars. We removed the Resource Bars interface in step 1. The Resource Bars exist of the health bar, mana bar, and the buff bar. So if you finish the Tutorial you got your custom health/mana bars but no buff bar. Later I will add a custom buff bar to the Tutorial.
Now create the class HealthManaBars and implement the OnInitialize() method:
Now we want to create a visible variable to easily control the current visibility of the UI:
We will add an empty default Terraria panel and position it at the top right of the game. We will go over the other UI elements later. Add to the OnInitialize():
Back to the Mod class create a HealthManaBars instance and register the UIState to the UserInterface:
To See anything we need to update our UI. To do so go to the ModifyInterfaceLayers() and insert into the MethodSequenceListItem delegate:
You can now run build your mod and you will see the first result:
4. Create our own UIElement
Terraria has already the most UIElements you need to build your UI. The best is all of them are in terraria style. You can find all elements in your Terraria Reference under Terraria.GameContent.UI.Elements:
We used the UIPanel earlier, but now we want to create our own UIElement. A flat panel without any borders.
So create a new class called UIFlatPanel that inheritance from UIElement. We need a color for the background and a texture. The texture is needed because everything will be drawn using a spriteBatch which require a texture.
Here the texture I use:
Download and put into your project (mine is at {ModID}\Textures\UI). Now we will create our UIElement class:
Now we need to tell the UIElement how it should be drawn. We override the methode DrawSelf(..):
We get the Dimension which is holding the information of the size and position of the element. We create the top left point called point1. Now we draw the _backgroundTexture as a Rectangle with the given size and color.
Now we got our own UIElement and are ready to test it out. Go to your HealthManaBars class and change the UIPanel to our new UIFlatPanel. Also, add another red one and blue one:
It should look like this:
5. Implement the Life/Mana Bar
So now we want to show the user the amount of life and mana as text. Also, implement its progress animation. To do so we create a new UIElement that contains two flat panels. One is the background and the other one is the current life/mana. I named the class ResourceBar. I also created an inner enum to set the current stat to display:
Now create the OnInitialize() and add a gray FlatPanel as background and a colored as the current value and a UIText element. Determine the color of the current panel depending on the ResourceBarMode:
Next we will implement the progress of the bar by overriding the draw method and determine how many percent of the current bar should be displayed:
Now we need to override the Update(..) method to update the text:
The ResourceBars are ready now so go back to the HealthManaBars class and change the hp and mana UIFlatPanels to ResourceBars. Also, remove the old white panel:
To be able to stay in the top right coner i override the DrawSelf method of HealthManaBars:
Now it should stay at the top right even after resize.
Now we are ready and got two new bars. In the end, it should look like this:
Thank you for your patience and after you implemented the health bar you will see it´s very easy to create or replace a UI. In some days we will create a custom buff bar.
CreditsMyself
the tModLoader Team & Co- creating tModloader, ExampleMod
Re-Logic - Creating that amazing game
in this tutorial, we want to create a custom health bar and custom mana bar. I will start with an empty project.
Project ID: CustomBars
Project Name: Custom Resource Bars
Code:
public override void ModifyInterfaceLayers(List<MethodSequenceListItem> layers)
{
for (int i = 0; i < layers.Count; i++)
{
//Remove Resource bars
if (layers[i].Name.Contains("Resource Bars"))
{
layers.RemoveAt(i);
}
}
}
At first, we declare our new interface in the Mod class:
Code:
public UserInterface customResources;
Now we need to create the interface on the Load() method:
Code:
public override void Load()
{
if (!Main.dedServ)
{
customRessources = new UserInterface();
}
}
Code:
//Add you own layer
layers.Insert(i, new MethodSequenceListItem(
"CustomBars: Custom Resource Bar",
delegate
{
//At this point, your UI that we will create later will be updated. Leave it blank at the moment
return true;
},
null)
Now we are ready to create our UIState. The UIState will be assigned to our interface. That will activate and recalculate the UI(and all the children) at the start.
So create a new folder called UI. Create a class that inheritance UIState and name it HealthManaBars. That class will provide only the health and mana bars. We removed the Resource Bars interface in step 1. The Resource Bars exist of the health bar, mana bar, and the buff bar. So if you finish the Tutorial you got your custom health/mana bars but no buff bar. Later I will add a custom buff bar to the Tutorial.
Now create the class HealthManaBars and implement the OnInitialize() method:
Code:
namespace CustomBars.UI
{
internal class HealthManaBars: UIState
{
public override void OnInitialize()
{
//empty
}
}
}
Code:
public static bool visible = false;
Code:
UIPanel parent = new UIPanel();
parent.Height.Set(100f, 0f);
parent.Width.Set(300, 0f);
parent.Left.Set(Main.screenWidth - parent.Width.Pixels, 0f);
parent.Top.Set(0f, 0f);
parent.BackgroundColor = new Color(255, 255, 255, 255);
base.Append(parent);
Code:
public HealthManaBars healthManaBars;
.
.
.
public override void Load()
{
if (!Main.dedServ)
{
customRessources = new UserInterface();
healthManaBars = new HealthManaBars();
HealthManaBars.visible = true;
customRessources.SetState(healthManaBars);
}
}
Code:
if (HealthManaBars.visible)
{
//Update CustomBars
customResources.Update(Main._drawInterfaceGameTime);
healthManaBars.Draw(Main.spriteBatch);
}
Terraria has already the most UIElements you need to build your UI. The best is all of them are in terraria style. You can find all elements in your Terraria Reference under Terraria.GameContent.UI.Elements:
We used the UIPanel earlier, but now we want to create our own UIElement. A flat panel without any borders.
So create a new class called UIFlatPanel that inheritance from UIElement. We need a color for the background and a texture. The texture is needed because everything will be drawn using a spriteBatch which require a texture.
Here the texture I use:
Download and put into your project (mine is at {ModID}\Textures\UI). Now we will create our UIElement class:
Code:
namespace CustomBars.UI
{
class UIFlatPanel : UIElement
{
public Color backgroundColor = Color.Gray;
private static Texture2D _backgroundTexture;
public UIFlatPanel ()
{
if (_backgroundTexture == null)
_backgroundTexture = ModLoader.GetTexture("CustomBars/Textures/UI/Blank");
}
}
}
Code:
protected override void DrawSelf(SpriteBatch spriteBatch)
{
CalculatedStyle dimensions = GetDimensions();
Point point1 = new Point((int)dimensions.X, (int)dimensions.Y);
int width = (int)Math.Ceiling(dimensions.Width);
int height = (int)Math.Ceiling(dimensions.Height);
spriteBatch.Draw(_backgroundTexture, new Rectangle(point1.X, point1.Y, width, height), backgroundColor);
}
Now we got our own UIElement and are ready to test it out. Go to your HealthManaBars class and change the UIPanel to our new UIFlatPanel. Also, add another red one and blue one:
Code:
public override void OnInitialize()
{
UIFlatPanel parent = new UIFlatPanel();
parent.Height.Set(65f, 0f);
parent.Width.Set(300f, 0f);
parent.Left.Set(Main.screenWidth - parent.Width.Pixels, 0f);
parent.Top.Set(0f, 0f);
parent.backgroundColor = new Color(255, 255, 255, 255);
UIFlatPanel hp = new UIFlatPanel();
hp.Height.Set(25f, 0f);
hp.Width.Set(280f, 0f);
hp.Left.Set(10f, 0f);
hp.Top.Set(5f, 0f);
hp.backgroundColor = Color.Red;
parent.Append(hp);
UIFlatPanel mana = new UIFlatPanel();
mana.Height.Set(25f, 0f);
mana.Width.Set(280f, 0f);
mana.Left.Set(10f, 0f);
mana.Top.Set(35f, 0f);
mana.backgroundColor = Color.Blue;
parent.Append(mana);
base.Append(parent);
}
5. Implement the Life/Mana Bar
So now we want to show the user the amount of life and mana as text. Also, implement its progress animation. To do so we create a new UIElement that contains two flat panels. One is the background and the other one is the current life/mana. I named the class ResourceBar. I also created an inner enum to set the current stat to display:
Code:
namespace CustomBars.UI
{
internal enum ResourceBarMode
{
HP,
MANA
}
class ResourceBar : UIElement
{
private ResourceBarMode stat;
private float width;
private float height;
public ResourceBar(ResourceBarMode stat, int height, int width)
{
this.stat = stat;
this.width = width;
this.height = height;
}
}
}
Code:
private UIFlatPanel currentBar;
private UIText text;
.
.
.
public override void OnInitialize()
{
Height.Set(height, 0f); //Set Height of element
Width.Set(width, 0f); //Set Width of element
UIFlatPanel barBackground = new UIFlatPanel(); //Create gray background
barBackground.Left.Set(0f, 0f);
barBackground.Top.Set(0f, 0f);
barBackground.backgroundColor = Color.Gray;
barBackground.Width.Set(width, 0f);
barBackground.Height.Set(height, 0f);
currentBar = new UIFlatPanel(); //Create current value panel
currentBar.SetPadding(0);
currentBar.Left.Set(0f, 0f);
currentBar.Top.Set(0f, 0f);
currentBar.Width.Set(width, 0f);
currentBar.Height.Set(height, 0f);
//assign color to panel depending on stat
switch (stat)
{
case ResourceBarMode.HP:
currentBar.backgroundColor = new Color(164, 55, 65); //red
break;
case ResourceBarMode.MANA:
currentBar.backgroundColor = new Color(46, 67, 114); //blue
break;
default:
break;
}
text = new UIText("0|0"); //text to show current hp or mana
text.Width.Set(width, 0f);
text.Height.Set(height, 0f);
text.Top.Set(height / 2 - text.MinHeight.Pixels / 2, 0f); //center the UIText
barBackground.Append(currentBar);
barBackground.Append(text);
base.Append(barBackground);
}
Code:
public override void Draw(SpriteBatch spriteBatch)
{
Player player = Main.player[Main.myPlayer];
float quotient = 1f;
//Calculate quotient
switch (stat)
{
case ResourceBarMode.HP:
quotient = (float)player.statLife / (float)player.statLifeMax;
break;
case ResourceBarMode.MANA:
quotient = (float)player.statMana / (float)player.statManaMax;
break;
default:
break;
}
currentBar.Width.Set(quotient * width, 0f);
Recalculate(); // recalculate the position and size
base.Draw(spriteBatch);
}
Code:
public override void Update(GameTime gameTime)
{
Player player = Main.player[Main.myPlayer]; //Get Player
switch (stat)
{
case ResourceBarMode.HP:
text.SetText("" + player.statLife + " | " + player.statLifeMax); //Set Life
break;
case ResourceBarMode.MANA:
text.SetText("" + player.statMana + " | " + player.statManaMax); //Set Mana
break;
default:
break;
}
base.Update(gameTime);
}
Code:
public override void OnInitialize()
{
ResourceBar hp = new ResourceBar(ResourceBarMode.HP, 280, 25);
hp.Left.Set(Main.screenWidth - hp.Width.Pixels - 10, 0f);
hp.Top.Set(5f, 0f);
base.Append(hp);
ResourceBar mana = new ResourceBar(ResourceBarMode.MANA, 280, 25);
mana.Left.Set(Main.screenWidth - hp.Width.Pixels - 10, 0f);
mana.Top.Set(35f, 0f);
base.Append(mana);
}
Code:
protected override void DrawSelf(SpriteBatch spriteBatch)
{
panel.Left.Set(Main.screenWidth - panel.Width.Pixels, 0f);
panel.Top.Set(0f, 0f);
Recalculate();
}
Now we are ready and got two new bars. In the end, it should look like this:
Thank you for your patience and after you implemented the health bar you will see it´s very easy to create or replace a UI. In some days we will create a custom buff bar.
Credits
the tModLoader Team & Co- creating tModloader, ExampleMod
Re-Logic - Creating that amazing game