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
I have a small issue, in removing the "Resource Bars" layer, you also remove the buff display. Is there any way to remove JUST the life/mana bar, or re-program in the buffs? I'm not to familiar with UI code.
Subaro
Terrarian
If you have the official source on your hands you can search the code where they draw the buffs. You can copy change the code out of the source and put it into your mod. Then the buffs will be displayed as ever and you can add your own custom health/mana bars or any other UI Element.
9IP
Terrarian
Trying to create clickable UI and get two problems.
At first, UI don't response on any clicks/hovers until some random time passed or I Alt+Tab Terraia with UI opend. What can be a problem? I didn't create "parent" UIPanel and using "Vanilla: Inventory" layer.
Second, when clicks actually work, input son't blocked by UI, so any item in hand used simultaneously with OnClick effects. Didn't find any kind of "input blocks"
Also checked ExampleMod, but didn't find any missed calls or something...
At first, UI don't response on any clicks/hovers until some random time passed or I Alt+Tab Terraia with UI opend. What can be a problem? I didn't create "parent" UIPanel and using "Vanilla: Inventory" layer.
Second, when clicks actually work, input son't blocked by UI, so any item in hand used simultaneously with OnClick effects. Didn't find any kind of "input blocks"
Also checked ExampleMod, but didn't find any missed calls or something...
class GemSocketsUI : UIState
{
public static bool visible;
public PathOfTerraria mod;
private UIText head;
private UIText info;
private UIGemSlot[] gemSlots = new UIGemSlot[6];
public GemSocketsUI(PathOfTerraria mod)
{
this.mod = mod;
visible = true;
}
public override void OnInitialize()
{
head = new UIText("Skill Gems");
head.Left.Set(50f, 0f);
head.Top.Set(273f, 0f);
Append(head);
for (int i = 0; i < 6; i++)
{
gemSlots[ i ] = new UIGemSlot(mod, i);
gemSlots[ i ].Left.Set(145f + (47f * i), 0f);
gemSlots[ i ].Top.Set(258f, 0f);
gemSlots[ i ].Width.Set(45f, 0f);
gemSlots[ i ].Height.Set(45f, 0f);
Append(gemSlots[ i ]);
}
}
public override void Draw(SpriteBatch spriteBatch)
{
head.TextColor = Colors.AlphaDarken(Color.Wheat);
base.Draw(spriteBatch);
}
private void slotClick(UIMouseEvent evt, UIElement listener)
{
Main.NewText("ID: " + listener.Id);
}
}
{
public static bool visible;
public PathOfTerraria mod;
private UIText head;
private UIText info;
private UIGemSlot[] gemSlots = new UIGemSlot[6];
public GemSocketsUI(PathOfTerraria mod)
{
this.mod = mod;
visible = true;
}
public override void OnInitialize()
{
head = new UIText("Skill Gems");
head.Left.Set(50f, 0f);
head.Top.Set(273f, 0f);
Append(head);
for (int i = 0; i < 6; i++)
{
gemSlots[ i ] = new UIGemSlot(mod, i);
gemSlots[ i ].Left.Set(145f + (47f * i), 0f);
gemSlots[ i ].Top.Set(258f, 0f);
gemSlots[ i ].Width.Set(45f, 0f);
gemSlots[ i ].Height.Set(45f, 0f);
Append(gemSlots[ i ]);
}
}
public override void Draw(SpriteBatch spriteBatch)
{
head.TextColor = Colors.AlphaDarken(Color.Wheat);
base.Draw(spriteBatch);
}
private void slotClick(UIMouseEvent evt, UIElement listener)
{
Main.NewText("ID: " + listener.Id);
}
}
class UIGemSlot : UIPanel
{
private int slotNumber;
private UIImage image;
private PathOfTerraria mod;
public UIGemSlot(PathOfTerraria _mod, int slotNum)
{
image = new UIImage(Main.itemTexture[0]);
mod = _mod;
slotNumber = slotNum;
}
public override void OnInitialize()
{
SetPadding(0f);
BackgroundColor = Color.Wheat.MultiplyRGBA(new Color(0.6f, 0.6f, 0.6f, 0.8f));
BorderColor = new Color(20, 20, 20, 180);
image.HAlign = UIAlign.Center;
image.VAlign = UIAlign.Center;
image.ImageScale = 0.75f;
Append(image);
}
public override void MouseDown(UIMouseEvent evt)
{
SetImage(Main.itemTexture[Main.mouseItem.type]);
}
private PoTPlayer Player()
{
return Main.LocalPlayer.GetModPlayer<PoTPlayer>(mod);
}
public void SetSlot(int slotNum)
{
slotNumber = slotNum;
}
public int GetSlot()
{
return slotNumber;
}
public void SetImage(Texture2D img)
{
image.SetImage(img);
Recalculate();
}
}
{
private int slotNumber;
private UIImage image;
private PathOfTerraria mod;
public UIGemSlot(PathOfTerraria _mod, int slotNum)
{
image = new UIImage(Main.itemTexture[0]);
mod = _mod;
slotNumber = slotNum;
}
public override void OnInitialize()
{
SetPadding(0f);
BackgroundColor = Color.Wheat.MultiplyRGBA(new Color(0.6f, 0.6f, 0.6f, 0.8f));
BorderColor = new Color(20, 20, 20, 180);
image.HAlign = UIAlign.Center;
image.VAlign = UIAlign.Center;
image.ImageScale = 0.75f;
Append(image);
}
public override void MouseDown(UIMouseEvent evt)
{
SetImage(Main.itemTexture[Main.mouseItem.type]);
}
private PoTPlayer Player()
{
return Main.LocalPlayer.GetModPlayer<PoTPlayer>(mod);
}
public void SetSlot(int slotNum)
{
slotNumber = slotNum;
}
public int GetSlot()
{
return slotNumber;
}
public void SetImage(Texture2D img)
{
image.SetImage(img);
Recalculate();
}
}
public override void ModifyInterfaceLayers(List<GameInterfaceLayer> layers)
{
int interfaceLayer = layers.FindIndex(layer => layer.Name.Equals("Vanilla: Inventory"));
if (interfaceLayer > -1)
{
layers.Insert(interfaceLayer, new LegacyGameInterfaceLayer("PathOfTerraria: Gem Sockets",
delegate
{
if (GemSocketsUI.visible && Main.playerInventory)
{
PoTUI.Update(Main._drawInterfaceGameTime);
gemSocketsUI.Draw(Main.spriteBatch);
}
return true;
},
InterfaceScaleType.UI));
}
}
{
int interfaceLayer = layers.FindIndex(layer => layer.Name.Equals("Vanilla: Inventory"));
if (interfaceLayer > -1)
{
layers.Insert(interfaceLayer, new LegacyGameInterfaceLayer("PathOfTerraria: Gem Sockets",
delegate
{
if (GemSocketsUI.visible && Main.playerInventory)
{
PoTUI.Update(Main._drawInterfaceGameTime);
gemSocketsUI.Draw(Main.spriteBatch);
}
return true;
},
InterfaceScaleType.UI));
}
}
I also have another issue, I can draw the buffs, but the mousetext gets bugged. The default class for that stuff requires an instance of terraria or something, the error says.
9IP
Terrarian
I also have another issue, I can draw the buffs, but the mousetext gets bugged. The default class for that stuff requires an instance of terraria or something, the error says.
so there is a special class to show text when mouse is over something? i guess i somehow missed it and just created UIText
Hi, I would like to know how to you go into the coding page please, I really don't know.
Nakano15
Terrarian
The guide is fine, but you forgot about one thing on the guide.
About adding on the beggining of the code:
Without those, one will get stuck at step 3.
About adding on the beggining of the code:
Code:
using Terraria.UI;
using Terraria.GameContent.UI;
using Terraria.GameContent;
using Terraria.GameContent.UI.Elements;
using Terraria.GameContent.UI.States;
DitherDude
Terrarian
I don't get step 4. Please help.
Caesitas
Terrarian
I want to make a mana like system, how would I go about using UI coding to do so? Without removing health and mana UI.
Nakano15
Terrarian
Ignore this tutorial, go to this one instead: tModLoader - Terraria Interface for Dummies
I am trying to follow this tutorial.
After fixing some of the errors my TModloader was returning I am stuck with a CS0246 at the end of step 3:
the type or namespace "MethodSequenceListItem" could not be found
Usually I managed to fix this error while coding by either referencing libraries or other subfolders - but I can't seem to find any info on the MethodSequenceListItem - topic
Any clue?
After fixing some of the errors my TModloader was returning I am stuck with a CS0246 at the end of step 3:
the type or namespace "MethodSequenceListItem" could not be found
Usually I managed to fix this error while coding by either referencing libraries or other subfolders - but I can't seem to find any info on the MethodSequenceListItem - topic
Any clue?
terrarian10
Plantera
If you have the official source on your hands you can search the code where they draw the buffs. You can copy change the code out of the source and put it into your mod. Then the buffs will be displayed as ever and you can add your own custom health/mana bars or any other UI Element.
Where Can I Find The Scource or the answer to why List<MethodSequenceListItem> is giving me errors?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 itCode: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:
Back to our ModifyInterfaceLayers(...) methode we need to register our interface that we created. We do that directly behind layers.RemoveAt(i):Code:public override void Load() { if (!Main.dedServ) { customRessources = new UserInterface(); } }
3. Create and register our UIStateCode://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:
Now we want to create a visible variable to easily control the current visibility of the UI:Code:namespace CustomBars.UI { internal class HealthManaBars: UIState { public override void OnInitialize() { //empty } } }
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():Code:public static bool visible = false;
Back to the Mod class create a HealthManaBars instance and register the UIState to the UserInterface: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);
To See anything we need to update our UI. To do so go to the ModifyInterfaceLayers() and insert into the MethodSequenceListItem delegate:Code:public HealthManaBars healthManaBars; . . . public override void Load() { if (!Main.dedServ) { customRessources = new UserInterface(); healthManaBars = new HealthManaBars(); HealthManaBars.visible = true; customRessources.SetState(healthManaBars); } }
You can now run build your mod and you will see the first result:Code:if (HealthManaBars.visible) { //Update CustomBars customResources.Update(Main._drawInterfaceGameTime); healthManaBars.Draw(Main.spriteBatch); }
View attachment 153852
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:
View attachment 153854
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: View attachment 153855
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(..):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"); } } }
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.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:
It should look like this: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); }
View attachment 153858
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: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; } } }
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: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); }
Now we need to override the Update(..) method to update the text: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); }
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: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); }
To be able to stay in the top right coner i override the DrawSelf method of HealthManaBars: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); }
Now it should stay at the top right even after resize.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:
View attachment 153883 View attachment 153884
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.
Myself
the tModLoader Team & Co- creating tModloader, ExampleMod
Re-Logic - Creating that amazing game
Thank You!
Similar threads
- Replies
- 2
- Views
- 820
- Replies
- 1
- Views
- 669
- Replies
- 46
- Views
- 15K
- Replies
- 2
- Views
- 7K
-
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.