Menu – Armory – Part 2: Weapon Upgrades

In this tutorial I will focus on creating upgrade for my weapons.

  • Possibility to change each weapon variable,
  • Draw everything on 3d UMG widget,
  • Explore weapons as 3d models,

Creating upgrade functionality is easy but it’s taking lot of time.

In this tutorial I wont:

  • Implement save / load system,
  • Implement currency. There will be cost but It won’t be decreasing or checking if we have enough money to upgrade,

Creating base UMG

Create new UMG Widget named UI_Armory_Weapons. For now let’s add necessary variables and dispatchers.

Add new dispatchers:

  • OnNextWeapon,
  • OnPreviousWeapon,

And one new variable CurrentWeapon – extending from BP_BaseWeapon.

Add two buttons: Button_Previous and Button_Next.

twobuttons

At this stage you will have only those two buttons. Make sure your anchor is in center and you have Position Y the same as I have. What you could do also is to add image (with Center Anchor) like mine:

umgframe

So you will know if your UI is fully rendered in 3d. Add OnClicked events to buttons and call dispatchers:

calldispatchers

Actor placed in world will bind to those dispatchers. Before leaving UMG create new custom event named UpdateWeapon with two inputs:

  • CurrentWeapon (BP_BaseWeapon),
  • CurrentIndex(int),

updateweapon

We will be calling this from actor placed in world.

Updating Base Weapon

This will take lot of time because I need to add lot of new variables. This part would be so much easy in C++ 🙂 You won’t be getting any results soon but I will move from one upgrade to another. Let’s start with 3D weapon.

Open BP_BaseWeapon and add those variables:

  • UI_Pivot (Vector). I would like to have possibility to move the weapon in 3D,
  • UI_Scale (Vector). The same thing but with scale,

Creating rotating weapons

Create new blueprint extending from Actor named UI_Weapons. Open it.

Add new Scene component named WeaponsRoot. Set Scale to 2. Add new Widget Component named Widget:

  • Location: (X=180.864090,Y=-4.912077,Z=51.413330)
  • Rotation: (Pitch=0.000027,Yaw=29.999952,Roll=99.999809)
  • Scale: (X=0.450000,Y=0.450000,Z=0.450000)
  • Class: UI_Armory_Weapons,

You should see your buttons in components view.

Now in event graph create new variables:

  • Weapons (BP_BaseWeapon Array),
  • DeltaTime (float),
  • CurrentWeaponIndex (int),

Create new custom events:

HideAllWeapons. This will make sure all weapons in array are hidden:

hideallweapons

Rotate. As you can see this is adding rotation to WeaponsRoot scene component.

rotate

ActivateUI. This is making sure we will have mouse and be able to click on UI.

activateui

ShowCurrentWeapon. Make sure we are only showing current weapon. Update UMG about new current weapon.

ShowCurrentWeapon

SpawnAllWeapons. This event will spawn all weapons from GameInstance array.

spawnallweapons

NextWeapon and PreviousWeapon. Update CurrentWeaponIndex and call ShowWeapon.

nextandprev

BindEvents. Just bind dispatchers from our UI. Thanks to this we have communication with UMG and this actor. As you can see each time someone will tap Next Button we will call Next Weapon function in this Actor.

bindevents

BeginPlay and Tick.

beginplayandtick

So basically what this is doing:

  • Spawn all weapons in WeaponRoot location,
  • Attach them to Weapon Root component,
  • Hide them all,
  • Show current weapon (at start this mean weapon in index 0),
  • Make sure we have mouse visible,
  • Bind Events,
  • Always rotate WeaponRoot component,

You could place this actor on your level near camera and test it out – your 3D meshes should change after tapping on buttons in UMG.

Updating Base Weapon – Ammo In Mag

First let’s move with Ammo In Mag upgrade.

Open BP_BaseWeapon and add those variables:

  • UP_MinAmmoInMag (int, 0),
  • UP_MaxAmmoInMag (int, 6),
  • UP_MaxAmmoInMag_Levels (int, 6),
  • UP_MaxAmmoInMag_Cost (int, 50),

And those functions:

SetCurrentAmmoInMag (with one int input)

setcurrentammoinmag

And GetAmmoInMagCost (pure, one int output)

getammoinmagcost

This is how I’m calculating cost – it will be used for all upgrades. What you could do is to change Exp in Power or overwrite this function in specific weapon. So basically each time you upgrade ammo in mag cost will increase.

UMG – Displaying Ammo In Mag

Open UI_Amory_Weapons. I won’t be showing you how to create UMG from scratch. Will try to trigger modular creation.

As you can see in screens there are 8 variables that I’m upgrading. What you could do is to create just ONE widget then copy 8 times.

Here’s the video presenting Horizontal Box used for each upgrade:

You can copy it 8 times and change variables names. For Ammo In Mag I have used those names:

  • ProgressBar: ProgressBar_AmmoInMag,
  • Text inside progress bar: TextBlock_AmmoInMag,
  • Text representing cost: TextBlock_AmmoInMag_Cost,
  • Button for upgrade: Button_AddAmmoInMag,

Now in event graph create new Graph named Update_AmmoInMag then add new Custom Event named Upd_AmmoInMag:

UpdAmmoInMag

This basically is updating all widgets. Rest upgrades will use almost the same event but with different variables.

Go back to main Event Graph and create new Custom Event named UpdateAllData:

UpdateAlldata

You don’t have Weapon Name Text and Ammo Type Text – just create those two (remember about Anchor Center)

Now in UpdateWeapon function just call UpdateAllData:

updateweapon_update

Again you won’t have Text Block Index, create one. Last thing is to add OnClicked event to upgrade button:

addammoinmag

At this point you should be able to see how many bullets each weapon have in mag and you can upgrade it. Be sure to properly set UP_* variables in weapons extending from BP_BaseWeapon. For example my pistol have:

  • UP_MinAmmoInMag: 6,
  • UP_MaxAmmoInMag: 12,
  • UP_MaxAmmoInMag_Levels: 12, (which means after upgrade we will get 1 more bullet – MaxAmmoInMax / Levels)

Run the game and check if you are able to upgrade ammo in mag. If not – try to debug it by placing print strings. Try to search where is the problem.

Updating Base Weapon – Ammo In Backpack

Basically this will be exactly the same as ammo in mag. Open BP_BaseWeapon and add those variables:

  • UP_MinAmmoInBackpack (int, 30),
  • UP_MaxAmmoInBackpack (int, 100),
  • UP_MaxAmmoInBackpack_Levels (int, 10)
  • UP_MaxAmmoInBackpack_Cost (int, 50)

Add new functions:

SetCurrentAmmoInBackpack

setcurrentammoinbackpack

GetAmmoInBackpackCost (pure, one int output)

getammoinbackpackcost

UMG – Displaying Ammo In Backpack

Open UI_Amory_Weapons and copy/paste HorizontalBox. Here are my variables names (which you could see in video presenting the hierarchy):

  • ProgressBar: ProgressBar_AmmoInBackpack,
  • Text inside progress bar: TextBlock_AmmoInBackpack,
  • Text representing cost: TextBlock_AmmoInBackpack_Cost,
  • Button for upgrade: Button_AddAmmoInBackpack,

Create new Graph named Update_AmmoInBackpack. Then add new custom event named Upd_AmmoInBackpack:

upd_ammoinbackpack

This is identical as Upd_AmmoInMag just with different (highlighted) variables.

Go to UpdateAllData function and call this event.

updatealldata_updammo

Create new OnClick event on the button:

addammoinbackpack

That’s all – you can now upgrade Ammo In Backpack. Be sure to properly set UP_* variables in weapons extending from BP_BaseWeapon. For example my pistol:

  • UP_MinAmmoInBackpack: 30,
  • UP_MaxAmmoInBackpack: 100,
  • UP_MaxAmmoInBackpack_Levels: 10

Updating Base Weapon – Reload Time

Open BP_BaseWeapon and add those variables:

  • UP_MinReloadTime (float, 2),
  • UP_MaxReloadTime (float, 1),
  • UP_ReloadTimeToAdd (float, -0.1 (yes, minus) )
  • UP_ReloadTime_Cost (int, 50),

Now add new functions:

SetReloadTime (one float input)

setreloadtime

GetReloadTimeCost (pure, one int output)

getreloadtimecost

UMG – Displaying Reload Time

Open UI_Amory_Weapons and copy/paste HorizontalBox. Here are my variables names:

  • ProgressBar: ProgressBar_ReloadTime,
  • Text inside progress bar: TextBlock_ReloadTime,
  • Text representing cost: TextBlock_ReloadTime_Cost,
  • Button for upgrade: Button_AddReloadTime,

Create new Graph named Update_ReloadTime. Then add new custom event named Upd_ReloadTime:

upd_reloadtime

Go to UpdateAllData function and call this event.

updatealldata_updreloadtime

And add new OnClicked event on the button:

addreloadtime

At this stage you should be able to upgrade your reload time. Make sure you properly set the UP_* variables in weapons extending from BP_BaseWeapon. For example my pistol:

  • UP_MinReloadTime: 2,
  • UP_MaxReloadTime: 0.5,
  • UP_ReloadTimeToAdd: -0.1,

Updating Base Weapon – Damage Modifier

Open BP_BaseWeapon and add those variables:

  • UP_MinDamageModifier (float, 1),
  • UP_MaxDamageModifier (float, 2),
  • UP_DamageModifierToAdd (float, 0,1),
  • UP_DamageModifier_Cost (int, 50),

And three new functions:

UpgradeDamageModifier. This time we will call this function from UMG instead doing math in UMG.

upgradedamagemodifier

GetDamageModifierCost (pure, one int output)

getdamagemodifiercost

UMG – Displaying Damage

Open UI_Amory_Weapons and copy/paste HorizontalBox. Here are my variables names:

  • ProgressBar: ProgressBar_Damage,
  • Text inside progress bar: TextBlock_Damage,
  • Text representing cost: TextBlock_Damage_Cost,
  • Button for upgrade: Button_AddDamage,

Create new Graph named Update_Damage. Then add new custom event named Upd_Damage:

upd_damage

Call this event in UpdateAllData and add OnClicked event on the button:

adddamage

And you can upgrade weapon damage modifiers. My pistol variables:

  • UP_MinDamageModifier: 1,
  • UP_MaxDamageModifier: 2,
  • UP_DamageModifierToAdd: 0.1,

Updating Base Weapon – Crit Modifier

This will be exactly the same as damage modifier but with different variables. Try to do it by yourself without my help.

UMG – Displaying Crit

The same as above – try to create it by yourself.

Updating Base Weapon – Accuracy

Open BP_BaseWeapon and add those variables:

  • UP_MinSpread (float, 0.4),
  • UP_MaxSpread (float, 0.01),
  • UP_SpreadToAdd (float, -0.05),
  • UP_SpreadCost (int, 50),

And add those functions:

UpgradeSpread

upgradespread

As you can see I’m adding couple of variables and making sure they won’t go outside clamp values.

GetSpreadCost (pure, one int output)

getspreadcost

UMG – Displaying Accuracy

Open UI_Amory_Weapons and copy/paste HorizontalBox. Here are my variables names:

  • ProgressBar: ProgressBar_Spread,
  • Text inside progress bar: TextBlock_Spread,
  • Text representing cost: TextBlock_SpreadCost,
  • Button for upgrade: Button_AddSpread,

Create new Graph named Update_Spread. Then add new custom event named Upd_Spread:

upd_spread

Call this event in UpdateAllData and add OnClicked event on the button:

addspread

And now you can upgrade accuracy.

Updating Base Weapon – Rifle Fire Rate

This is different because not all weapons have Rifle Fire Rate used. Open BP_BaseWeapon and set RifleFireRate to 0 instead of 1, then add those variables:

  • UP_MinFireRate (float, 0.2),
  • UP_MaxFireRate (float, 0.05),
  • UP_FireRateToAdd (float, -0.01),
  • UP_FireRate_Cost (int, 50),

And add those functions:

UpgradeFireRate

upgradefirerate

GetFireRateCost (pure, one int output)

getfireratecost

UMG – Displaying Rifle Fire Rate

Open UI_Amory_Weapons and copy/paste HorizontalBox (make sure HorizontalBox is a variable!). Here are my variables names:

  • ProgressBar: ProgressBar_FireRate,
  • Text inside progress bar: TextBlock_FireRate,
  • Text representing cost: TextBlock_FireRate_Cost,
  • Button for upgrade: Button_AddFireRate,

Create new Graph named Update_FireRate. Then add new custom event named Upd_FireRate. If RifleFireRate is 0 I’m hiding whole horizontal box.

upd_firerate

Call this event in UpdateAllData and add OnClicked event on the button:

addfirerate

Updating Base Weapon – Burst

Burst is used mostly in shotguns, but I will add possibility to increase it in other weapons as well. Open BP_BaseWeapon and add those variables:

  • UP_MinBurstCount (int, 1),
  • UP_MaxBurstCount (int, 1),
  • UP_BurstToAdd (int, 1),
  • UP_Burst_Cost (int, 50),

And add functions:

UpgradeBurst:

upgradeburst

GetBurstCost (pure, one int output)

getburstcost

UMG – Displaying Burst

Open UI_Amory_Weapons and copy/paste HorizontalBox. Here are my variables names:

  • ProgressBar: ProgressBar_Burst,
  • Text inside progress bar: TextBlock_Burst,
  • Text representing cost: TextBlock_BurstCost,
  • Button for upgrade: Button_AddBurst,

Create new Graph named Update_Burst. Then add new custom event named Upd_Burst:

upd_burst

Call this event in UpdateAllData and add OnClicked event on the button:

addburst

Now you can upgrade all 8 variables!

Updating Base Weapon – Unlocking Weapons

Open BP_BaseWeapon and add two variables:

  • isUnlocked (bool),
  • UP_WeaponCost (int, 5000),

And one SetIsUnlocked function:

setisunlocked

UMG – Unlocking

Open UI_Amory_Weapons create:

  • Button named: Button_BuyWeapon,
  • Text named: TextBlock_WeaponCost,
  • Image named: Image_HidePicture,

Go to Event Graph and create new custom event named CheckWeaponLock:

checkweaponlock

Call this event in the end of UpdateAllData. Create OnClicked event on button:

buyweapon

And that’s it! You should get good starting point to work with visuals and other upgrades mechanics. As you saw – lot’s of copying, lot’s of variables – easy but really time-consuming. As always – take your time!

Final Result

Creating ShooterTutorial takes a lot of my free time.
Buy Now Button
If you want you can help me out! I will use your donation to buy better assets packs and you will be added to Credits /Backers page as well.

Implementing game is taking time but writing about it is taking much more effort!

5 Replies to “Menu – Armory – Part 2: Weapon Upgrades”

  1. BaseWeapon meshes are not visible. I cant see it. the UI_Weapons actor is in the scene and I can see the umg but when pressing buttons nothing is changing

  2. Say I were making a game where you could have multiple of the same kind of weapon, would this system as is handle each separately? For instance, would I be able to have one pistol with max damage, one with max fire rate, and one that’s completely unmodified?

  3. Hey Tom, in some versions of the Editor this 3d version of the menu widget won’t work. In 4.10 I had to set it to “ScreenSpace” in the UI_Weapons blueprint to be able to interact with it. Based on some googling, 3d menus like the ones illustrated here broke at some point, and I’m not sure they’ll be fixed anytime soon.

    When you get that far, you’ll notice that nothing happens when you press the buttons. First, make sure WeaponsRoot is definitely in the camera view by attaching a mesh to it within the blueprint, and – also from within the blueprint – positioning it manually where you want it. So you’re moving it around in the blueprint viewport to place it correctly in your scene (alternatively, you could reposition your widget and leave the WeaponsRoot at the center of your blueprint so you can drag UI_Weapons directly to where you want the weapons to show up).

    Next, select each of your weapons and ensure UI Scale variable is not zero. I had to set mine to 25, but I’m using all my own models, your value will vary.

Leave a Reply