Legacy/HUD: Unity 3D OnGUI Remake

Overview Code Author: Loken01 For a while I had taken a break from UDK and had been using Unity3D for a bit, and even though it will never quite match up with AutoDesk ScaleForm, I thought I'd give...

Overview

Code Author: Loken01

For a while I had taken a break from UDK and had been using Unity3D for a bit, and even though it will never quite match up with AutoDesk ScaleForm, I thought I'd give it a whirl at making a more simplistic HUD system for users.

The basics of AHUD I learnt from Rama's awesome tutorials! HUD, Canvas, Code Sample of 800+ Lines

Everything in this is based on objects, so everything can handle it's own instance! Makes things super easy for us!

Functions Matching Unity's GUI class

  • Labels
  • Textures
  • Materials
  • Animated Materials
  • Buttons
  • Animated Buttons
  • Horizontal Sliders
  • Vertical Sliders
  • Movable Windows (Coming soon)

Transparency

Everything in this entire HUD system has full control over transparency. Materials are handled in the material editor. Textures work best if their LOD group is set to 'UI'.

Centering

I wanted to make sure everything could be scaled according to screen size so I made four functions:

  • Scale Width
  • Scale Height
  • Center Horizontal
  • Center Vertical

These work based on getting the sizes from the Canvas, and then doing a check against the relative position of 1920x1080. It means no matter the screen size, everything will stay exactly the same relative to the edges of the screen.

Input

Currently the only form of input is the mouse. But you can use your PlayerController or Character class to bind other actions and simply tweak this code. My personal version works using the controller and simulating mouse movement, but I wanted to generalize as much as possible for this tutorial.

Demos

So I made a few gifs just to show what could be done in about 2-3 minutes with this HUD system!

Labels:

File:Label.png
File:Label.png

Buttons:

File:Button.gif
File:Button.gif

Animated Buttons:

File:AnimatedButton.gif
File:AnimatedButton.gif

Horizontal Sliders:

File:HorizontalSlider.gif
File:HorizontalSlider.gif

Vertical Sliders:

File:VerticalSlider.gif
File:VerticalSlider.gif

Credit

Everything I learnt about the standard AHUD system came directly from Rama, so this is like an extension to his work

Apart from a few tiny bits here and there, (Rama's) almost all of this is my own creation.

Also a big thanks to DroseGaming for helping me with some bug issues!

Why Did I make this system?

I wanted it to be easier to make an easy to use object based system that could be easily managed in memory, handle their own animations, etc dynamically, without cluttering up your HUD class.

Pre-requisites

As in Rama's tutorial, you need to have a few things:

Font

Creat a font in your content browser. Right click, and make a new font, and give it a large default size. I tend to just stick it to the highest.

Texture

Literally any texture would do.

Button Material

Create a new material and set it to be Transparent and Unlit. You will need a button 'Up' and button 'Down' texture. You will need two parameters called 'Highlight' and 'Click'

And finally plug everything together like so:

File:ButtonMaterial.png
File:ButtonMaterial.png

Animated Button Material

This can be done exactly the same as above, but the textures would need to be in a sprite sheet like layout.

Slider Background Material

Create a material that is Transparent and Unlit. Only really needs the one texture.

Slider Button Material

For this you can simply use any "Button Material"

C++ Code

The code below assumes you have created a new class named "YourHud". Although you can rename to whatever you want. Just clean up any references. Simply replace any references to "YourGame.h" to be whatever your game has been called.

HUDObjects.h

153 Lines

#pragma once

#include "GameFramework/HUD.h"
#include "HUDObjects.generated.h"

USTRUCT()
struct FShapeStruct
{
    GENERATED_USTRUCT_BODY()

    //Vars
    float x;
    float y;
    float w;
    float h;

    //default properties
    FShapeStruct()
    {
        x = 0;
        y = 0;
        w = 0;
        h = 0;
    }
};

UCLASS()
class UHUDObjects : public UObject
{
    GENERATED_UCLASS_BODY()

    protected:
        //State handler
        bool IsButton;

        //Shape and positioning of this object
        FShapeStruct BGShapeAndPos;

        //Shape and positioning of this object
        FShapeStruct ShapeAndPos;

        //Background material reference
        UPROPERTY()
        UMaterialInterface* BackGround;

        //Slider background material reference
        UPROPERTY()
        UMaterialInterface* SliderBackGround;

        //Created material instance reference
        UPROPERTY()
        UMaterialInstanceDynamic* MIObj;

        //Created material instance for a slider background
        UPROPERTY()
        UMaterialInstanceDynamic* BGMIObj;

        //Name of the highlight parameter
        FString HighLightName;

        //Name of the click parameter
        FString ClickName;

        //Whether or not this has an animation
        bool bHasAnim;

        //Scale of the text
        float ScaleAmount;

        //Text
        FString Text;

        //Reference to the font used
        UPROPERTY()
        UFont* Font;

        //Animation
        FVector2D AnimTiling;
        //Number of tiles in total
        int NumTiles;
        //Time between frame updates
        float FrameUpdateDelay;
        //Current time taken from the last frame update
        float currentTime;

        //CurrentAnimTile
        int Tile;
        float MatU;
        float MatV;
        float MatUWidth;
        float MatVHeight;

        float CropU;
        float CropV;
        float CropX;
        float CropY;

        UPROPERTY()
        UTexture2D* Texture;

    //Functions
    public:
        //State of button
        bool IsInside;
        bool bGrabbed;

        //If the passed position is within the screen bounds of this object
        bool Hovered();

        //Update and Draw depending on how the object was initialised
        //SHOULD BE CALLED WITH CARE
        void Update(AHUD* HUDRef, FVector2D MousePos, float x, float y, float w, float h, float Scale, FLinearColor TextColour = FLinearColor::White);

        //Draw the horizontal slider
        float DrawHorizontalSlider(AHUD* HUDRef, float Amount, float MinAmount, float MaxAmount, FVector2D MousePos, float x, float y, float w, float h, float Scale);

        //Draw the vertical slider
        float DrawVerticalSlider(AHUD* HUDRef, float Amount, float MinAmount, float MaxAmount, FVector2D MousePos, float x, float y, float w, float h, float Scale);

        //Check for click on slider BG
        bool CheckInsideSliderBG(FVector2D MousePos);

        //Draw the texture that this object was initialised with.
        //SHOULD BE CALLED WITH CARE
        void DrawTexture(AHUD* HUDRef, float x, float y, float w, float h, FColor pColour);

        //Crops the U/V sizes. 0=No crop, 1=MaxCrop
        //This will only work on Texture or Animation Objects
        void CropObjectUV(FVector2D UVCrop);

        //Crops the X/Y sizes. 0=No crop, 1=MaxCrop
        //This will only work on Texture or Animation Objects
        void CropObjectXY(FVector2D XYCrop);

        //Initialise this object with only Text
        void Init(FString pText, UFont* pFont);
        //Initialise this object with only a texture
        void Init(UTexture2D* pTexture);
        //Initialise this object with a highlightable material
        void Init(bool pIsButton, UMaterialInterface* BackgroundMaterial, FString pHighLightName, FString pClickName);
        //Initialise this object with a slider button and background
        void Init(bool pIsButton, UMaterialInterface* SliderMaterial, FString pHighLightName, FString pClickName, UMaterialInterface* BackgroundMaterial);
        //Initialise this object with a highlightable material with text
        void Init(bool pIsButton, UMaterialInterface* BackgroundMaterial, FString pHighLightName, FString pClickName, FString pText, UFont* pFont);
        //Initialise this object with a highlightable animated material
        void Init(bool pIsButton, UMaterialInterface* BackgroundMaterial, FString pHighLightName, FString pClickName, FVector2D pAnimTiling, int pNumTiles, float pFrameUpdateDelay);
        //Initialise this object with a highlightable animated material with text
        void Init(bool pIsButton, UMaterialInterface* BackgroundMaterial, FString pHighLightName, FString pClickName, FString pText, UFont* pFont, FVector2D pAnimTiling, int pNumTiles, float pFrameUpdateDelay);

    protected:
        void UpdateAnim();
        void CheckInside(FVector2D MousePos);
};

HUDObjects.cpp

487 Lines

#include "YourGame.h"
#include "HUDObjects.h"

UHUDObjects::UHUDObjects(const class FPostConstructInitializeProperties& PCIP) : Super(PCIP)
{}

void UHUDObjects::Init(UTexture2D* pTexture)
{
    //Pass the texture
    Texture = pTexture;
}

void UHUDObjects::Init(bool pIsButton, UMaterialInterface* BackgroundMaterial, FString pHighLightName, FString pClickName)
{
    //Initialise global variables with passed parameters
    IsButton = pIsButton;

    //This material pointer is assigned as another pointer isn't it?
    //So how would I make is it's own dynamic instance?
    BackGround = BackgroundMaterial;

    //Set the highlight and click names
    HighLightName = pHighLightName;
    ClickName = pClickName;

    //If the material exists
    if (BackGround != NULL)
    {
        //Create an instance of it
        MIObj = UMaterialInstanceDynamic::Create(BackGround->GetMaterial(), this);
    }//if
}//Init

void UHUDObjects::Init(bool pIsButton, UMaterialInterface* SliderMaterial, FString pHighLightName, FString pClickName, UMaterialInterface* BackgroundMaterial)
{
    //pass vars
    Init(pIsButton, SliderMaterial, pHighLightName, pClickName);
    //set slider background
    SliderBackGround = BackgroundMaterial;

    //if it exists
    if (SliderBackGround != NULL)
    {
        //create an instance of it
        BGMIObj = UMaterialInstanceDynamic::Create(SliderBackGround->GetMaterial(), this);
    }//if
}//Init

void UHUDObjects::Init(bool pIsButton, UMaterialInterface* BackgroundMaterial, FString pHighLightName, FString pClickName, FVector2D pAnimTiling, int pNumTiles, float pFrameUpdateDelay)
{
    //pass vars
    Init(pIsButton, BackgroundMaterial, pHighLightName, pClickName);

    //set anim tilings
    AnimTiling = pAnimTiling;
    //set number of anim tiles
    NumTiles = pNumTiles;
    //set that we have an anim
    bHasAnim = true;
    //set up frame delay
    FrameUpdateDelay = pFrameUpdateDelay;
    //set current time to the max
    currentTime = FrameUpdateDelay;
    //set current tile to 0
    Tile = 0;
    //calculate the u width of the material
    MatUWidth = 1 / AnimTiling.X;
    //calculate the v width of the material
    MatVHeight = 1 / AnimTiling.Y;
}//Init

void UHUDObjects::Init(bool pIsButton, UMaterialInterface* BackgroundMaterial, FString pHighLightName, FString pClickName, FString pText, UFont* pFont, FVector2D pAnimTiling, int pNumTiles, float pFrameUpdateDelay)
{
    //pass vars
    Init(pIsButton, BackgroundMaterial, pHighLightName, pClickName, pAnimTiling, pNumTiles, pFrameUpdateDelay);

    //set text
    Text = pText;
    //set font
    Font = pFont;
}//Init

void UHUDObjects::Init(FString pText, UFont* pFont)
{
    //Initialise global variables with passed parameters
    IsButton = false;
    Text = pText;
    Font = pFont;
}//Init

void UHUDObjects::Init(bool pIsButton, UMaterialInterface* BackgroundMaterial, FString pHighLightName, FString pClickName, FString pText, UFont* pFont)
{
    //pass vars
    Init(pIsButton, BackgroundMaterial, pHighLightName, pClickName);
    //Set text
    Text = pText;
    //Set font
    Font = pFont;
}//Init

void UHUDObjects::CheckInside(FVector2D MousePos)
{
    //If within the X area
    if (MousePos.X > ShapeAndPos.x &amp;&amp; MousePos.X < ShapeAndPos.x + ShapeAndPos.w)
    {
        //If within the Y area
        if (MousePos.Y > ShapeAndPos.y &amp;&amp; MousePos.Y < ShapeAndPos.y + ShapeAndPos.h)
        {
            //Mouse is inside
            IsInside = true;
        }//if
        else
        {
            //Mouse is not inside
            IsInside = false;
        }//else
    }//if
    else
    {
        //Mouse is not inside
        IsInside = false;
    }//else

    //If the material instance exists and the highlight name exists
    if (MIObj != NULL &amp;&amp; IsButton &amp;&amp; HighLightName.Len() > 0)
    {
        //Set up var
        float TmpVar;
        //Get highlight value, to be sure it exists
        if (MIObj->GetScalarParameterValue(FName(*HighLightName), TmpVar))
        {
            //if we are inside
            if (IsInside)
            {
                //set it to 1
                MIObj->SetScalarParameterValue(FName(*HighLightName), 1);
            }//if
            else
            {
                //otherwise set it to 0
                MIObj->SetScalarParameterValue(FName(*HighLightName), 0);
            }//else
        }//if
    }//if

    //If the material instance exists and the click name exists
    if (MIObj != NULL &amp;&amp; IsButton &amp;&amp; ClickName.Len() > 0)
    {
        //Set up var
        float TmpVar;
        //Get click value, to be sure it exists
        if (MIObj->GetScalarParameterValue(FName(*ClickName), TmpVar))
        {
            //if it has been grabbed
            if (bGrabbed)
            {
                //set it to 1
                MIObj->SetScalarParameterValue(FName(*ClickName), 1);
            }//if
            else
            {
                //otherwise set it to 0
                MIObj->SetScalarParameterValue(FName(*ClickName), 0);
            }//else
        }//if
    }//if

}//CheckInside

bool UHUDObjects::CheckInsideSliderBG(FVector2D MousePos)
{
    //If within the X area
    if (MousePos.X > BGShapeAndPos.x &amp;&amp; MousePos.X < BGShapeAndPos.x + BGShapeAndPos.w)
    {
        //If within the Y area
        if (MousePos.Y >(BGShapeAndPos.y - BGShapeAndPos.h) &amp;&amp; MousePos.Y < BGShapeAndPos.y + (BGShapeAndPos.h * 2))
        {
            //Mouse is inside
            return true;
        }//if
        else
        {
            //Mouse is not inside
            return false;
        }//else
    }//if
    else
    {
        //Mouse is not inside
        return false;
    }//else
}

bool UHUDObjects::Hovered()
{
    return IsInside;
}//Hovered

void UHUDObjects::UpdateAnim()
{
    //if the time is greater than 0
    if (currentTime > 0)
    {
        //decrement it
        currentTime -= 0.01f;
    }//if
    else
    {
        //otherwise reset it
        currentTime = FrameUpdateDelay;

        //if the current tile is less than the max number of tiles
        if (Tile < (NumTiles - 1))
        {
            //increment it
            Tile += 1;

            //increment the u position
            MatU += MatUWidth;

            //if the u position is now equal to or greater than 1
            if (MatU >= 1)
            {
                //reset it to 0
                MatU = 0;

                //increment the v position
                MatV += MatVHeight;

                //if the v position is now equal to or greater than 1
                if (MatV >= 1)
                {
                    //reset it
                    MatV = 0;
                }//if
            }//if
        }//if
        else
        {
            //otherwise reset everything
            Tile = 0;
            MatU = 0;
            MatV = 0;
        }//else
    }//else
}//UpdateAnim

void UHUDObjects::Update(AHUD* HUDRef, FVector2D MousePos, float x, float y, float w, float h, float Scale, FLinearColor TextColour)
{
    //Set vars
    ShapeAndPos.x = x;
    ShapeAndPos.y = y;
    ShapeAndPos.w = w;
    ShapeAndPos.h = h;
    ScaleAmount = Scale;

    //Check if the mouse is inside the object
    CheckInside(MousePos);

    //If the BG material reference  isn't null, and the passed HUD isn't null
    if (HUDRef != NULL)
    {
        if (MIObj != NULL)
        {
            //if this is an animation
            if (bHasAnim)
            {
                //Update the animation
                UpdateAnim();

                HUDRef->DrawMaterial(MIObj,
                    ShapeAndPos.x, ShapeAndPos.y,                               //X and Y
                    ShapeAndPos.w - (ShapeAndPos.w * CropX),                    //Width Minus cropped percentage
                    ShapeAndPos.h - (ShapeAndPos.h * CropY),                    //Height Minus cropped percentage
                    MatU + (MatUWidth * CropX),                                 //U start plus percentage of U Width
                    MatV + (MatVHeight * CropY),                                //V start plus percentage of V Height
                    (MatUWidth * (1 - CropU)) - (MatUWidth * CropX),            //Width is percentage of cropped U, 
                    (MatVHeight * (1 - CropV)) - (MatVHeight * CropY),          //Height is percentage of cropped V, 
                    1, false);                                                  //Other bits
            }//if
            else
            {
                //Draw the material as assigned
                HUDRef->DrawMaterialSimple(MIObj, ShapeAndPos.x, ShapeAndPos.y, ShapeAndPos.w, ShapeAndPos.h, 1, false);
            }//else
        }//If

        //if the text isn't empty
        if (!Text.IsEmpty())
        {
            //if the font exists
            if (Font != NULL)
            {
                //Get the font text size
                float tWidth, tHeight;
                HUDRef->GetTextSize(Text, tWidth, tHeight, Font, ScaleAmount);

                //Calculate spaceing around the text inside the button
                float newX = (ShapeAndPos.w - tWidth) / 2;
                float newY = (ShapeAndPos.h - tHeight) / 2;

                //Draw text and adjust for center
                HUDRef->DrawText(Text, TextColour, ShapeAndPos.x + newX, ShapeAndPos.y + newY, Font, ScaleAmount, false);
            }//if
        }//if   
    }//if

}//Update

float UHUDObjects::DrawHorizontalSlider(AHUD* HUDRef, float Amount, float MinAmount, float MaxAmount, FVector2D MousePos, float x, float y, float w, float h, float Scale)
{
    //Set vars
    BGShapeAndPos.x = x;
    BGShapeAndPos.y = y;
    BGShapeAndPos.w = w;
    BGShapeAndPos.h = h;
    ScaleAmount = Scale;

    //Work out how much to extend the slider to make it fit correctly
    float BGWidener = BGShapeAndPos.w * 0.08f;
    //If the BG material reference  isn't null, and the passed HUD isn't null
    if (HUDRef != NULL)
    {
        if (BGMIObj != NULL)
        {
            //Draw the material as assigned
            HUDRef->DrawMaterialSimple(BGMIObj, BGShapeAndPos.x - BGWidener, BGShapeAndPos.y, BGShapeAndPos.w + (BGWidener * 2), BGShapeAndPos.h, 1, false);
        }//if
    }//if

    //Get a percentage between 0-1
    float PercentageAlong = Amount / (MaxAmount - MinAmount);

    //Work out the size/position of the slider, based off of the total size
    ShapeAndPos.w = BGShapeAndPos.w*0.05f;
    ShapeAndPos.x = (BGShapeAndPos.x + (BGShapeAndPos.w * PercentageAlong)) - (ShapeAndPos.w/2);
    ShapeAndPos.h = BGShapeAndPos.h * 2.5f;
    ShapeAndPos.y = BGShapeAndPos.y - ((ShapeAndPos.h - BGShapeAndPos.h)/2);

    //Check if the mouse is inside the object
    CheckInside(MousePos);

    //if the object has been grabbed
    if (bGrabbed)
    {
        //then we are inside
        IsInside = true;

        //calculate slider ranges
        float Left = (BGShapeAndPos.x + (BGShapeAndPos.w * 0)) - (ShapeAndPos.w / 2);
        float Right = (BGShapeAndPos.x + (BGShapeAndPos.w * 1)) - (ShapeAndPos.w / 2);

        //Update the object to match the mouse pos
        ShapeAndPos.x = (MousePos.X) - (ShapeAndPos.w / 2);
        //Clamp within ranges
        ShapeAndPos.x = FMath::Clamp(ShapeAndPos.x, Left, Right);

        //work out the new percentage to return
        PercentageAlong = ((ShapeAndPos.x - BGShapeAndPos.x) + (ShapeAndPos.w / 2)) / BGShapeAndPos.w;

        //Calculate the amount to return
        Amount = MaxAmount * PercentageAlong;
        //Clamp again just to be sure
        Amount = FMath::Clamp(Amount, MinAmount, MaxAmount);
    }//if

    //If the BG material reference  isn't null, and the passed HUD isn't null
    if (HUDRef != NULL)
    {
        if (MIObj != NULL)
        {
            //Draw the material as assigned
            HUDRef->DrawMaterialSimple(MIObj, ShapeAndPos.x, ShapeAndPos.y, ShapeAndPos.w, ShapeAndPos.h, 1, false);
        }//if
    }//if
    return Amount;
}//DrawHorizontalSlider

float UHUDObjects::DrawVerticalSlider(AHUD* HUDRef, float Amount, float MinAmount, float MaxAmount, FVector2D MousePos, float x, float y, float w, float h, float Scale)
{
    //Set vars
    BGShapeAndPos.x = x;
    BGShapeAndPos.y = y;
    BGShapeAndPos.w = w;
    BGShapeAndPos.h = h;
    ScaleAmount = Scale;

    //Work out how much to extend the slider to make it fit correctly
    float BGHeightAdd = BGShapeAndPos.h * 0.08f;
    //If the BG material reference  isn't null, and the passed HUD isn't null
    if (HUDRef != NULL)
    {
        if (BGMIObj != NULL)
        {
            //Draw the material as assigned
            HUDRef->DrawMaterialSimple(BGMIObj, BGShapeAndPos.x, BGShapeAndPos.y - BGHeightAdd, BGShapeAndPos.w, BGShapeAndPos.h + (BGHeightAdd * 2), 1, false);
        }//if
    }//if

    //Get a percentage between 0-1
    float PercentageAlong = Amount / (MaxAmount - MinAmount);

    //Inverting
    PercentageAlong = 1 - PercentageAlong;

    //Work out the size/position of the slider, based off of the total size
    ShapeAndPos.h = BGShapeAndPos.h*0.05f;
    ShapeAndPos.y = (BGShapeAndPos.y + (BGShapeAndPos.h * PercentageAlong)) - (ShapeAndPos.h / 2);
    ShapeAndPos.w = BGShapeAndPos.w * 2.5f;
    ShapeAndPos.x = BGShapeAndPos.x - ((ShapeAndPos.w - BGShapeAndPos.w) / 2);

    //Check if the mouse is inside the object
    CheckInside(MousePos);

    //if the object has been grabbed
    if (bGrabbed)
    {
        //then we are inside the button
        IsInside = true;

        //Work out the ranges the slider can meet
        float Top = (BGShapeAndPos.y + (BGShapeAndPos.h * 0)) - (ShapeAndPos.h / 2);
        float Bottom = (BGShapeAndPos.y + (BGShapeAndPos.h * 1)) - (ShapeAndPos.h / 2);

        //Update the object to match the mouse pos
        ShapeAndPos.y = (MousePos.Y) - (ShapeAndPos.h / 2);
        //Clamp within ranges
        ShapeAndPos.y = FMath::Clamp(ShapeAndPos.y, Top, Bottom);

        //Work out the percentage to return
        PercentageAlong = ((ShapeAndPos.y - BGShapeAndPos.y) + (ShapeAndPos.h / 2)) / BGShapeAndPos.h;

        //Inverting
        PercentageAlong = 1 - PercentageAlong;

        //Calculate the amount
        Amount = MaxAmount * PercentageAlong;
        //Clamp it just to be sure
        Amount = FMath::Clamp(Amount, MinAmount, MaxAmount);
    }//if

    //If the BG material reference  isn't null, and the passed HUD isn't null
    if (HUDRef != NULL)
    {
        if (MIObj != NULL)
        {
            //Draw the material as assigned
            HUDRef->DrawMaterialSimple(MIObj, ShapeAndPos.x, ShapeAndPos.y, ShapeAndPos.w, ShapeAndPos.h, 1, false);
        }//if
    }//if
    return Amount;
}//DrawVerticalSlider

void UHUDObjects::DrawTexture(AHUD* HUDRef, float x, float y, float w, float h, FColor pColour)
{
    //if the hud exists
    if (HUDRef != NULL)
    {
        //if the texture exists
        if (Texture != NULL)
        {
            //Draw the texture
            HUDRef->DrawTexture(Texture, x, y,
                w - (w * CropX), 
                h - (h * CropY), 
                0 + CropX, 
                0 + CropY, 
                (1 - CropU) + CropX, 
                (1 - CropV) + CropY, 
                pColour);
        }//if
    }//if
}

void UHUDObjects::CropObjectUV(FVector2D UVCrop)
{
    //Pass in vars within clamped ranges
    CropU = FMath::Clamp(UVCrop.X, 0, 1);
    CropV = FMath::Clamp(UVCrop.Y, 0, 1);
}//CropObjectUV

void UHUDObjects::CropObjectXY(FVector2D XYCrop)
{
    //Pass in vars within clamped ranges
    CropX = FMath::Clamp(XYCrop.X, 0, 1);
    CropY = FMath::Clamp(XYCrop.Y, 0, 1); 
}//CropObjectXY

GUI.h

251 Lines

#pragma once

#include "GameFramework/HUD.h"
#include "HUDObjects.h"
#include "GUI.generated.h"

USTRUCT()
struct FButtonMaterial
{
    GENERATED_USTRUCT_BODY()

    //The material to be used for this HUD object
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Buttons)
        UMaterialInterface* Material;

    //Name of the material var for toggling Highlighting
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Buttons)
        FString HighLightVarName;

    //Name of the material var for toggling Selection
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Animations)
        FString ClickVarName;

    FButtonMaterial()
    {
        //Defaults
        HighLightVarName = "HighLight";
        ClickVarName = "Click";
    }
};

USTRUCT()
struct FAnimationStruct
{
    GENERATED_USTRUCT_BODY()

    //The material to be used for this HUD object
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Animations)
        UMaterialInterface* Material;

    //Name of the material var for toggling Highlighting
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Animations)
        FString HighLightVarName;

    //Name of the material var for toggling Selection
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Animations)
        FString ClickVarName;

    //Animation Rows and Columns
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Animations)
        FVector2D AnimColRows;

    //Total Number of tiles in the animation
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Animations)
        float TotalAnimTiles;

    //Time between each frame
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Animations)
        float FrameDelaySeconds;

    FAnimationStruct()
    {
        //Defaults
        TotalAnimTiles = 0;
        FrameDelaySeconds = 0.5f;
        HighLightVarName = "";
        ClickVarName = "";
    }
};

UCLASS()
class AGUI : public AHUD
{
    GENERATED_UCLASS_BODY()

    // Infiltrace
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Text)
        TArray Fonts;

    //Font scale
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Text)
        float DefaultFontScale;

    //Button Materials 
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Buttons)
        TArray ButtonMaterials;

    //Image Textures
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Textures)
        TArray ImageTextures;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Materials)
        TArray Materials;

    //Animated Materials
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Animations)
        TArray AnimationMaterials;

    // Draw Hud?
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Options)
        bool NoHUD;

    public:
        //Reference to the Player Controller
        UPROPERTY()
        APlayerController* ThePC;

    protected:

        //Screen Sizes
        UPROPERTY()
            float SizeX;
        UPROPERTY()
            float SizeY;

        /*
        * GUI Object that creates a label with simple, centered text
        * @param Object (out) - The object to be instantiated and/or updated
        * @param pHUDRef - The hud pointer to be passed : this
        * @param pText - The text to be displayed
        * @param FontIndex - The font to be used from this HUD's FONT array
        * @param TextColour - The colour of the font to be displayed
        * @param x - The start horizontal position of the object in pixels
        * @param y - The start vertical position of the object in pixels
        * @param w - The width of the object in pixels
        * @param h - The height of the object in pixels
        * @param pScale - Standard AHUD scaling     
        */
        void Label(/* Out */ UHUDObjects* &amp; Object, AHUD* pHUDRef, FString pText, int FontIndex, FLinearColor TextColour, float x, float y, float w, float h, float pScale = 1);

        /*
        * GUI Object that creates a texture at a specified location, with a given size and colour
        * @param Object (out) - The object to be instantiated and/or updated
        * @param pHUDRef - The hud pointer to be passed : this
        * @param TextureIndex - The texture to be used from this HUD's TEXTURE array
        * @param x - The start horizontal position of the object in pixels
        * @param y - The start vertical position of the object in pixels
        * @param w - The width of the object in pixels
        * @param h - The height of the object in pixels
        * @param pColour - The colour adjustment that should be applied to the texture
        */
        void Texture(/* Out */ UHUDObjects* &amp; Object, AHUD* pHUDRef, int TextureIndex, float x, float y, float w, float h, FColor pColour = FColor::White);

        /*
        * GUI Object that creates a basic material, with a given size and position
        * @param Object (out) - The object to be instantiated and/or updated
        * @param pHUDRef - The hud pointer to be passed : this
        * @param MatIndex - The material to be used from this HUD's MATERIAL array
        * @param pText - The text to be displayed
        * @param FontIndex - The font to be used from this HUD's FONT array
        * @param TextColour - The colour of the font to be displayed
        * @param x - The start horizontal position of the object in pixels
        * @param y - The start vertical position of the object in pixels
        * @param w - The width of the object in pixels
        * @param h - The height of the object in pixels
        * @param pScale - Standard AHUD scaling
        */
        void Material(/* Out */ UHUDObjects* &amp; Object, AHUD* pHUDRef, int MatIndex, FString pText, int FontIndex, FLinearColor TextColour, float x, float y, float w, float h, float pScale = 1);

        /*
        * GUI Object that creates an Animated Sprite Sheet Material, with a given size and position
        * @param Object (out) - The object to be instantiated and/or updated
        * @param pHUDRef - The hud pointer to be passed : this
        * @param AnimIndex - The animated material to be used from this HUD's ANIMATEDMATERIAL array
        * @param x - The start horizontal position of the object in pixels
        * @param y - The start vertical position of the object in pixels
        * @param w - The width of the object in pixels
        * @param h - The height of the object in pixels
        * @param pScale - Standard AHUD scaling
        */
        void AnimatedMaterial(/* Out */ UHUDObjects* &amp; Object, AHUD* pHUDRef, int AnimIndex, float x, float y, float w, float h, float pScale = 1);

        /*
        * GUI Object that acts as a button, with 3 states: Normal, Highlighted and Clicked. Returns a bool if clicked
        * @param Object (out) - The object to be instantiated and/or updated
        * @param pHUDRef - The hud pointer to be passed : this
        * @param ButtonIndex - The button material to be used from this HUD's BUTTONMATERIAL array
        * @param pText - The text to be displayed
        * @param FontIndex - The font to be used from this HUD's FONT array
        * @param TextColour - The colour of the font to be displayed
        * @param pMousePos - The position of the mouse in screen space
        * @param x - The start horizontal position of the object in pixels
        * @param y - The start vertical position of the object in pixels
        * @param w - The width of the object in pixels
        * @param h - The height of the object in pixels
        * @param pScale - Standard AHUD scaling
        */
        bool Button(/* Out */ UHUDObjects* &amp; Object, AHUD* pHUDRef, int ButtonIndex, FString pText, int FontIndex, FLinearColor TextColour, FVector2D pMousePos, float x, float y, float w, float h, float pScale = 1);

        /*
        * GUI Object that acts as a button, with 3 animated sprite sheet states: Normal, Highlighted and Clicked. Returns a bool if clicked
        * @param Object (out) - The object to be instantiated and/or updated
        * @param pHUDRef - The hud pointer to be passed : this
        * @param AnimButtonIndex - The button material to be used from this HUD's ANIMATEDMATERIAL array
        * @param pText - The text to be displayed
        * @param FontIndex - The font to be used from this HUD's FONT array
        * @param TextColour - The colour of the font to be displayed
        * @param pMousePos - The position of the mouse in screen space
        * @param x - The start horizontal position of the object in pixels
        * @param y - The start vertical position of the object in pixels
        * @param w - The width of the object in pixels
        * @param h - The height of the object in pixels
        * @param pScale - Standard AHUD scaling
        */
        bool AnimatedButton(/* Out */ UHUDObjects* &amp; Object, AHUD* pHUDRef, int AnimButtonIndex, FString pText, int FontIndex, FLinearColor TextColour, FVector2D pMousePos, float x, float y, float w, float h, float pScale = 1);

        /*
        * GUI Object that returns the updated value of the slider
        * @param Object (out) - The object to be instantiated and/or updated
        * @param pHUDRef - The hud pointer to be passed : this
        * @param SliderButtonIndex - The button material to be used from this HUD's BUTTONMATERIAL array
        * @param SliderBackgroundMaterialIndex - The button material to be used from this HUD's MATERIAL array
        * @param pMousePos - The position of the mouse in screen space
        * @param x - The start horizontal position of the object in pixels
        * @param y - The start vertical position of the object in pixels
        * @param w - The width of the object in pixels
        * @param h - The height of the object in pixels
        * @param Amount - The amount to be passed in on this update pass
        * @param MinAmount - The minimum amount to be used in this slider
        * @param MaxAmount - The maximum amount to be used in this slider
        */
        float HorizontalSlider(/* Out */ UHUDObjects* &amp; Object, AHUD* pHUDRef, int SliderButtonIndex, int SliderBackgroundMaterialIndex, FVector2D pMousePos, float x, float y, float w, float h, float Amount = 0, float MinAmount = 0, float MaxAmount = 1);

        /*
        * GUI Object that returns the updated value of the slider
        * @param Object (out) - The object to be instantiated and/or updated
        * @param pHUDRef - The hud pointer to be passed : this
        * @param SliderButtonIndex - The button material to be used from this HUD's BUTTONMATERIAL array
        * @param SliderBackgroundMaterialIndex - The button material to be used from this HUD's MATERIAL array
        * @param pMousePos - The position of the mouse in screen space
        * @param x - The start horizontal position of the object in pixels
        * @param y - The start vertical position of the object in pixels
        * @param w - The width of the object in pixels
        * @param h - The height of the object in pixels
        * @param Amount - The amount to be passed in on this update pass
        * @param MinAmount - The minimum amount to be used in this slider
        * @param MaxAmount - The maximum amount to be used in this slider
        */
        float VerticalSlider(/* Out */ UHUDObjects* &amp; Object, AHUD* pHUDRef, int SliderButtonIndex, int SliderBackgroundMaterialIndex, FVector2D pMousePos, float x, float y, float w, float h, float Amount = 0, float MinAmount = 0, float MaxAmount = 1);

        //Scaling
        float CenterHorizontal(float Width);
        float CenterVertical(float Height);
        float ScaleWidth(float Width);
        float ScaleHeight(float Height);

        /** after all game elements are created */
        virtual void PostInitializeComponents() OVERRIDE;
        virtual void DrawHUD() OVERRIDE;
};

GUI.cpp

346 Lines

#include "YourGame.h"
#include "GUI.h"

//Constructor
AGUI::AGUI(const class FPostConstructInitializeProperties&amp; PCIP) : Super(PCIP)
{
    //Draw HUD?
    NoHUD = false;

    //Scale
    DefaultFontScale = 0.7;
}//Constructor

//SCALING
float AGUI::ScaleWidth(float Width)
{
    return (Width / 1920)*SizeX;
}///Scale Width

float AGUI::CenterHorizontal(float Width)
{
    return (SizeX / 2) - (ScaleWidth(Width) / 2);
}//CenterHorizontal

float AGUI::ScaleHeight(float Height)
{
    return (Height / 1920)*SizeY;
}//ScaleHeight

float AGUI::CenterVertical(float Height)
{
    return (SizeY / 2) - (ScaleHeight(Height) / 2);
}//CenterVertical

//CORE
void AGUI::PostInitializeComponents()
{
    Super::PostInitializeComponents();

    //Grab the PC
    ThePC = GetOwningPlayerController();
}//PostInitializeComponents

void AGUI::DrawHUD()
{
    //If the PC is NULL
    if (!ThePC)
    {
        //Try to get the PC
        ThePC = GetOwningPlayerController();

        //If there still isn't a PC, then return
        if (!ThePC) return;
    }//if

    //Check that the PC's input exists, otherwise, return
    if (!ThePC->PlayerInput) return;

    //Draw HUD?
    if (NoHUD) return;

    //Super
    Super::DrawHUD();

    //No Canvas?
    if (!Canvas) return;

    //Assign the canvas sizes to the global vars for use outside of DrawHUD
    SizeX = Canvas->SizeX;
    SizeY = Canvas->SizeY;
}//DrawHUD

//GUI WIDGETS
void AGUI::Label(UHUDObjects* &amp; Object, AHUD* pHUDRef, FString pText, int FontIndex, FLinearColor TextColour, float x, float y, float w, float h, float pScale)
{
    //Instantiate new object and assign reference to the pointer
    if (Object == NULL)
    {
        //If the pointer has an object
        if (Fonts.IsValidIndex(FontIndex) &amp;&amp; Fonts[FontIndex] != nullptr)
        {
            Object = NewObject(this);
            if (Object != NULL)
            {
                //Set up the HUD Object
                Object->Init(pText, Fonts[FontIndex]);
            }//if
        }//if
    }//if
    else
    {
        //Update the object
        Object->Update(pHUDRef, FVector2D(0, 0), x, y, w, h, pScale, TextColour);
    }//else
}//Label

void AGUI::Texture(/* Out */ UHUDObjects* &amp; Object, AHUD* pHUDRef, int TextureIndex, float x, float y, float w, float h, FColor pColour)
{
    if (Object == NULL)
    {
        //If the pointer has an object
        if (ImageTextures.IsValidIndex(TextureIndex) &amp;&amp; ImageTextures[TextureIndex] != nullptr)
        {
            Object = NewObject(this);
            if (Object != NULL)
            {
                //Set up the HUD Object
                Object->Init(ImageTextures[TextureIndex]);
            }//if
        }//if
    }//if
    else
    {
        //Update the object
        Object->DrawTexture(pHUDRef, x, y, w, h, FColor::White);
    }//else
}//Texture

void AGUI::Material(UHUDObjects* &amp; Object, AHUD* pHUDRef, int MatIndex, FString pText, int FontIndex, FLinearColor TextColour, float x, float y, float w, float h, float pScale)
{
    if (Object == NULL)
    {
        //If the pointer has an object
        if (ButtonMaterials.IsValidIndex(MatIndex) &amp;&amp; ButtonMaterials[MatIndex].Material != nullptr &amp;&amp; Fonts.IsValidIndex(FontIndex) &amp;&amp; Fonts[FontIndex] != nullptr)
        {
            Object = NewObject(this);
            if (Object != NULL)
            {
                //Set up the HUD Object
                Object->Init(false, Materials[MatIndex], "", "", pText, Fonts[FontIndex]);
            }//if
        }//if   
    }//if
    else
    {
        //Update object
        Object->Update(pHUDRef, FVector2D(0, 0), x, y, w, h, pScale, TextColour);
    }//else
}//Material

void AGUI::AnimatedMaterial(UHUDObjects* &amp; Object, AHUD* pHUDRef, int AnimIndex, float x, float y, float w, float h, float pScale)
{
    //Instantiate new object and assign reference to the pointer
    if (Object == NULL)
    {
        //If the pointer has an object
        if (AnimationMaterials.IsValidIndex(AnimIndex) &amp;&amp; AnimationMaterials[AnimIndex].Material != nullptr)
        {
            Object = NewObject(this);
            if (Object != NULL)
            {
                //Set up the HUD Object
                Object->Init(false, AnimationMaterials[AnimIndex].Material, AnimationMaterials[AnimIndex].HighLightVarName, AnimationMaterials[AnimIndex].ClickVarName, AnimationMaterials[AnimIndex].AnimColRows, AnimationMaterials[AnimIndex].TotalAnimTiles, AnimationMaterials[AnimIndex].FrameDelaySeconds);
            }
        }//if
    }//if
    else
    {
        //Update the object
        Object->Update(pHUDRef, FVector2D(0,0), x, y, w, h, pScale);
    }//else
}//Animated Material

bool AGUI::Button(UHUDObjects* &amp; Object, AHUD* pHUDRef, int ButtonIndex, FString pText, int FontIndex, FLinearColor TextColour, FVector2D pMousePos, float x, float y, float w, float h, float pScale)
{
    //If the object doesn't exit
    if (Object == NULL)
    {
        //If the pointer has an object
        if (ButtonMaterials.IsValidIndex(ButtonIndex) &amp;&amp; ButtonMaterials[ButtonIndex].Material != nullptr &amp;&amp; Fonts.IsValidIndex(FontIndex) &amp;&amp; Fonts[FontIndex] != nullptr)
        {
            //create a new version of the object
            Object = NewObject(this);
            if (Object != NULL)
            {
                //Set up the HUD Object
                Object->Init(true, ButtonMaterials[ButtonIndex].Material, ButtonMaterials[ButtonIndex].HighLightVarName, ButtonMaterials[ButtonIndex].ClickVarName, pText, Fonts[FontIndex]);
            }//if
        }//if   

        return false;
    }//if
    else
    {
        //Update the object
        Object->Update(pHUDRef, pMousePos, x, y, w, h, pScale, TextColour);

        //If the left mouse button is down
        if (ThePC->IsInputKeyDown(EKeys::LeftMouseButton))
        {
            //if the object is hovered and the button was just pressed
            if (Object->Hovered() &amp;&amp; ThePC->WasInputKeyJustPressed(EKeys::LeftMouseButton))
            {
                //we have grabbed the object
                Object->bGrabbed = true;
            }//if
        }//if
        else
        {
            //if the object has been grabbed
            if (Object->bGrabbed)
            {
                //set it to false
                Object->bGrabbed = false;
                return Object->Hovered();
            }//if
            return false;
        }//else
        return false;
    }//else
}//button

bool AGUI::AnimatedButton(UHUDObjects* &amp; Object, AHUD* pHUDRef, int AnimButtonIndex, FString pText, int FontIndex, FLinearColor TextColour, FVector2D pMousePos, float x, float y, float w, float h, float pScale)
{
    //Instantiate new object and assign reference to the pointer
    if (Object == NULL)
    {
        //If the pointer has an object
        if (AnimationMaterials.IsValidIndex(AnimButtonIndex) &amp;&amp; AnimationMaterials[AnimButtonIndex].Material != nullptr &amp;&amp; Fonts.IsValidIndex(FontIndex) &amp;&amp; Fonts[FontIndex] != nullptr)
        {
            //create a new object
            Object = NewObject(this);
            if (Object != NULL)
            {
                //Set up the HUD Object
                Object->Init(true, AnimationMaterials[AnimButtonIndex].Material, AnimationMaterials[AnimButtonIndex].HighLightVarName, AnimationMaterials[AnimButtonIndex].ClickVarName, pText, Fonts[FontIndex], AnimationMaterials[AnimButtonIndex].AnimColRows, AnimationMaterials[AnimButtonIndex].TotalAnimTiles, AnimationMaterials[AnimButtonIndex].FrameDelaySeconds);
            }//if
        }//if

        return false;
    }//if
    else
    {
        //update object
        Object->Update(pHUDRef, pMousePos, x, y, w, h, pScale, TextColour);

        //if the left mouse button is down
        if (ThePC->IsInputKeyDown(EKeys::LeftMouseButton))
        {
            //if the mouse is over the object and the button was pressed during this frame
            if (Object->Hovered() &amp;&amp; ThePC->WasInputKeyJustPressed(EKeys::LeftMouseButton))
            {
                //we have grabbed the object
                Object->bGrabbed = true;
            }//if
        }//if
        else
        {
            //if the object has been grabbed
            if (Object->bGrabbed)
            {
                //set it to false
                Object->bGrabbed = false;
                return Object->Hovered();
            }//if
            return false;
        }//else
        return false;
    }//else
}//AnimatedButton

float AGUI::HorizontalSlider(UHUDObjects* &amp; Object, AHUD* pHUDRef, int SliderButtonIndex, int SliderBackgroundMaterialIndex, FVector2D pMousePos, float x, float y, float w, float h, float Amount, float MinAmount, float MaxAmount)
{
    if (Object == NULL)
    {
        //If the pointer has an object
        if (ButtonMaterials.IsValidIndex(SliderButtonIndex) &amp;&amp; ButtonMaterials[SliderButtonIndex].Material != nullptr &amp;&amp; Materials.IsValidIndex(SliderBackgroundMaterialIndex) &amp;&amp; Materials[SliderBackgroundMaterialIndex] != nullptr)
        {
            Object = NewObject(this);
            if (Object != NULL)
            {
                //Set up the HUD Object
                Object->Init(true, ButtonMaterials[SliderButtonIndex].Material, ButtonMaterials[SliderButtonIndex].HighLightVarName, ButtonMaterials[SliderButtonIndex].ClickVarName, Materials[SliderBackgroundMaterialIndex]);
            }//if
        }//if

        return Amount;
    }//if
    else
    {
        if (ThePC->IsInputKeyDown(EKeys::LeftMouseButton))
        {
            if ((Object->Hovered() 

 Object->CheckInsideSliderBG(pMousePos)) &amp;&amp; ThePC->WasInputKeyJustPressed(EKeys::LeftMouseButton))
            {
                Object->bGrabbed = true;
            }//if
        }//if
        else
        {
            if (Object->bGrabbed)
            {
                Object->bGrabbed = false;
            }//if
        }//else

        //Clamp the range just to be sure
        Amount = FMath::Clamp(Amount, MinAmount, MaxAmount);

        //Draw slider button
        return Object->DrawHorizontalSlider(pHUDRef, Amount, MinAmount, MaxAmount, pMousePos, x, y, w, h, 1);
    }//else
    return Amount;
}//HorizontalSlider

float AGUI::VerticalSlider(UHUDObjects* &amp; Object, AHUD* pHUDRef, int SliderButtonIndex, int SliderBackgroundMaterialIndex, FVector2D pMousePos, float x, float y, float w, float h, float Amount, float MinAmount, float MaxAmount)
{
    if (Object == NULL)
    {
        //If the pointer has an object
        if (ButtonMaterials.IsValidIndex(SliderButtonIndex) &amp;&amp; ButtonMaterials[SliderButtonIndex].Material != nullptr &amp;&amp; Materials.IsValidIndex(SliderBackgroundMaterialIndex) &amp;&amp; Materials[SliderBackgroundMaterialIndex] != nullptr)
        {
            Object = NewObject(this);
            if (Object != NULL)
            {
                //Set up the HUD Object
                Object->Init(true, ButtonMaterials[SliderButtonIndex].Material, ButtonMaterials[SliderButtonIndex].HighLightVarName, ButtonMaterials[SliderButtonIndex].ClickVarName, Materials[SliderBackgroundMaterialIndex]);
            }//if
        }//if

        return Amount;
    }//if
    else
    {
        if (ThePC->IsInputKeyDown(EKeys::LeftMouseButton))
        {
            if ((Object->Hovered() 

 Object->CheckInsideSliderBG(pMousePos)) &amp;&amp; ThePC->WasInputKeyJustPressed(EKeys::LeftMouseButton))
            {
                Object->bGrabbed = true;
            }//if
        }//if
        else
        {
            if (Object->bGrabbed)
            {
                Object->bGrabbed = false;
            }//if
        }//else

        //Clamp the range just to be sure
        Amount = FMath::Clamp(Amount, MinAmount, MaxAmount);

        //Draw slider button
        return Object->DrawVerticalSlider(pHUDRef, Amount, MinAmount, MaxAmount, pMousePos, x, y, w, h, 1);
    }//else
    return Amount;
}//VerticalSlider

YourHUD.h

42 Lines

#pragma once

#include "GUI.h"
#include "YourHUD.generated.h"

UCLASS()
class AYourHUD : public AGUI
{
    GENERATED_UCLASS_BODY()

    public:

        //Objects we will be using to demonstrate each type of object
        UPROPERTY()
        UHUDObjects* TestLabel;
        UPROPERTY()
        UHUDObjects* TestTexture;
        UPROPERTY()
        UHUDObjects* TestMaterial;
        UPROPERTY()
        UHUDObjects* TestAnimMaterial;
        UPROPERTY()
        UHUDObjects* TestButton;
        UPROPERTY()
        UHUDObjects* TestAnimButton;
        UPROPERTY()
        UHUDObjects* TestHorizontalSlider;
        UPROPERTY()
        UHUDObjects* TestVerticalSlider;

        //Variables to hold for the sliders
        float horizontalSlideValue;
        float verticalSlideValue;

        //Variable to hold mouse position
        UPROPERTY()
        FVector2D MousePos;

    protected:
        //Draw HUD
        virtual void DrawHUD() OVERRIDE;
};

YourHUD.cpp

72 Lines

#include "YourGame.h"
#include "YourHUD.h"

//Constructor
AYourHUD::AYourHUD(const class FPostConstructInitializeProperties&amp; PCIP) : Super(PCIP)
{
    //Default the mouse positions
    MousePos.X = 0;
    MousePos.Y = 0;

    //Default the slider values
    horizontalSlideValue = 0;
    verticalSlideValue = 0;
}//Constructor

void AYourHUD::DrawHUD()
{
    //If the PC is NULL
    if (!ThePC)
    {
        //Try to get the PC
        ThePC = GetOwningPlayerController();

        //If there still isn't a PC, then return
        if (!ThePC) return;
    }//if

    //Check that the PC's input exists, otherwise, return
    if (!ThePC->PlayerInput) return; 

    //Draw HUD?
    if (NoHUD) return;

    //Super
    Super::DrawHUD();

    //No Canvas?
    if (!Canvas) return;

    //Grab the mouse position
    ThePC->GetMousePosition(MousePos.X, MousePos.Y);

    //This works by passing the object, this hud, the text, the index of the font array you want to use, the mouse position, then rectangle positioning, using scaling functions, and then the font size, scaled to the screen.
    Label(TestLabel, this, "This is a label!", 0, FLinearColor::White, CenterHorizontal(300), ScaleHeight(120), ScaleWidth(300), ScaleHeight(120), ScaleWidth(0.75f));

    //This works by passing the object, this hud, the index of the texture array you want to use, then rectangle positioning, and finally a tint colour
    Texture(TestTexture, this, 0, CenterHorizontal(300), ScaleHeight(240), ScaleWidth(300), ScaleHeight(120), FColor::White);

    //This works by passing the object, this hud, the index of the material array you want to use, the text, the index of the font array you want to use, rectangle positioning, and font/material scaling
    Material(TestMaterial, this, 0, "This is a material!", 0, FLinearColor::White, CenterHorizontal(300), ScaleHeight(360), ScaleWidth(300), ScaleHeight(120), ScaleWidth(0.75f));

    //This works by passing the object, this hud, the index of the animated material array you want to use, rectangle positions, and font/material scaling
    AnimatedMaterial(TestAnimMaterial, this, 0, CenterHorizontal(300), ScaleHeight(480), ScaleWidth(300), ScaleHeight(120), ScaleWidth(0.75f));

    //This works by passing the object, this hud, then index of the button material array you want to use, the text, the index of the font, the font colour, the mouse position, rectangle positioning and font/material scaling
    if(Button(TestButton, this, 0, "This is a button!", 0, FLinearColor::White, MousePos, CenterHorizontal(300), ScaleHeight(600), ScaleWidth(300), ScaleHeight(120), ScaleWidth(0.75f)))
    {
        //Stuff goes here for when button is clicked
    }//if

    //This works by passing the object, this hud, then index of the animated button material array you want to use, the text, the index of the font, the font colour, the mouse position, rectangle positioning and font/material scaling
    if(AnimatedButton(TestAnimButton, this, 0, "This is an animated button!", 0, FLinearColor::White, MousePos, CenterHorizontal(300), ScaleHeight(720), ScaleWidth(300), ScaleHeight(120), ScaleWidth(0.75f)))
    {
        //Stuff goes here for when button is clicked
    }//if

    //This works by passing the object, this hud, the index of the button for the slider, the index for the material for the background, rectangle positioning, the current value, the min value and the max value.
    horizontalSlideValue = HorizontalSlider(TestHorizontalSlider, this, 0, 0, MousePos, CenterHorizontal(300), ScaleHeight(840), ScaleWidth(300), ScaleHeight(7.5f), horizontalSlideValue, 0, 1);

    //This works by passing the object, this hud, the index of the button for the slider, the index for the material for the background, rectangle positioning, the current value, the min value and the max value.
    verticalSlideValue = HorizontalSlider(TestVerticalSlider, this, 0, 0, MousePos, CenterHorizontal(400), CenterVertical(300), ScaleWidth(7.5f), ScaleHeight(300), verticalSlideValue, 0, 1);  
}//DrawHUD

BluePrint/Editor End

Once you have compild your new project, make a new Class BluePrint of "YourHUD" and set the new BP to be your HUD System. Open the BluePrint and go into the defaults.

Text Section

Drop down the Text section, add an element to the Fonts array, and add in the font you created earlier. Any time the script asks for a 'Font Index', it's referring to the element number of this array. (On the left)

File:TextHUD.png
File:TextHUD.png

Buttons Section

Drop down the Button section, add an element to the Button Materials array, and add in the button material you created earlier. Set the Highlight and Click names to be the respective parameters in that material. Any time the script asks for a 'Button Index' or 'Slider Button Index', it's referring to the element number of this array. (On the left)

File:ButtonHUD.png
File:ButtonHUD.png

Textures Section

Drop down the Textures section, add an element to the Image Textures array, and add in the texture you want. Any time the script asks for a 'Texture Index', it's referring to the element number of this array. (On the left)

File:TextureHUD.png
File:TextureHUD.png

Materials Section

Drop down the Materials section, add an element to the Materials array, and add in the simple material you made earlier. Any time the script asks for a 'Material Index' or 'Slider Background Material Index', it's referring to the element number of this array. (On the left)

File:MaterialHUD.png
File:MaterialHUD.png

Animations Section

Drop down the Animations section, add an element to the Animation Materials array, and add in the simple or button material you created earlier. NOTE: This expects the textures of the material to be in a sprite sheet layout. If its a Button, then set the Highlight and Click names to be the respective parameters in that material. Any time the script asks for a 'Anim Button Index' or 'Anim Index', it's referring to the element number of this array. (On the left)

The 'Anim Col Rows' is how many sprites across the texture is, then how many down. Total anim tiles is how many tiles there are altogether, in case it doesn't go all the way to the end. The Frame Delay Seconds is how much time you want there to be between frame updates.

File:AnimationHUD.png
File:AnimationHUD.png

Conclusion

You can take this code and make whatever kind of HUD system you want. I never demonstrated it, but there are functions in the GUI class that can crop animated materials, so you can have an animated health bar thats cropped from the left, making it look like it's decreasing without cutting off at the right. 'CropXY(FVector2D)' and 'CropUV(FVector2D)'

You can also set up your own mouse system that doesn't use 'ThePC->GetMousePosition()' and implement a cool feature like gamepad control, etc.

-Peace

Hoodini Hoodini Bot Last updated on