Show C++ Variable Value in UI Widget

Hi All.

Working on a small prototype shooter, mainly to learn C++.
Created a small ammo/reload function which seems to work as intended (for now).

The issue im having is that when i try to expose the number of bullets in the chamber, it shows as 0.
This is the variable i want to expose to the UI:


UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "weapon"
int32 CurrentChamberAmmo;


Ive set CurrentChamerAmmo to 30 in the constructor

this is the Event Graph in my UI where it gets a reference to the currently equipped weapon:

And this is where i try to expose it to the screen itself:


However this just displays 0, when it should actually display 30.

Any ideas where ive gone wrong?

Thanks!

You might want to put a Print String hanging off the Cast Failed just to see if the widget is initializing faster than the Character and thus leaving the CurrentWeapon invalid. I would think you’d see a blueprint log error, but it’s worth a shot.

Did that but doesnt come up with any errors or strings being printed.
I believe the current weapon is valid as im able to shoot. I can see the ammo value decreasing in the log too but cant get it displaying in the UI for some reason.

@Ts91 Where are you creating the UI? I am asking because I am wondering if the widget is being created before the weapon… thou the weapon reference could be invalid, there is a chance that instead of having an error, the conversion from int to text is returning always 0. To be sure, you could include a check IsValid for the Current Weapon before returning the value, this would avoid an error anyway, and if it is not valid, insert another print.

Mostly a bit more detail than what actually eagletree explained.

I must admit I don’t have experience doing what you are doing. I extend UUserWidget and place variables in there that I want my Character and Controller to access. I make my HUD widget a child of the extended UUserWidget and then it has access to the variables I want it to have. I use a pointer from the CreateWidget to poke those values into it. That way in my firing routine, just save the value at that time and fires an event to update the value. You can do a blueprintImplementable event in the extended widget class to force the widget to update the value and then don’t even need to have a bind on the widget.

I may not understand what you are doing. I am assuming it’s a Character that is doing the firing and management of the weapon and ammo, and the widget is just reporting the values in the HUD.

@eagletree those bindings might bring performance issues if you just have too many of them. The way you do is what I do aswel. Painless.

Youre correct that the character is firing but its calling the method from the weapon class, as i plan to have multiple weapons with different firing mechanics.

So the widget BP is being initialised in my Player Character BP on begin play (As Below)

The weapon is being initialised in the Character C++ file in the begin play method(As Below)


// Spawn Weapon
    FActorSpawnParameters SpawnParams;
    SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
    CurrentWeapon = GetWorld()->SpawnActor<ATPSWeapon>(StarterWeapon, FVector::ZeroVector, FRotator::ZeroRotator, SpawnParams);
    if (CurrentWeapon)
    {
        CurrentWeapon->SetOwner(this);
        CurrentWeapon->AttachToComponent(GetMesh(), FAttachmentTransformRules::SnapToTargetNotIncludingScale, WeaponSocketName);
    }

The Weapon Ammo etc is all part of the Weapon C++ file (as below)



    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon")
    int32 TotalAmmo;

    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon")
    int32 MaxChamberAmmo;

    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon")
    int32 CurrentChamberAmmo;

Its a little confusing.

EDIT
Okay so i added an IsValid call in the UI Constructor:


And for some reason its printing out “CharacterWeapon Invalid” No idea why though as im able to shoot

At the C++ Begin Play code, you need to call Super::BeginPlay(); after the code for the spawn weapon, otherwise the blueprint nodes will be called before the weapon being set. also in the last pic, you forgot to set the value for current weapon.

I do have Super::BeginPlay() in the Begin Play Method, i just didnt copy it into the previous post.

In terms of the last picture. Im just getting a reference to the current weapon which is the weapon BP called (Base Weapon BP - for testing purposes).
im then calling the ammo count in the GetText graph:

The order which you call Super::BeginPlay() does matter, it has to be called after the attibution:

CurrentWeapon = GetWorld()->SpawnActor<ATPSWeapon>(StarterWeapon, FVector::ZeroVector, FRotator::ZeroRotator, SpawnParams);

Otherwise the widget is created and there is no CurrentWeapon set yet.

Okay i changed the order, put Super::BeginPlay() after the current weapon assignment.
Still not working.

Now im also getting the following error in my message log:


But im going to assume thats because it shows the CurrentWeapon as invalid?

Yes, this is the reason.

You will need to change the logic a bit behind the UI. Usually the UI is created by the game mode. Try to let the UI the most dummy you can, meaning you don’t know anything about other classes and even having references to other classes on it. Other classes can have access to you UI by just getting the current game mode and from there via the UI reference set any variable which represents fields of info. This makes the UI reusable and a good practice aswel.

Sorry you confused me a little. Not sure what you mean exactly.

You can create your own Game Mode blueprint and use it on your project instead of the default ones, you just use the defaults as a base (inheritance). The game mode is one of the objects present at all times. You can create your UI inside the Game Mode blueprint instead of your Character blueprint and it is the recommended practice doing so.

Do not store a reference to the weapon inside the UI, but let a variable called ChamberAmmo be there and use it to show the value.

Inside your Character Blueprint (or any other place) right after you have created CurrentWeapon, you can use GetGameMode() return and cast to the class you have used for Game Mode and use it to access the UI reference and then set its ChamberAmmo with CurrentWeapon->CurrentChamberAmmo, this will automatically refresh the UI.

Created my own Game Mode BP and did the whole “Add to Viewport” in that BP.
The bit im not confused on is the quoted above. Not exactly sure how id get a CurrentChamberAmmo variable without actually referencing the current weapon in the UI graph.
Or how id use GetGameMode in the C++ class.

Give me some time and I will make a small video to show. It is way easier showing than writing here.

Okay no problem!

Follow a short video and a project link for you to check: project link

I recommend a creation of a small set of functions to easily help you set and retrieve the values from Widget, so many things here you don’t need to repeat while coding. The importance on using GameMode as for managing when and how values are updated is important and also GameInstance as I have explained in the video.

The Udemy.com course I have mentioned and which is so cheap for the actual content, is this one: course link

2 Likes

Thank you very much for the video! really appreciate it.
Ill have a look as soon as im home.

I do have the above udemy course and am following it which is why im surprised that im having this issue as the content is really good.

Hello NilsonLima,

Thank you very much for your video. I have a similar project where my character collects cones in the arena instead of shooting. I am just trying to figure
out how I can update the widget counter to actually count the cones I collected.

Best regards, Peter