Making a 3D side-scroller game in UE4

Introduction

Let’s start summing up what we did in the previous tutorial. We started our series with a general introduction to Unreal Engine 4 through a project which explores some of the basic concepts of the engine. We saw the framework’s class hierarchy, the visual scripting, the character animation settings, and we defined a fixed camera as a temporary solution in our game, among other things. If you haven’t already read the previous tutorial, I strongly suggest you do before continuing with this one.

In this tutorial, we will create the base to our 3D side-scroller game’s style. Currently my team and I are working on an automatic Runner, 2D side-scroller for IOS and Android. You can follow us on our Facebook page to keep up with our work in progress and to know when it will release. If you like this kind of game, I can assure you that you will love ours ;).

As I already said, in this tutorial we will configure our game camera to achieve a side-scroller view. We will also add some coins to our scene and use simple collision mechanism that will allow the character to collect the coins. We will “teach” our character to run and jump :). We will also see some variable and function macros for the integration between the C++ code and the Editor… and so much more. Are you ready?!… Well let’s get started!!

Setting the level from the editor

Let’s start by making a small change to the current level through the editor to match the style of game that we want. The base to a side-scroller game is to have the camera parallel to the main character and to have the camera a certain distance away from the character on the y axis. The character moves only in two directions – upward and downward when he jumps, and left/right when he walks.

Open in the Editor the UE4Demo project that we used in the last tutorial and delete the visible objects that we won’t use (the chairs, the table, the statue, etc.), leaving only the floor object. After that, modify this object using the transformation and escalate tools situated in the upper-right corner of the viewport. Then create copies of the object, modify them indistinctly and spread them through the level. Make sure to leave the ‘Actor Play Start’ on one of the platforms, to avoid that the character free fall into abyss. This is how I did it (use your imagination to achieve a better result than mine :).

Modified level in the Editor to match our game style

Modified level in the Editor to match our game style

 

As you will notice, when the game runs, it shows a red alert which says: LIGHTING NEEDS TO BE REBUILT. This alert has to do with the fact that we change the level geometry and the engine needs to rebuild the light so the illumination and shadows fit the new geometry. You can rebuild the lights selecting the Toolbar/Build/Build Lighting Only option. Run again and you will notice that everything goes back to normal.

For now we have a very basic level but enough to implement and test all the things that we have planned to do.

Configuring the camera for a side-scroller game.

At this point, it’s important to clarify that UE4 has a default template to build this style of game. In fact, we will use practically the same elements that this template uses but the idea of this tutorial is to do it from scratch to understand the basic concepts of the game style.

First we will change the game camera. In the last tutorial, we configured a simple fixed camera that served the purpose of introducing us both into the visual scripting (Blueprint Editor) and the C++ code. We will no longer use this camera so go ahead and delete the current implementation of the camera both in code and in the Blueprint Editor. If you still have the code implementation, comment out the lines inside the Begin Play method. In the Blueprint you may delete all the nodes or, if you want to keep the references, delete the connection leaving the BeginPlay node. By deleting this connection, we break the camera algorithm because the execution doesn’t continue when the BeginPlay event is executed but we still hold the rest of the connections and references.

Let’s configure a new camera’s style, this time through code in our Character’s class. Always take into account that you can also do it through the Editor. Remember that we have a Blueprint class that inherits our HeroCharacter class. A good way to practice will be for you to adventure by yourself once we do it by code to do the same in the Editor by modifying the HeroCharacterBlueprint.

Open the HeroCharacter class and add the next declarations after the GENERATED_UCLASS_BODY() macro:


/** Spring arm to fix the camera to the Character to match the side-scroller style */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
TSubobjectPtr<USpringArmComponent> SpringArm;
    
/** Game camera, is attached to the arm’s socket to achieve the side-scroller’s camera style */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
TSubobjectPtr<UCameraComponent> SideViewCamera;

We add two class variables to our HeroCharacter, but I’m sure that the thing that caught your attention was the UPROPERTY macro included for each variable. This way we define whether or not we want to use these attributes in the Editor and what options we have to work with them. As we saw in the previous tutorial, one of the coolest things about UE4 is the seamless integration between the code and the editor and this macro is one of the powerful utilities to achieve it. Next, let’s look at some of this macro’s parameters:

VisibleAnywhere: Defines if this property will be visible in the Editor’s property panel.

BlueprintReadOnly: Defines if this property could be read from VisualScript in the Blueprint, but it can’t be modified.

Category: Allow to specify a category name under the properties will be listed in the Editor.

You can find a detailed reference of all of the configurable parameters to the UPROPERTY macro in the Runtime/CoreUObject/Public/UObject/ObjectBase.h inside the UP namespace. If you click over a category while pressing the cmd key in MACOS, or click one while holding ctrl in Windows, you will be taken to the specific reference for that macro.
After we implemented the constructor where we initialized these variables, go to the Editor to check the result of defining the attributes with this macro.

These two class attributes just created in HeroCharacter are of a data type we haven’t used before. The first one is USpringArmComponent that we named SpringArm. Notice that we used the parametrized TSubobjectPtr class to define it. This way we can use the CreateDefaultSubobject method of the PCIP object received in the constructor to create an instance of any data type, which we will in a second. The USpringArmComponent allows us to fix a component to its parent in a fixed distance. We will use this component to fix the game’s camera with a certain distance from the character.

We will also create the class attribute SideViewCamera of UCameraComponent data type. The class name is quite descriptive. This attribute is our game camera :).

Next we will initialize this variable in the class constructor. Open the HeroCharacter.cpp and add the following code block:


//Initializing the USpringArmComponent attribute
SpringArm = PCIP.CreateDefaultSubobject<USpringArmComponent>(this, TEXT("CameraBoom"));
   
//Adding the springArm to the Character's RootComponent (the collision capsule)
SpringArm->AttachTo(RootComponent);
   
//bAbsoluteRotation allows us to define if this support will rotate with the player or will stay fixed.
//In our case we don't want it to rotate with the character.
SpringArm->bAbsoluteRotation = true;
   
//The distance between the arm and its target. This value defines the distance between the character and the camera.
//Try out different values to see the outcome.
SpringArm->TargetArmLength = 500.f;
   
//Socket Offset.
//Socket is an anchor point to other components.
//For instance, in the character case we can define the socket in the character's hand
//this way we can add another component(for example a gun).
//But in our case we will add a camera to our SpringArm
SpringArm->SocketOffset = FVector(0.f,0.f,75.f);
   
//The relative rotation of the arm regard to its parent.
//We want the camera rotated 180 degrees in the Y axis in order to be situated parallel to the character, at the same level.
//This way we achieve the classic side-scroller camera's style.
SpringArm->RelativeRotation = FRotator(0.f, 180.f, 0.f);
   
// Creating the UCameraComponent instance.
SideViewCamera = PCIP.CreateDefaultSubobject<UCameraComponent>(this, TEXT("SideViewCamera"));
   
//The AttachTo method allow us to add an object to another in a given socket. It receives two parameters,
//the first one, the object where we will be anchored (the springArm) and the second the socket's name where we will be anchored.
//USpringArmComponent's SocketName returns the name of the components socket.
SideViewCamera->AttachTo(SpringArm, USpringArmComponent::SocketName);

Pay attention to each line comments so you can understand what each stands for. Overall, we create and configure the USpringArmComponent’s object and then we add it to the Character. Next, we create and configure the UCameraComponent’s object (the game camera) and add it to the USpringArmComponent to fix it to a given distance from the Character. Notice that we create the instances with the received reference in the constructor class using PCIP.CreateDefaultSubobject.

Ready, build and play the game. Now you have the game view in the side-scroller style :). Try to move in the level just created to see how the camera follows your every moment, always at a fixed distance.

New game view configuration to match the side-scroller camera's style

New game view configuration to match the side-scroller camera’s style

 

Don’t close the editor. Let’s focus in HeroCharacterBlueprint. In the last tutorial, we created this blueprint in the Character folder. Open it and activate the Components mode (upper-right corner). Notice that now in the Character’s Components panel we have a new object: the SpringArm and it contains a child the SideViewCamera. Check out all the properties defined by code. You can also check all the default properties values, change the values, and check out the different outcomes.

To test the parameters effect of the UPROPERTY macro in practice, go back to the code and delete the VisibleAnywhere parameter set in the property and build again. When you open the HeroCharacterBlueprint in the editor, in spite of seeing the components, we can’t see the properties values in the details panel when we select them.

Modifying the game controls for a side-scroller’s game.

So far we have set the camera’s style but I’m sure you noticed that the game controls don’t fit our game’s style, given that the character can move both in X and Y axis which is very unusual in a side-scroller game. Therefore we’ll change the game controls a bit to adjust them to the side-scroller style. We will also add two new actions and controllers to our character: run and jump.

I assume that after the last tutorial you have a couple of ideas of how to add these actions. In the Editor, select Edit/Project Settings/Input and leave only the MoveRight entry. Now let’s add another input type the ActionBinding. These entries, unlike the AxisBinding entries, are used to execute specific actions e.g. to jump or open a door. Create a new entry of this data type and name it Jump. Select the space bar as the key control. If you look closely you will notice that we can also define that the action gets executed when two keys are pressed simultaneously. In this case, will only use the space bar to jump.

New configuration of the game's controls. Adding jump control.

New configuration of the game’s controls. Adding jump control.

 

Now let’s code. First of all, we no longer need the MoveForward method of the HeroCharacter class. Delete the method statement in the .h and the implementation in the .cpp. Also, in the SetupPlayerInputComponent method, delete the MoveForward BindAxis. Lastly, we have to modify the MoveRight implementation given that at the moment when the entry gets called we rotate the character position, now we want that the character to move forward and backward respectively. Modify the MoveForward as the code below:


/**
*  Gets called when the MoveForward entry is detected (When the user press the A or D keys).
*  @param Value Value is equal to 1 when the D is pressed and -1 when A is.
*/
void AHeroCharacter::MoveRight(float Value)
{
if ( (Controller != NULL) && (Value != 0.0f) )
{
        // Adds a new movement to the right or left according to the Value value.
        AddMovementInput(FVector(0.f,-1.f,0.f), Value);
}
}

Now this method is much simpler and I hope it’s easier to understand what it does. Anyway, I will explain step by step what we just did. We apply a movement vector that affects only the y axis of the vector’s value. So when the user presses the D key, the character will move forward (to the right) and when the A key is pressed, the character will move backward, meaning to the left side.

Now we have to implement the method that will get called to execute the jump action when the user presses the space bar. It’s very simple. Just add the next line to the SetupPlayerInputComponent method:

InputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);

Notice one thing, the method that gets called is the ACharacter::Jump. Jump is a method implemented in our base class, not in our own class HeroCharacter. This method already has all that we need to make the character jump. It’s really amazing how much help the framework provides us with :).

Go ahead build and play the game. Press the A and D keys to see how the character moves correctly on the scene, and how when you press the W and S keys, nothing happens. Hit the space bar and you will see how our character now also jumps :) … but something is still missing. Yes the character is jumping but visually is playing the walk animation. Next thing we need to do is add the jump animation.

Setting the jump animations for the character

Since the last tutorial, we have the main character resources that supposedly our design team have us, among them we have three FBX animations to jump: the Jump_End.FBX, Jump_Loop.FBX, Jump_Start.FBX and the Run.FBX file. Import them in the Animation folder. You can inspect them in the Persona Editor.

I’m sure that the fact that we have three different animations for the jump caught your attention, and you ask yourself, “Why??”. I will give you the answer right away but first let me share a personal experience with you involving this aspect: When we start the development of our current project, you can take a look in here :)). We struggle with this problem.
In our game, the character jumps at different heights. For instance, it can do a small jump to avoid a box or a long jump from a cliff and stays longer in the air. The problem is that in the long jump case we play the jump animation when the action is started with a duration and might end while the character is still in the air falling in the last frame of the jump animation until it touches the ground where the transition will continue normally. That’s the reason why in many cases, it’s necessary to divide the jump animation in three pieces, we have the start jumping action then we have a loop animation that is played while the character is falling and finally the animation when the character touches the ground. This is how we achieve the whole jump animation cycle independently of the height.

Let’s configure it in the character animation blueprint. As we saw in the last tutorial, we use a state machine for the animation system that allows us to separate the different states that our character supports and set an animation for each state. Currently the state machine of our character is very simple, containing only the Idle state and the Walking state. Let’s add the jumping states.

Inside the HeroAnimBlueprint/AnimGraph, enter the state machine, drag the cursor from the Idle/Walk node to create a new node, and name it JumpStart. Repeat the procedure twice using the last created node to create the JumpLoop node and finally the JumpEnd. At the end, connect the JumpEnd state to Idle/Walk to close the cycle. It should look like this:

New Character state machine, with the jumping states added

New Character state machine, with the jumping states added

 

We have just defined three new states to our character and the order in which they would be reached. In other words, the character could be in rest or running and can change to the JumpStart state (jump starts). From the JumpStart state, he can reach the JumpLoop (loop cycle) and then the JumpEnd state. Lastly, he could go to the Idle/Walk state. Notice the directional arrows between the states. These are the connections that define the origin and destination states. If you jump you will notice the four states and the blending between them.

Each state has an icon over the transition arrow. This icon represents the condition that triggers the transition between the states. We have to define this condition using the visual scripting in the Blueprint Editor. The first case is when the character is in the Idle/Walk state and starts the jump action. The condition to pass to this state will be BOOL variable that will store if the character is in the air or not. When the character changes the state such that it is in the air, we will change to the JumpStart state.

Double click in the transition icon to enter in its edition mode. By default we have a Result node with the “Can Enter Transition” description. This node expects a bool parameter that the state machine will use to decide if the state transition takes place. Create and add a new variable like we did in the last tutorial but this time use bool as data type. Name it IsInAir or any name that you prefer but it must be something meaningful. Add it to the blueprint in GET mode and finally connect this node output port to the input port of the Result node. So if the IsInAir variable has a true value, the transition will execute and the character will pass to the JumpStart state.

VisualScript of the transition between the Idle/Walk and JumpStart

VisualScript of the transition between the Idle/Walk and JumpStart

 

Save and exit the edition mode of the transition between the Idle/Walk and JumpStart and enter the edition mode of the JumpStart node to define which animation will be played in this case. Drag the JumpStart animation from the resources folder into the blueprint and connect it to the final node. The JumpStart and JumpEnd animations will be played only once which is different to what we did in the last tutorial where the Idle and walk animations are played in a loop. The idea is to start playing the JumpStart then pass to the JumpLoop that as its name suggest plays in a loop and finally play the JumpEnd animation only once. So select the JumpStart animation and in the property panel, uncheck the Loop option. Do the same for the JumpEnd animation.

VisualScript of JumpStart node

VisualScript of JumpStart node

 

Now we have to define the condition to pass from the JumpStart to the JumpLoop animation. For this task we will use a new node. We need to be able to detect when the JumpStart animation is about to end to know when to start playing the loop animation. Double click in the transition icon between JumpStart and JumpLoop. Once again we meet the Result node that we’re about to use but first we need to do an algorithm to define when the animation is near to end.

Let’s add a new node of the Time Remaining (Ratio) type to the Jump_Start Asset. This node informs us of how much time remains before the animation ends. Let’s add another node < float type, we will use it to know if an A parameter is smaller than a B one. Connect the output port of the TimeRemaining node to the upper input port of the comparison. For the second input port, we will use a manual value, in this case 0.1. Now,when the TimeRemaining is less than 0.1 (the animation is about to end), we transition to the JumpLoop state. In order to complete the transition setup, we still have to connect the comparison node output to the Result node. It should look like this: [caption id="" align="alignnone" width="630"]VisualScript of the transition between JumpStart and JumpLoop animationsVisualScript of the transition between JumpStart and JumpLoop animations[/caption]

 

Summing up, we periodically check if the StartJump animation is about to end by checking if the remaining time is less than 0.1. When this condition is fulfilled, the transition is executed.

Save and exit the transition’s edition mode and enter the state JumpLoop edition mode. Add the JumpLoop animation and connect it to the Result. Unlike with the JumpStart animation, with the JumpLoop animation, we need to play it in a loop because this is the one that plays while the character is falling, so check that the loop option is checked.

JumpLoop's node VisualScript

JumpLoop’s node VisualScript.

 

Let’s configure the last transition between the JumpLoop and JumpEnd nodes. JumpEnd, as its name suggests, is the animation played when the jump ends. The condition to transition to this state is that the character is close to the floor (it’s no longer in the air). That’s exactly what the isInAir variable represents. Double click on the transition icon between JumpLoop and JumpEnd and add the isInAir variable as GET. The problem is that we need to know when the character isn’t in the air so we need to use the isInAir negation, so we will add a NOT node type to the blueprint. This node type returns the input’s negation. Connect the NOT node to the isInAir node and this to the Result. Now, as soon as the character hits the floor, the character will transition to the JumpEnd state.

VisualScript of transition between JumpLoop and JumpEnd

VisualScript of transition between JumpLoop and JumpEnd.

 

Exit the transition’s edition mode and enter in the JumpEnd edition mode. Drag and connect to the Final Pose the JumpEnd animation and uncheck the loop option.

JumpEnd's node VisualScript

JumpEnd’s node VisualScript

 

Finally, we have to define the condition for when to transition back to the Idle/Walk state coming from the JumpEnd state. This animation represents the character already on the floor but still recovering from the fall. We need to wait until the JumpEnd animation is about to end to change to the initial state (Idle/Walk). Basically, we will repeat the steps we use in the transition between the JumpStart and JumpLoop. I hope you are able to do it by yourself… 😉 it should look like this:

VisualScript of transition between JumpEnd and Idle/Walk

VisualScript of transition between JumpEnd and Idle/Walk

 

Now we have completed the character state machine, but a small detail is still missing. We need to set the IsInAir variable value like we did earlier with the Speed variable.

Close the AnimGraph Editor and open the EventGraph. Add a GetMovementComponent node and connect the TryGetPawnOwner node that we created in our last tutorial to the input port of the GetMovementComponent node. Add another node and name it IsFalling and connect its output port of GetMovementComponent to the new node’s input port. Add the IsInAir variable in SET mode and connect the IsFalling output to the IsInAir input. Finally, connect the blank output port of the SET Speed to the SET IsInAir input for the algorithm continuity.

HeroAnimBlueprint's EventGraph modify it to set the IsInAir variable value when the character is in the air

HeroAnimBlueprint’s EventGraph modified to set the IsInAir variable value when the character is in the air

 

If you have read the previous tutorial, I’m sure you won’t have any problem understanding what we just did. We got the character’s MovementComponent, which contains an IsFalling method that returns a bool value denoting if the character is in the air or not. This IsFalling method is the one we will be using to set our IsInAir variable. Now we have the state machine for our character. Build the AnimationBlueprint and run the game. Press the space bar … now our hero jumps too :).

Character jumping with proper animation

Character jumping with proper animation

 

Implementing character’s running mechanism!!

Now our character knows how to walk, rest and jump, but a classic feature in side-scroller games is the ability to run to get more momentum and jump higher and further. Who doesn’t remember in one of Super Mario latest level the huge hole that can only be jumped with a great momentum, do you :)… So the next thing we will do is to add this skill to our character. Let’s implement it so that when the character is walking and the Shift key is pressed, the character will run.

First of all, open the editor and in the controls sections, add a new ActionBinding entry, name it Run and select the LeftShift key. Close the editor and open the HeroCharacter.cpp inside the SetupPlayerInputComponent method and add the following two lines:


//The Run entry is detected, when the Shift key is pressed we set that the ToggleRunState method should be call.
InputComponent->BindAction("Run", IE_Pressed, this, &AHeroCharacter::ToggleRunState);
   
//The Run entry is detected, when the Shift key is released we set that the ToggleRunState method should be call.
InputComponent->BindAction("Run", IE_Released, this, &AHeroCharacter::ToggleRunState);

Notice a tiny detail in this code. We are setting the BindAction for the Run entry twice and passing the same ToggleRunState method (that we will soon implement). The difference between the calls is that the second parameter specifies when the method gets called. The first case, IE_Pressed is fulfilled when the Shift key is pressed and IE_Release when it’s released. What we want to achieve is that when the key is pressed, the character runs and when the key is released, the character stops running and continues walking. Very similar to the Super Mario logic for the big jump!! :).

Now let’s implement the ToggleRunState method. Add the method’s declaration to the .h file:


/**
* Gets call when the engine detects the Run entry
* Change to the character run state.
*/
void ToggleRunState();

Go to the .cpp and add the following lines to the implementation:


/**
* Gets call when the engine detects the Run entry
* Change to the character run state.
*/
void AHeroCharacter::ToggleRunState()
{
//If the CharacterMovement's MaxWalkSpeed attribute is 400.f we increase it to 900.f to achieve that the character will  move faster.
//Otherwise we set it to 400 again so the character move in the walk speed range.
    if(CharacterMovement->MaxWalkSpeed == 400.0f)
        CharacterMovement->MaxWalkSpeed = 900.0f;
    else
        CharacterMovement->MaxWalkSpeed = 400.0f;
}

By default, the movement speed value is 400. When the shift key is pressed, we change the MaxWalkSpeed to 900, which causes the character to move faster. When the shift key is then released, the method is called again and we set the value back to 400, decreasing the movement speed.

If you want to test your knowledge, you can implement the run mechanism in the HeroCharacter’s Blueprint. If you accept thus challenge, remember first to delete the C++ code. It should looks like this:

Blueprint version of the run mechanism

Blueprint version of the run mechanism

 

I personally prefer to keep all the character’s logic in code, but this exercise may serve as practice to increase your skills in the Blueprint Editor, something that’s new for much of us and I’m sure caught your attention :). I also recommend to expose the max and min values of the MaxWalkSpeed so it can be modifiable from the Editor and to avoid going to the code to change its values. Remember, in order to make variable values modifiable via the editor, you have to use the UPROPERTY macro, but this time I won’t show you how I did it so you must check how we did it previously and use your imagination. I’m sure you can do it 😉

Build and play the game. Let’s try it out. While you’re walking, press the shift key and you will see how the character moves much faster. We’re not quite finished yet because the character still uses the walk animation while running so it looks weird.

Adding the run animation to the character

Let’s add another animation to our character – the run animation. We will use the Idle/Walk state created previously to add the run animation. We will also use the same node to blend between the animations. An amazing feature of this type of node is that we can add more than two animations. The idea is to modify it to set three control points: the first one at the start of the graph will use Idle animation, the second in the middle of the graph will use the Walk animation, and the third at the end of the graph for the Run animation.

Import Run.FBX from your resources, open the IdleWalkBlendSpace1D created in the last tutorial, change the X Axis Range property to 900 (the movement value of the character when it’s running), and click the Apply Parameter Changes. Now add the Idle animation at the start, the Walk animation in the middle, and the Run animation at the end. Make sure the Enable Preview BlendSpace option is checked and move the cursor over the graph to see the blend between the animations according to the speed value. Pretty cool and easy, ehhh???

New IdleWalkBlendSpace1D configuration for the Idle/Walk/Run state

New IdleWalkBlendSpace1D configuration for the Idle/Walk/Run state

 

Save, play the game and try to run. Now our character walks and runs perfectly.

Running character pressing the D+Shift keys

Running character pressing the D+Shift keys

 

Adding coins in the scene for the character collect.

We already have our character walking, running and jumping through the scene in a side-scroller style, but we need to add some purpose to the game because wandering around isn’t much fun. Let’s try to improve it a little by adding some coins in the scene for the character to collect, a common feature in this style of game. In next tutorials, we will see what our character wins with these coins.

First, we need a coin model. I’m sure you can find several StaticMesh that you can use as coins from the MarketPlace. I strongly recommend you take some time to visit the MarketPlace. I’m sure that you will find a lot of things that you will love and many of them are FREE!! :D.

Anyway, you can download the FBX of a very simple coin here :S Its not amazing but it works for this tutorial. Import the FBX file to the project (I created a Coin folder). In the importing window, you will notice that Unreal detects that this is a StaticMesh. Expand the advanced options and select the materials and texture options. This way, we’re also importing the model’s material. That is also extremely simple.

Now with the resource imported, let’s create the C++ class that encapsulates all the coin logic. Create a new class in the Editor and named it Coin. This class will inherit from Actor. Select Yes when the Editor asks you if you want to open the class in the IDE. Modify the .h file so it looks like the following:


/** Represents a coins. The character can collect them by colliding with them. */
UCLASS()
class ACoin : public AActor
{
GENERATED_UCLASS_BODY()
   
    /**
     * USphereComponent is sphere shape component generally used to detect simple collisions
     * This will be the root component of the coin and with it we will detect the collisions between the character and the coins.
     */
     UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Coin)
    TSubobjectPtr<USphereComponent> BaseCollisionComponent;
   
    /** Coin's StaticMesh, we used previously in the Character. We store the coin's StaticMesh instance. */
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Coin)
    TSubobjectPtr<UStaticMeshComponent> CoinMesh;
   
    /**  Boolean variable to enable/disable the coin */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Coin)
    bool bIsActive;
};

I recommend you pay attention to the code comments because I always point out which function has every line. Basically, we define the BaseCollisionComponent attribute to be the root component of our coin which we will use to detect collision. The other attribute is the UStaticMeshComponent which is used to define the StaticMesh that represents the coin in the level. The last one is the bIsActive we will used as a flag to disable the coin when the user collides with it.

Go to the .cpp file and modify the constructor to match the following code:


ACoin::ACoin(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
{
    //Create the USphereComponent instance.
    BaseCollisionComponent = PCIP.CreateDefaultSubobject<USphereComponent>(this, TEXT("BaseSphereComponent"));
   
    //Initialize the Actor's RootComponent with the USphereComponent.
    RootComponent = BaseCollisionComponent;
   
    //Create the UStaticMeshComponent instance
    CoinMesh = PCIP.CreateDefaultSubobject<UStaticMeshComponent>(this, TEXT("CoinMesh"));
   
    //We add the UStaticMeshComponent as child of the root component
    CoinMesh->AttachTo(RootComponent);
   
    //By default the coin will be active
    bIsActive = true;
}

We instantiate the USphereComponent as the coin’s root component. We also create the UStaticMeshComponent instance. We will soon configure it from the Editor and then added it to the RootComponent. Finally, we set the bIsActive variable to true because we want the coin to be active when it’s created.

Adding coins to the scene

Let’s create the Coin’s Blueprint as we did with the Character in the last tutorial. In the ContentBrowser, select the Coin folder, then right click and select the Blueprint option. Finally, set Coin as the base class and name it CoinBlueprint. As you will see, it contains the same components that we define in the USphereComponent constructor, for instance, the RootComponent and the UStaticMeshComponent. Unfold the CoinMesh and select the StaticMesh imported for the coin.

CoinBlueprint component's section. Adding the StaticMesh component

CoinBlueprint component’s section. Adding the StaticMesh component.

 

Now we will add some coins to the scene. Find the CoinBlueprint in the ContentBrowser and drag it into the level at the position where you want to place a coin. This must be a place reachable by the character. It’s important to remember that in this style of game, the character is placed on a fixed Y axis, so you must place the coins at the same Y value as the character in order for him to collide with the coins.

This is the simple level I made:

Level in edition mode with coins added.

Level in edition mode with coins added.

 

We added the coins to the level, but so far they don’t do anything. If you walk into the coins, nothing happens. Besides, the coins look very bad because they’re static. Let’s add some life to them.

Collision mechanism to collect the coins

At the moment, the character hits the coins but there isn’t any feedback. Let’s add the collision detection that, as its name suggests, will detect the collision between the character and the coins. We will have a “Collected coins” variable that we will increase when the character collides with a coin. We will create and call the OnCollected() method in the Coin class where we will disable the coin, delete it from the scene and print a log on the screen to debug the algorithm.

Open the HeroCharacter.h and add the following declarations:


    /** Character's amount of coins collected */
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category=Coins)
    int32 CoinsCollected;

    /** It's called constantly in the character's Tick to check if its colliding with a coin */
    void CollectCoins();
   
    /**
     * Gets executed automatically by the engine every frame
     * @param DeltaSeconds the difference in seconds between the last and current frame.
     */
    virtual void Tick(float DeltaSeconds) OVERRIDE;

Before we get deep in code, let’s theorise on the functionality that we will use. Every Actor in UE4 implement the Tick method. This method is called automatically by the engine every frame. If you are reading this tutorial, you are probably familiar with game development, at least with its theory. If so, you will know this method’s significance. Basically, all of the Actor’s algorithms that must run constantly will be called inside this method. The method receives a float as a parameter. This is the amount of time, in seconds, that has passed since the last tick/frame. This value is commonly used in a variety of tasks. For instance, it can be used as a multiplier when modifying the character’s position or rotation in order to achieve an execution depending on the framerate as to avoid gaps in case that the framerate decreases.

So we will call the CollectCoins method in the Tick method so it runs constantly. Internally, this method checks if a coin is inside the Character’s CapsuleComponent. If it is, that means that the character is colliding with that coin do we should trigger our collision mechanism.

Open the HeroCharacter.cpp file. At the end of the constructor implementation, add the CoinsCollected = 0 line. This causes the CoinsCollected variable to be set to zero when the character is create and is done because hasn’t collected any coins. Add the CollectCoins and Tick methods:


/** It's called constantly in the character's Tick method to check if is colliding with a coin */
void AHeroCharacter::CollectCoins()
{
    //AActors array to save temporary all the actors that are colliding with the character
TArray<AActor*> CollectedActors;
   
    //GetOverlappingActors method of the CapsuleComponent. This method returns all the actors colliding with the character in the array we pass as parameter.
    //All the objects that are currently inside the capsule.
    CapsuleComponent->GetOverlappingActors(CollectedActors);
   
    //We iterate through all the objects inside the CapsuleComponent.
    for(int32 i = 0; i < CollectedActors.Num(); i++)
    {
        //We have to cast the array elements to ACoin because the array is declared as AActors.
        ACoin *Coin = Cast<ACoin>(CollectedActors[i]);
       
        //We make sure that the coin is active and that the Destroy method hasn't been called
        if(Coin != NULL && !Coin->IsPendingKill() && Coin->bIsActive)
        {
            //We increase the coins collected amount.
            CoinsCollected++;
           
            //Finally, we call the OnCollected method of the Coin class to execute all the collect coin logic.
            Coin->OnCollected();
        }
    }
}

/**
* Gets executed automatically by the engine every frame
* @param DeltaSeconds the difference in seconds between the last and the current frame.
*/
void AHeroCharacter::Tick(float DeltaSeconds)
{
    Super::Tick(DeltaSeconds);

    //In every update is called the CollectCoin to constantly check if it's colliding with a coin.
    CollectCoins();
}

Take a minute to read every line’s comments to really understand the collision detection process. This is a very simple collision detection but it’s enough to understand how to work with it in UE4 :). It’s important to clarify that inside the CollectCoins method we have a reference to the ACoin class created by us. To avoid errors, we have to add #include “Coin.h” declaration at the top of the .cpp file below the #include “UE4Demo.h” line.

Only one small thing is left. If you try to build now you will get an error because when a collision is detected, the OnCollected method of the Coin class is called and we haven’t implemented this method yet. Let’s do that now:

Add the method’s declaration to the .h file and the implementation in the .cpp.


/** It's called when a collision is detected */
void ACoin::OnCollected()
{
    //To Debug we print a log on the screen
    GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "Coin Collected !!");
   
    //We change to false the bIsActive flag
    bIsActive = false;
   
    //We call the Actor's Destroy method, to remove the coin from the scene
    Destroy();
}

This method will be called when a collision is detected. First we use the AddActorLocalRotation method of the framework’s GEngine object. This method is very handy because it allows us to print messages in a specific colour at a certain amount of time on the screen. To debug our code in runtime is very useful. Here we print Coin Collected when the character collides with a coin. Besides that, we set the bIsActive variable as false and we remove the coin from the scene using the Actor’s Destroy method.

Build and run the game one more time. Now walk into a coin … Very nice!! When the character passes through a coin, the coin is removed from the scene. Internally, the amount of coins collected is increased (at the moment there isn’t any visual feedback regarding this value) and then we print the temporary Coin Collected¡! log to the screen.

“Debugging” the scene collisions

If you are good at paying attention to small details, I’m sure you will notice a small problem with this collision mechanism. Try to reach a coin slowly, you will notice that the collision occur before the character actually touches the coin. To find the problem, UE4 provides us with an amazing command that allows us to check the collision component of an actor at runtime. Run the game one more time and pay attention in the upper-right corner of the Editor. You’ll notice there is a text field that allows us to write commands. Write in the field: show COLLISION and press the Enter key. Immediately, the collision component appears over every actor .

Run time game with the show COLLISION command active to debug the Actor's collision component.

Run time game with the ‘show COLLISION’ command active to debug the Actor’s collision component.

 

Notice two things that could the cause the problem. First, the coin component is bigger than the coin itself. Second, the character’s capsule radius could be reduced. End the game execution and open the CoinBlueprint then select ROOT in the components mode. In the Details panel, search for the Shape section that holds the sphere radius. Change its value to 15 and check out the preview showing how the sphere surrounds the coin. Notice how this adjustment better fits the model. Save and try again. You will see how the collision detection has improved as now the character has to be very close to catch the coin.

Modifying the sphere component radius to adjust the collision detection

Modifying the sphere component radius to adjust the collision detection

 

You can do the same with the character’s capsule if you want to continue improving the collision mechanism. It’s important to mention that this value can be defined in the class constructor by code. Try to do it by yourself to practice.

Rotating coins on its own axis.

To add some life to the coins, we will rotate them on their own Y axis. Close the editor, open the Coin.h class and add the following lines:


    /** Coin rotation factor */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Rotation")
    FRotator RotationRate;
   
    virtual void Tick(float DeltaTime) OVERRIDE;

We simply add the Tick method and a new RotationRate attribute of FRotator type. This is the rotation vector we will use to rotate the coin in every Tick call. Actually, there is no need to declare an attribute but in doing so, we gain the opportunity to configure the rotation factor in the editor, thanks to the UPROPERTY macro.

Go to Coin.cpp file. At the end of the constructor, add this two lines:


    //Initialize the coin rotation factor in each update
    RotationRate = FRotator(0.0f, 180.0f, 0.0f);
   
    //Enable the Tick method of this Actor
    PrimaryActorTick.bCanEverTick = true;

The first line is the rotation vector’s initialization. By default, the Tick method isn’t called automatically in an Actor inherited class such as our Coin class. To enable the call to the Tick method in this class, it’s necessary to set the PrimaryActorTick.bCanEverTick attribute as true.

Very well, now add the Tick method’s implementation:


void ACoin::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

    //Adds a rotation factor to the coin in each Tick call
    AddActorLocalRotation(this->RotationRate * DeltaTime, false);
}

The code is very simple. Basically we add a rotation factor thanks to the AddActorLocalRotation, in each update.

Ready!! Build, run and test. Super nice, right!! The coins are constantly rotating in the scene, waiting to be caught :).

Implementing the coin logic in the Blueprint.

As I already mentioned in the last tutorial, the decision of whether to use the code or the Editor is up to the individual. I personally follow these two rules of thumb. 1. Implement all the related things only in one place (for maintenance purpose). In other words, don’t have half of the logic in code and the other half in the Blueprint. 2. If the Actor logic is very simple like it is for this coin, the ideal solution is to use the Blueprint. However, when the thing needed to be implemented is large and complex, I personally prefer to use C++.

You could have some practice implementing the coin logic in the Blueprint. Do you dare? It should look something like:

Coin VisualScript

Coin VisualScript

 

Notice that we implement what happens when the OnCollected method is called in the Blueprint. We still have to add in the method’s declaration, the UFUNCTION(BlueprintNativeEvent) macro, or the UFUNCTION(BlueprintImplementableEvent). Next I will explain both:

UFUNCTION(BlueprintImplementableEvent) is designed to be overridden by a blueprint. Do not provide a body for this function; the automatically generated code will include a thunk that calls ProcessEvent to execute the overridden body.

[UFUNCTION(BlueprintNativeEvent) macro]. This function is designed to be overridden by a blueprint, but also has a native implementation. Provide a body named [FunctionName]_Implementation instead of [FunctionName]; the automatically generated code will include a thunk that calls the implementation method when necessary.

For example, if you want to test the OnCollected method, the definition will be like this:


UFUNCTION(BlueprintNativeEvent)
void OnCollected();

And the implementation should look like:


void ACoin::OnCollected_Implementation()
{
    //As Debug we print a log on the screen
    GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "Coin Collected !!");
   
    //We change the bIsActive flag to false
    bIsActive = false;
   
    //We remove the coin from the scene with the Destroy method
    Destroy();
}

The silver lining is that we can have our code implementation, but we can also override this implementation in the Blueprint … cool, right? UE4 stuffs!! :). Try the coin logic implemented in VisualScript in order to gain confidence in the Blueprint Editor, one of the wonders of UE4.

Conclusion

Well, I think it’s time to call it a day. In this second tutorial, we did several new things. Among them, we made a simple collision detection mechanism We implemented the Tick method. We added the run and jump animations to the character. We configured our game camera to the 3D Side-Scroller style. We saw some variables and macro class functions for the integration between the code and the Blueprint Editor, etc.

In next tutorial, we will continue to build our game. We will add a HUD so the user knows the number of coins collected, and the time available to achieve some goal. We will define the GameMode, the win and lose conditions and so much more ;).

I hope you found this tutorial useful. If you did, please leave me your comments and share this tutorial with the rest of your friends who are also passionate about game development with UE4. Till next time!!… Bye.

Fernando Castillo Coello
Follow me

Fernando Castillo Coello

Gameplay Programmer at GameOlic
I've been into games development with Unreal Engine since 2014 and want to share with you some of the tips and tricks that I learned during my journey.
Fernando Castillo Coello
Follow me

Un pensamiento en “Making a 3D side-scroller game in UE4

  1. gabriel

    Hey man do you know much about behavour tree.Im making a side scroller and its just not working.The enemy iv made is not moving inspite of the behavour tree moving to the follow service. I d use UE4 community but they have no answers for this basic question.

    In otherwords do you have a game with working behavour tree A.I for a side scroller enemy i can have a look at ?

    Responder

Responder a gabriel Cancelar respuesta

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *

Puedes usar las siguientes etiquetas y atributos HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>