In this tutorial I will implement score system which:
- Should be intuitive for player,
- Will reward players with good accuracy,
- Will reward players who play fast,
It won’t be so hard so let’s go!
<strong>This Tutorial has been created using Unreal Engine 4.8.2</strong>.
Make sure you are working on the same version of the engine.
First of all some theory. I think that the best way for calculating score here is to take which body part was hit and calculate points added to score using multiplier.
This will look like this:
BasePointValue * BodyPartHit. For example: 10 * Head = 20 or 10 * Leg = 5
To add more “gameplay” element to score it should have some sort of combo system. The idea here is:
- Every time we hit an enemy combo bar will increase,
- Combo bar is decreasing over time,
- Each time combo bar will be full player will get next combo level. Combo bar will reset,
- If our accuracy is bad (we haven’t hit anything) combo level will go back to 1,
- Combo level will be used as multiplier for points,
So here’s how it should look in theory: BasePointValue * ComboLevel * BodyPartHit.
Thanks to this player will need to aim and will get more points if shooting fast. Sounds good enough.
Implementing score and combo
We will use GameState class for this. You should have GameplayGameState ( UE4 classes explanation) and assigned to your level.
Open it and add those variables:
- CurrentPoints (float),
- CurrentComboLevel (int, default: 1),
- BasePointsToAdd (float, default: 15) this means each time we hit we will add 15 points as a base,
- ComboBarDecreasingSpeed (float, default: 0.1),
- ComboBarIncreasingValue (float, default: 0.35) – the base value for how much we will add to combo bar when hit an enemy,
- DeltaTime (float),
- isDecreasingComboBar (bool, default: true) this will be used later when I will have gameplay phases implemented,
- CurrentComboBarValue, (float),
- MissDecreaseValue (float, default: 0.25) – how much combo bar should decrease if we miss,
Then add those event dispatchers:
- ComboLevelIncreased (with one input: CurrentComboLevel int),
- ComboLevelDecreased (with one input: CurrentComboLevel int),
Now it’s time for new functions.
IncreaseComboBar function with one input Hit Result:
This function is responsible for managing combo bar, combo level and adding points. Earlier theory is implemented here.
It’s straightforward – decreasing Combo Bar Value and call Miss dispatcher.
Now go to your Event Graph and add Tick event with UpdateComboBar custom event.
This is making sure combo bar is decreasing over time and manage combo level.
That’s all in GameState – make sure this game state is connected with your level!
UMG will show us the combo bar, combo level and current points. I’m using K-Spree GUI, you can read the implementation here.
Create new widget named HUD_Points. Try to recreate this hierarchy:
Now bindings. Select ProgressBar and bind a function to Percent.
Just getting the CurrentComboBarValue and passing it to ProgressBar percent.
Select TextBlock_Points and create binding for the Text.
You could manage points by using dispatchers as well because we know when we will hit, but I’m not sure when points will be added later on that’s why binding is safer.
Now go to your event graph and bind gamestate dispatchers:
We will play feedback animations on UMG and update ComboLevel text thanks to those dispatchers.
That’s all in UMG.
Adding UMG to player
Open GameplayCharacter and add new Widget Component named HUD_Poinst. It need to be attached as the rest UMG Widget.
- Location :(X=-7.986703,Y=-27.562475,Z=35.536598)
- Rotation: (Pitch=-12.431763,Yaw=60.849777,Roll=85.633919)
- Scale: (X=0.034050,Y=0.034050,Z=0.034050)
- Widget Class: HUD_Points,
- Draw Size: 500 x 200,
- Pivot: 0, 0,
- Collision Presets: No Collision,
Using score and combo
Now we need to start using this system. Open BP_BaseWeapon and add two new variables:
- HitActorsResults (Hit Result ARRAY),
- NumberOfHitEnemies (int),
Get Best Hit Result (input: Results, HitResult ARRAY) with two local variables:
- CurrentBestHitResult (Hit Result),
- CurrentBestValue (float),
Why we need this function? Imagine that you are shooting using Shotgun – one bullet hit an head an one bullet hit leg, which bullet should be taken for points and combo system? This function will return the best hit result.
New function: Calculate Points
This function is responsible for letting GameState know if should increase combo bar or decrease it.
Now we need to drive HitActorResults array variable and those functions. The best place for this is Fire function. It need to be updated.
I will try to explain. Before we do damage we are calculating the points, that’s because we are checking isDead variable. If were calculating points after AddDamage player won’t be getting points when killing an enemy.
Each time we shoot we are adding HitResult to HitActorResults array and in the end of Burst Count Loop we are iterating points over one of them and deal damage to all of them.
The last thing to do is to update BP_BaseProjectile to update the score and combo as well.
Go to OnProjectileStop function and add a sequence:
We are done but there will be couple of things to do later:
- Hi score should be saved in levels, not in GameplayGameState,
- Basically without level system we can’t create “new hi-score” and leaderboards functionalities yet. This will be done later,
- We could add another multiplier for score – player level. This will reward active players,
Implementing game is taking time but writing about it is taking much more effort!