I was tasked with creating a combo attack system in Unreal Engine 4 as part of my UE4-oriented independent study, and here are the steps I followed to do so:
Step 1: Setting Up Variables
Go into the
SideScrollerCharacter blueprint, and then go to its
Construction Script.
Create a float named
meleeHitboxOffset.
- Set it to
75 for now.
Create a float named
comboLength.Create a float named
hitboxDelay.
- Note: Not currently shown; set to
0.5.
Create a float named
hitboxDelayDefault.
Create a Boolean named
hitboxActive.
- Note: Not currently shown.
Create a float named
compassYaw.
- Note: Not currently shown.
In the variables list, click the “eye” next to
compassYaw,
meleeHitboxOffset,
comboLength,
hitboxActive, and
hitboxDelay to make them public.
Step 2: Setting Up Inputs
In the main UE4 window, navigate to: Edit > Project Settings > Engine > Input
Under Bindings, create and set the following key binding:
-
Attack, bound to the Left Mouse Button.
Optionally, you may alter the other key bindings as necessary.
For example, I differentiated between
MoveLeft and
MoveRight, unlike the default.
Step 3: Creating the Hitbox Actor
In the Content Browser, navigate to: Content > SidescrollerBP > Blueprints.
Right-click, and then create a new Blueprint Class.
Name this new class
PlayerMeleeHitbox.
Now, open up
PlayerMeleeHitbox in the Blueprint Editor.
Add a
Cube static mesh component to it, and then a
Box collision component.
Move both to 0x, 0y, 0z if they aren’t already there.
- Their scale will need to be fiddled with, but ideally the
Box collision will be just barely bigger than the static mesh.
Later, the static mesh will be removed, but it serves as a visualization for now.
Make sure that the
Cube static mesh has no collision at all, and that the
Box collision overlaps all dynamic objects.
Step 4: Adding an Input Check
First, create a function for
SideScrollerCharacter called
Melee Attack.
In
SideScrollerCharacter’s
Event Graph, add an
InputAction Attack node, and then have it run
Melee Attack.
Step 5a: The Melee Attack Function
The
Melee Attack function will house quite a bit of code, the first of which being a series of
Branch nodes to check if you can attack.
Of the ones you see, the relevant ones are:
A
Branch checking how long
comboLength is.
- Only continue if less than or equal to
2.
A
Branch checking if
hitboxActive is true.
- Only continue if false.
Step 5b: The Melee Attack Function (cont.d)
Next, set
hitboxDelay to
hitboxDelayDefault, or
0.5.
Get a reference to
Self,
GetActorRotation from it,
Break the resulting
Rotator, and then set
compassYaw to the rotator’s
Z.
Split the path into two separate paths using a
Sequence.
Meanwhile, before continuing,
Get compassYaw and then plug it into two
inRange (float)’s. In the first, check between
-90 to -0.1, and in the second check between
0.1 to 90.
Step 5c: The Melee Attack Function (cont.d)
Add a
Branch to each path of the
Sequence you just made, and plug the
-90 to -0.1 inRange into the first one and the
0.1 to 90 inRange into the second.
Below,
GetActorLocation of the
SideScrollerCharacter, and then
Break the
Vector.
First,
subtract the resulting
Y-value by
meleeHitboxOffset, or
75. After that,
Make the new
Y-value along with the old
X and
Z into a new
Vector.
Next,
add the old
Y-value to
meleeHitboxOffset, or
75.
Make another
Vector just like before.
Plug these new vectors into their own
Make Transform nodes.
For the
True path of the aforementioned
Branches, make a
SpawnActor Player Melee Hitbox node and plug the
FIRST Make Transform into it. Do the same for the
SECOND Make Transform.
Step 6: Creating an Enemy
Before we get into the proper melee hitbox, we are going to need an enemy to hit with it.
Do what you did before with making
PlayerMeleeHitbox, step for step, but this time call it
Enemy.
In
Enemy’s
Construction Script, make a
PUBLIC float called
enemyHealth, and set it to
10.
In
Enemy’s
Event Graph, drag off of
Event Tick and make a
Branch. Have it check for when
enemyHealth is
Less Than or Equal To 0. When this is
True,
Print a
String before
Destroying the
Actor.
Step 7a: The PlayerMeleeHitbox BP
Create the following functions for
PlayerMeleeHitbox:
-
Toggle Hitbox Variables.
-
Check Combo Length.
In
PlayerMeleeHitbox’s
Construction Script, run
Toggle Hitbox Variables first, and then
Check Combo Length.
In
Toggle Hitbox Variables,
Cast to SideScrollerCharacter (after using
Get Player Character), and then set
Hitbox Active to
true.
Step 7b: The PlayerMeleeHitbox BP (cont.d)
In
PlayerMeleeHitbox’s
Event Graph, drag off of
Event Tick and
Cast to SideScrollerCharacter. Plug
Get Player Character into this.
Off of the cast,
Get hitboxDelay and plug it into a
Less Than or Equals with the other value being
0.
Plug the result into a
Branch that, if
True, does the following:
Set hitboxActive to
False, runs
Check Combo Length, and then
Destroys the
Actor.
Step 7c: The PlayerMeleeHitbox BP (cont.d)
Now is where things start getting a little complicated.
In
PlayerMeleeHitbox’s
Check Combo Length function,
Cast to SideScrollerCharacter and then
Get hitboxActive from it. Plug it into a
Branch, and, while you’re at it,
Get comboLength.
For the next two sub-steps, remember that every
Get or
Set comboLength must be linked back to
Cast to SideScrollerCharacter.
Step 7d: The PlayerMeleeHitbox BP (cont.d)
First, we are going to increment
comboLength from 0 to 1, 1 to 2, and 2 to 3.
Dragging off of the earlier
Branch’s
True path, nest a series of three more
Branches.
Below the first
Branch, plug the earlier
Get comboLength into a
Nearly Equal (float) node as the A value. For the B value, enter
2.0. Plug this into the first
Branch. If it is
true,
Set comboLength to
3.
If the first
Branch was
false, do the same as above but enter
1.0 as the B value. If this is
true,
Set comboLength to
2.
If the second
Branch was
false, do the same as above but enter
0.0 as the B value. If this is
true,
Set comboLength to
1.
For debugging purposes, also have each of these
Print comboLength as a
String.
Step 7e: The PlayerMeleeHitbox BP (cont.d)
Next, we are going to decrement
comboLength from 1 to 0, 2 to 1, and 3 to 2.
Dragging off of the earlier
Branch’s
False path, nest a series of three more
Branches.
Below the first
Branch, plug the earlier
Get comboLength into a
Nearly Equal (float) node as the A value. For the B value, enter
1.0. Plug this into the first
Branch. If it is
true,
Set comboLength to
0.
If the first
Branch was
false, do the same as above but enter
2.0 as the B value. If this is
true,
Set comboLength to
1.
If the second
Branch was
false, do the same as above but enter
3.0 as the B value. If this is
true,
Set comboLength to
2.
For debugging purposes, also have each of these
Print comboLength as a
String.
Step 7f: The PlayerMeleeHitbox BP (cont.d)
Going back to
PlayerMeleeHitbox’s
Event Graph, we are going to have the hitbox detect an overlap with any
Enemy actor.
Create an
OnComponent Begin Overlap node, and
Cast to Enemy from it using the
Other Actor pin as its
Object reference. Immediately afterwards,
Cast to SideScrollerCharacter and pin the
GetPlayerCharacter node from earlier to it.
From
SideScrollerCharacter,
Get comboLength and plug it into three separate
Nearly Equal (float) nodes as the A value. For the B value, input
1,
2, and
3 respectively.
Step 7g: The PlayerMeleeHitbox BP (cont.d)
Off of the main path, create a nest of three
Branches, plugging the uppermost
Nearly Equals node into the uppermost
Branch and so on for the others.
For each, if
True,
Print a
String and then:
- If
comboLength equaled
1,
Set enemyHealth to
enemyHealth minus 1.
- If
comboLength equaled
2,
Set enemyHealth to
enemyHealth minus 2.
- If
comboLength equaled
3,
Set enemyHealth to
enemyHealth minus 3.
Step 7h: The PlayerMeleeHitbox BP (cont.d)
Finally, have all of the three sub-paths converge back into a
Set hitboxActive node, setting the Boolean to
False.
After that,
Destroy the
Actor.
Step 8: Revisiting SideScrollerCharacter
We are almost finished with the blueprints; just a little more!
In
SideScrollerCharacter’s
Event Graph, drag off of
Event Tick and make a
Branch. Plug into it a
Less Than or Equals To, and then compare
hitboxDelay and
0.
If
True,
Set hitboxDelay to
0 and
Set comboLength to
0.
If
False,
Set hitboxDelay to
hitboxDelay minus Delta Seconds, a pin dragged off of
Event Tick.
Step 9: Setting Up Your Scene
At last, place a couple
Enemy actors into your scene, and then play.
If everything works as intended, you will make a hitbox in the direction you are facing (either left or right).
With this setup, you will only be able to swing once… but if you hit an enemy, you will be able to swing up to three times!
Once the enemy is hit with two full combo attacks or a mixture of hits, they will be destroyed.
Of course, there are several ways to improve it from here:
- Making it so you can’t move while in the middle of a combo.
- Tweaking the position and size of the hitbox.
- Adding alternate hitboxes for mid-air attacks.
- Making the hitboxes move along with the player.
Bonus: A Brief Look into the Importance of Combat
The Importance of Combat
- First and foremost, combat makes a game more
engaging.
- Games can and have pulled off combat-less experiences well, but several genres are practically built around the concept.
- Other times, combat adds to the overall experience like spice would a well-prepared meal.
- As game designers, it is our job to make the player
feel emotions, and combat in particular should
excite them.
- To give you an idea, I have a couple examples of good video games with equally good and engaging combat systems.
Example: Dark Souls
- Dark Souls’s combat system requires the player to make smart plays and punishes them severely for mistiming risky techniques like parrying.
- One of the core mechanics of the game, healing yourself with your Estus Flask, also leaves the player helpless for several precious seconds.
- In terms of “combo attacks” in particular, each weapon family features similar strings of light and heavy attacks.
- For example, a dagger will have a string of very fast, low-damaging slashes, while the zweihander features slow, wide-arcing slices that easily stagger opponents.
Example: Ori and the Blind Forest
- Unlike Dark Souls, Ori and the Blind Forest’s combat takes on a somewhat lesser focus, the game instead intermixing it with platforming.
- Aside from a couple purely offensive skills like the standard homing spark, many abilities are just as effective in fighting enemies as they are in maneuvering around the environment.
- A strong aerial ground-slam can smash through weak floors and armored enemies alike. A grenade-like ball of light can be used to hit distant enemies or be bashed off of to travel a fair distance.
- The bashing mechanic in particular. Redirecting enemy fire, using the enemies themselves to dodge, hurling enemies into hazards…