tModLoader Terraria Interface for Dummies

Status
Not open for further replies.

Agrair

Terrarian
Terraria Interface for Dummies


Congrats! You found my guide on Terraria’s user interface. In this guide, I’ll go over what and how interfaces work, how to create one, and then properly implement it into your mod. It requires some basic terminology, like “class” and “method”. I suggest you figure out what these mean.

There’s also a mod that goes with this. You may have gotten here because of it. If you load it in game, you can use commands to see each example (i.e. /something will display the first example). If you want, here's the source: Agrair/TerrariaUITutorial


Fundamentals

The Terraria UI framework is very polymorphic. All classes (at least the one’s I’ll show) inherit from UIElement, allowing us to manipulate our UI to a great extent. Don’t understand? It’ll become clear soon enough. There are three classes you’ll probably use the most. UIState, UIPanel, and UIElement (UIState and UIPanel inherit from UIElement, meaning values and methods in UIElement will appear in both without actually being implemented. We use this to our advantage). You can think of UI as a family tree. UIState is the head of the family, UIPanels are beneath them, and UIElements beneath them. UIPanels and UIElements are appended to their “parents”. In a practical sense, only UIPanels can draw themselves because they usually tend to be blue rectangles that look like control panels in game (hence the name). Not too much complexity, is there. UIElements are things like buttons and text boxes. They move, change, and are interacted with by the player. You can always append UIElements directly to a UIState if you don’t want to use UIPanels. You use a UIState to keep them all in one place. There’s a fourth class I haven’t talked about, and it’s called UserInterface. This is a handy little “wrapper” that does all the extra stuff for you and puts them into one or two methods.

Still with me? Great, on to the next bit. You can always take a break though, which is a good idea if you need a rest from reading.


Starting out - Something

We’re going to create a blank square that we can drag around the screen. First, you want to create a folder called UI and a file called "SomethingUI.cs" (change this to whatever you want) inside. Note that you need to change `TerrariaUITutorial` and `SomethingUI` to whatever you like. Namespace is just the same as folder path.
Code:
using Terraria.UI;

namespace TerrariaUITutorial.UI
{
     internal class SomethingUI : UIState
     {
          public override void OnInitialize()
          {
          }
     }
}
This doesn't do anything by itself, we'll need to add some stuff to it. Create a file called "DragableUIPanel.cs", and fill it with this code. Note that you need to change the namespace again. This facilitates a UIPanel that can be dragged anywhere across the screen. You'll need to reference Microsoft.Xna.Framework at this point (see step 11).
Code:
using Terraria.UI;

namespace TerrariaUITutorial.UI
{
    internal class SomethingUI : UIState
    {
        public static bool visible;
        public DragableUIPanel panel;

        public override void OnInitialize()
        {
            // if you set this to true, it will show up in game
            visible = false;

            panel = new DragableUIPanel(); //initialize the panel
            // ignore these extra 0s
            panel.Left.Set(800, 0); //this makes the distance between the left of the screen and the left of the panel 500 pixels (somewhere by the middle)
            panel.Top.Set(100, 0); //this is the distance between the top of the screen and the top of the panel
            panel.Width.Set(100, 0);
            panel.Height.Set(100, 0);

            Append(panel); //appends the panel to the UIState
        }
    }
}
Look at the comments and see what this does now. This still doesn't do anything. UIStates aren't autoloaded by tModLoader, like ModItems and ModNPCs. You need to initialize it manually. This is what my mod class looks like:
Code:
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Terraria;
using Terraria.ModLoader;
using Terraria.UI;
using TerrariaUITutorial.UI;

namespace TerrariaUITutorial
{
    public class TerrariaUITutorial : Mod
    {
        internal SomethingUI somethingUI;
        public UserInterface somethingInterface;

        public override void Load()
        {
            // this makes sure that the UI doesn't get opened on the server
            // the server can't see UI, can it? it's just a command prompt
            if (!Main.dedServ)
            {
                somethingUI = new SomethingUI();
                somethingUI.Initialize();
                somethingInterface = new UserInterface();
                somethingInterface.SetState(somethingUI);
            }
        }

        public override void UpdateUI(GameTime gameTime)
        {
            // it will only draw if the player is not on the main menu
            if (!Main.gameMenu
                && SomethingUI.visible)
            {
                somethingInterface?.Update(gameTime);
            }
        }

        public override void ModifyInterfaceLayers(List<GameInterfaceLayer> layers)
        {
            layers.Add(new LegacyGameInterfaceLayer("Cool Mod: Something UI", DrawSomethingUI, InterfaceScaleType.UI));
        }

        private bool DrawSomethingUI()
        {
            // it will only draw if the player is not on the main menu
            if (!Main.gameMenu
                && SomethingUI.visible)
            {
                somethingInterface.Draw(Main.spriteBatch, new GameTime());
            }
            return true;
        }
    }
}
At this point, you definitely need Microsoft.Xna.Framework. However, even at this point, it's still not visible. Why? Because of `SomethingUI.visible`. Back in SomethingUI.OnInitialize, we set it to false. But if you set it to true, it should work (sorry about the really bad quality):
Congrats, you've created your first UI! However, there's *still* something wrong with your UI. Changing the UI scale in your settings will completely change the position. We can remedy this by making the code look like this now:
Code:
using Microsoft.Xna.Framework;
using Terraria;
using Terraria.UI;

namespace TerrariaUITutorial.UI
{
    internal class SomethingUI : UIState
    {
        public static bool visible;
        private DragableUIPanel panel;
        public float oldScale;

        public override void OnInitialize()
        {
            // if you set this to true, it will show up in game
            visible = false;

            panel = new DragableUIPanel(); //initialize the panel
            // ignore these extra 0s
            panel.Left.Set(800, 0); //this makes the distance between the left of the screen and the left of the panel 800 pixels (somewhere by the middle).
            panel.Top.Set(100, 0); //this is the distance between the top of the screen and the top of the panel
            panel.Width.Set(100, 0);
            panel.Height.Set(100, 0);

            Append(panel); //appends the panel to the UIState
        }

        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
            if (oldScale != Main.inventoryScale)
            {
                oldScale = Main.inventoryScale;
                Recalculate();
            }
        }
    }
}

UI is a very delicate part of coding, and I hope that this guide helped you in some way or another. Sometimes, it can take awhile to complete, but with enough practice and understanding you can get the hang of it.
If you found this tutorial helpful, I'm glad you did.
 
Last edited:
So, it has come to my attention that the mod is only compilable using C#6, so just ensure that `languageVersion = 6` is in "build.txt".
 
Last edited:
In your mod class, you have a method UpdateUI(). It says:
Code:
public override void UpdateUI(GameTime gameTime)
       {
           // it will only draw if the player is not on the main menu
           if (!Main.gameMenu
               && SomethingUI.visible)
           {
               somethingInterface?.Update(gameTime);
           }
       }
There is a '?' after somethingInterface. It seems like a mistake? It builds OK, but seems to generate an error. It works fine in game without the question mark.

The Command SomethingCommand.cs doesn't seem to be accepted by tModLoader. I take it the intension is that you type the word "something" in the chat to toggle SomethingUI.visible true/false? Correct?

Other than the classes, which you've described, there is also UITextPanel<T> : UIPanel, which is under Terraria.GameContent.UI.Elements. T is usually string. It seems to be a kind of a subpanel with text.
 
Last edited:
In your mod class, you have a method UpdateUI(). It says:
Code:
public override void UpdateUI(GameTime gameTime)
       {
           // it will only draw if the player is not on the main menu
           if (!Main.gameMenu
               && SomethingUI.visible)
           {
               somethingInterface?.Update(gameTime);
           }
       }
There is a '?' after somethingInterface. It seems like a mistake? It builds OK, but seems to generate an error. It works fine in game without the question mark.

The Command SomethingCommand.cs doesn't seem to be accepted by tModLoader. I take it the intension is that you type the word "something" in the chat to toggle SomethingUI.visible true/false? Correct?

Other than the classes, which you've described, there is also UITextPanel<T> : UIPanel, which is under Terraria.GameContent.UI.Elements. T is usually string. It seems to be a kind of a subpanel with text.

The ? is not necessary, it’s what’s called an in-line null check, it just makes sure that everything is loaded before doing anything, it’s fine if you remove it but I’m not sure what will happen upon reload. It’s a C#6 or 7 feature

Correct, that’s what it’s supposed to do, it uses another C# 7 feature

Not sure what you want, do you want an explanation for what it does?
[doublepost=1557760965,1557760931][/doublepost]PS: sorry about all the C#7, it’s just something I’ve become really accustomed to, not everyone has it tho
 
I use TModLoader v0.10.1.5 (I think it's the latest one) and it doesn't seem to accept code like this. Did you get it to run in Terraria? I'm getting errors CS1525 and CS1002. Both seem like simple syntax errors. I got it to run only after removing the '?' in UpdateUI() and completely removing the command. Only in Terraria. In Visual Studio it builts OK.

Thank you for explaining the new C# feature. I saw it in code of the other mods as well.

I mentioned UITextPanel<T> class as I saw it in other mods and you haven't mentioned it. Maybe you consider adding it to your Guide, especially since you plan part 2.

Your Guide was very very helpful to me. Thank you for posting it. I tried to do exactly what you've expained. I want to mod Signs: either use Terraria functionality or make a cusom one in order to add readable and writable books and scrolls to the game (not to be confused with spells). Either way this requires creation of some kind of UI.

Therefore part 2 of your Guide would be crucial. I struggle with how to add buttons and a text field to the panel.
 
Last edited:
Yeaah, C#7 isn’t something open to the general public, I’ll add something to the forum explaining how to get it

Kk, I’ll add that to the list of examples I’ll do
[doublepost=1557787950,1557787367][/doublepost]Added the little explanation
 
Status
Not open for further replies.
Back
Top Bottom