Create A Side Scroller C++ Game In Unreal Engine Part 1: Creating The Player Actor C++ Class And Its Functionalities

Table of Contents

Create A Side Scroller C++ Game In Unreal Engine Part 1: Creating The Player Actor C++ Class And Its Functionalities

Reading Time: 18 minutes
Level: Beginner
Version: Unreal Engine 4.27

Help Others Learn Game Development

Share on facebook
Share on twitter
Share on reddit
Share on linkedin

In this tutorial we are going to create a 2.5D infinite runner game using Unreal Engine and C++. The game is simple, yet it contains a lot of cool features that will help you learn how to create games using Unreal Engine and C++.

Here is a short preview of the game that we will create:


Download Assets And Complete Project For This Tutorial

To follow along with this tutorial, please download the assets by clicking on the green Download assets button above.

In the downloaded folder you will find the assets for the tutorial and the complete project that you can use as a reference to inspect the code.

Important Information Before We Start

I’ve labeled this tutorial as beginner, however, this is not a tutorial for complete beginner.

I expect you to know your way around Unreal Engine and its interface. I also expect that you know the basics and a little above basics of working with blueprints. Basic knowledge of C++ is also required. Things like variables, functions, classes, objects, and so on.

To put it simple, this tutorial is suited for beginners who started learning Unreal Engine and a little bit of C++, and they created a few basic games in Unreal Engine using blueprints, and now they look to learn how to create games using C++ and Unreal Engine.

If this is not you, then please go through my C++ tutorial series starting with variables, and my Unreal Engine Parasite Platformer tutorial.

Now that we have that out of the way, we can start with our game.

Creating The Project

As always, from the Unreal Project Browser select Games and click the Next button:

Img 1
In the next windows select the Third Person project and click on the Next button:
 
Img 2
In the next window select the C++ instead of Blueprint, set the location where you want to store your project and give it name, I set the name SideRunner and then click the Create Project button:
 
Img 3


Enabling Engine Content

The first thing that I am going to do is enable the Engine Content that comes a long with the project.
 
in the Content Browser, click on the view options in the bottom right corner:
 
Img 4
From the drop down list, check the Show Engine Content checkbox:
 
Img 5
This will show the extra folders that are hidden by default, that come with a predefined Unreal Engine project such as Third Person, the one we selected:
 
Img 6


Resizing The Unreal Engine Editor Font

Before we proceed, I want to show you a nice trick that can help you with your development process.

If you are working on large monitors, it can happen that the font size in the editor is small and you need to give effort to read the labels in the editor.

You can resize the font by going to Window -> Developer Tools -> Widget Reflector:

Img 7
In the Widget Reflector tab you can change the Application Scale, I usually set mine at 1.16:
 
Img 8


Creating The Gameplay Level And Setting Up The Input

Now that we resized the font in the editor, in the Content folder, Right Click -> Folder to create a new folder and name it Maps.

Btw, you can name the folder Maps, Levels, Scene, however you want, because they all refer to the same thing.

Next, click on File -> New Level:

Img 9

From the New Level window, select the Default level:

Img 10

Save the level by going to File -> Save Current, or hold CTRL + S, on MacOS CMD + S, name the level Gameplay and save the it in the Maps folder:

Img 11

In the World Outliner tab, select the Floor actor and delete it by pressing the Delete button on your keyboard:

Img 12

From the Content -> Geometry -> Meshes, drag the TemplateFloor mesh in the level:

Img 13

In the World Outliner rename the TemplateFloor to Floor, and change the values for the Location and Scale in the Transform component:

Img 14

Next, go to Edit -> Project Settings:

Img 15
From the Project Settings tab, click on Input on the left side and set the following for the Action Mappings and Axis Mappings:
 
Img 16

If you need help with setting up the input, you can follow this guide by clicking here.

Since this is a side scroller game, we move the player character forward and backwards by using the A and D key, you can also add the Left Arrow and the Right Arrow keys if you wish, and we use Space to make him jump, and this all we need.

Runner Character C++ Class

Now that we set up everything we need, in the Content -> C++ Classes -> SideRunner, Right Click -> New C++ Class:

Img 17
Our new C++ class is going to inherit from the Character class, so from the new window select the Character class and press Next:
 
Img 18
Name the new class RunnerCharacter and press Create Class:
 
Img 19

When the class is created, it will automatically open in Visual Studio. You will notice that we have two files for the class, RunnerCharacter.h and RunnerCharacter.cpp:

Img 20

We already talked about this in the lecture about classes and objects, and we explained that the .h and the .cpp file represent one class.

In the .h file we model the behavior of a class e.g. we declare the variable and functions that the class will have.

And in the .cpp file we implement those functionalities e.g. code the functions to do specific operations, use the declared variables for their purpose and so on.

Forward Declaration And Avoiding #include

Open the RunnerCharacter.h file, and at the bottom of the class declare the following variable:

				
					UPROPERTY(VisibleAnywhere)
		class UCameraComponent* SideViewCamera;
				
			

Let’s break down the lines we wrote one by one.

The UPROPERTY is a C++ macro that basically helps with things like exposing those variables you define to blueprints, and then we can access those variables in the Details tab.

The VisibleAnywhere parameter that we passed in the UPROPERTY Indicates that this property(variable) is visible in all property windows, but cannot be edited.

The UCameraComponent is a class that represents the camera object that we can place in the level, the * after the UCameraComponent denotes that this variable is a pointer, and the name of that variable is SideViewCamera.

The class keyword in front of the UCameraComponent is used to forward declare the UCameraComponent variable. The reason for that is, because we are declaring a variable of type UCameraComponent in the RunnerCharacter class.

The RunnerCharacter class doesn’t know of the existence of UCameraComponent class. The way that we inform the RunnerCharacter class of the existance of UCameraComponent class is in two ways.

The first way is to use the #include keyword and include the UCameraComponent at the top of the class file where you see the other includes:

				
					#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "RunnerCharacter.generated.h"

// INCLUDING THE CAMERA COMPONENT SO THAT
// THE RunnerCharacter CLASS IS AWARE
// OF ITS EXISTANCE
#include "Camera/CameraComponent.h"
				
			
The second way is what we did, add the class keyword in front of the class that you want to include in the file:
 
				
					UPROPERTY(VisibleAnywhere)
		class UCameraComponent* SideViewCamera;
				
			
So what is the difference between the two?
 
For starters, when we use the #include, we include the .h file of the class that we want. This means that we include all the declarations(variables and functions) of that .h file.
 
This is something we want to avoid doing in a .h file, because if we only need to declare a variable so that we can use it in the .cpp file, we don’t need to import all of the declarations of that variable.
 
In our case, we only need to declare the UCameraComponent in the .h file so that we can use it in the .cpp file, we don’t need to import all variables and functions that are defined in the UCameraComponent in the RunnerCharacter.h file.
 
Further more, if we want to use the RunnerCharacter class in another class, we would need to import the RunnerCharacter.h file. When we do this, we will import all the declarations we made in the RunnerCharacter.h file, plus all the h imports we have in the RunnerCharacter file, and this can get ugly when your project gets larger. This will lead to longer compile times, and ultimately slow down your project.
 
To avoid all this, instead of using the #include, we use the class in front of the variable and this way we inform the class where we are declaring the variable of the existence of the variable type that we are declaring, but we don’t import all the declarations that the class has.
 
So when we use:
 
				
					UPROPERTY(VisibleAnywhere)
		class UCameraComponent* SideViewCamera;
				
			
We inform the RunnerCharacter class of the existence of the UCameraComponent and we can declare it, but we don’t import all of its declarations. This is really important to know from the very start so that we don’t make mistakes that will be tedious to fix later.
 

Declaring And Implementing Functions And Compiling Our Code

Moving forward, we can declare the rest of the variables that we will use in our RunnerCharacter class. Below the declaration of the SideViewCamera variable, add the following lines of code:

				
					protected:

	void MoveRight(float Value);

public:

	void RestartLevel();

	UFUNCTION()
		void OnOverlapBegin(UPrimitiveComponent* OverlappedComp,
			AActor* OtherActor, UPrimitiveComponent* OtherComp,
			int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);

private:

	float zPosition;
	FVector TempPos = FVector();

	bool CanMove;
				
			

The MoveRight function will be used to move the player actor left and right, or forward and backwards since this is a side scroller game.

The RestartLevel function is self explanatory.

The OnOverlapBegin is the function that will inform us when we collide with other actors. This is how we are going to test if the player actor collides with the spike or the wall that is chasing him to end the game.

The zPosition variable will be used to determine the offset between the camera and the player actor.

The TempPos variable is used to store a temporary reference to the player actor’s position.

And the CanMove variable is going to control if we can move the player actor in the game or not.

Don’t forget to create definitions inside the RunnerCharacter.cpp file for the functions that we declared in the RunnerCharacter.h file:

				
					void ARunnerCharacter::MoveRight(float Value)
{
}

void ARunnerCharacter::RestartLevel()
{
}

void ARunnerCharacter::OnOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, 
	UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
}
				
			

You can either copy the code above and paste it in your RunnerCharacter.cpp file, or you can follow this guide by clicking here that will show a shortcut for creating function definitions in the .cpp file.

Now we can compile our code. To do that, you can hold CTRL + SHIFT + B, or you can go to Build -> Build Solution:

Every time we write new code or we make any changes to the existing code, we need to compile it the same way you saw in the preview above so that those changes will reflect in the Unreal Engine editor.

This is really important, because if we don’t compile the code, we will not be able to use it in Unreal Engine editor.

For example, if we create the player actor’s jump functionality but we don’t compile the code in Visual Studio, the player actor will not be able to jump when we test the game in the editor.

We can also compile the code in Unreal Engine editor by pressing the Compile button located in the Toolbar:

Before we move to the next section in this tutorial, I will leave the full code that we wrote so far for the .h and .cpp file of the RunnerCharacter class.

You can use this as a reference to compare your code with mine, just to make sure that everything is in order and you didn’t make any mistake.

RunnerCharacter.h:

				
					#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "RunnerCharacter.generated.h"

UCLASS()
class SIDERUNNER_API ARunnerCharacter : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	ARunnerCharacter();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

	UPROPERTY(VisibleAnywhere)
		class UCameraComponent* SideViewCamera;

protected:

	void MoveRight(float Value);

public:

	void RestartLevel();

	UFUNCTION()
		void OnOverlapBegin(UPrimitiveComponent* OverlappedComp,
			AActor* OtherActor, UPrimitiveComponent* OtherComp,
			int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);

private:

	float zPosition;
	FVector TempPos = FVector();

	bool CanMove;

};
				
			
RunnerCharacter.cpp:
 
				
					#include "RunnerCharacter.h"

// Sets default values
ARunnerCharacter::ARunnerCharacter()
{
 	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void ARunnerCharacter::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void ARunnerCharacter::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

// Called to bind functionality to input
void ARunnerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

}

void ARunnerCharacter::MoveRight(float Value)
{
}

void ARunnerCharacter::RestartLevel()
{
}

void ARunnerCharacter::OnOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, 
	UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
}

				
			


Adding #include In The .CPP File Of The Class

Now that we declared all the variables and functions that we need, and we created the definitions of the functions, we can start adding the functionality code to the script.
 
Go in the RunnerCharacter.cpp file and the first that we will do is add the includes for the classes we intent to use. Above the class declaration, add the following lines of code:
 
				
					#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
				
			
“So, what is this teacher? First you say don’t use #include now you are using it, are you crazy?”
 
Well, I am glad that you asked that question handsome stranger.
 
In the Forward Declaration And Avoiding #include section of this tutorial, we mentioned that you always want to use forward declaration and avoid the use of #include, but is for the .h file, because when we want to use a specific class, and I say use I mean use its variables and functions, we import that class using its .h file.
 
In the .cpp file however, we implement all the functionality that we declared in the .h file, so there is no harm to use #include in the .cpp file.
 
Besides, if we don’t include the .h file of the class we intent to use, then we will not be able to use it.
 

How To Know What To Include?

Looking at the lines of code that include the classes you are probably wondering how can you know what to type to include the CameraComponent class, or any other class.
 
That is pretty easy to figure out. Just go on Unreal Engine’s API reference web page by clicking here. You can also google this by typing in the search “unreal engine api” and click on the first link.
 
On the API webpage, use the search bar at the top right corner and type the name of the class that you are searching. For example I can type “UCameraComponent”:
Img 21
Press Enter on your keyboard for the search to start, and from the results click on the first link:
 
Img 22

When you do that, on the next page scroll down until you find the #include of the specific class that you are looking for:

Img 23

The code you see in the red rectangle is what you need to copy and paste in the .cpp file to include the specific class.

This way, you can easily find the include for any class that you will use in your projects.

Coding The RunnerCharacter.cpp Class

Going back to our RunnerCharacter.cpp class. Let’s explain the includes that we wrote:

				
					#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
				
			
We already know what is the CameraComponent.h so we will skip that. The CapsuleComponent.h will allow us to to use the functionality of the Capsule Component class.
 
We need this because we want to manipulate the Capsule Component that comes with the Character class we inherited.
 
The CharacterMovementComponent.h is the component that controls the movement of the Actor. It comes with the Character class we inherited and it has options that will affect the speed, jump force, and other walk and run related properties.
 
Now that we got that out of the way, let us initialize all the variables that we need. Inside the ARunnerCharacter() constructor, add the following lines of code:
 
				
					ARunnerCharacter::ARunnerCharacter()
{
 	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	GetCapsuleComponent()->InitCapsuleSize(42.f, 96.f);

	SideViewCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("Side View Camera"));
	SideViewCamera->bUsePawnControlRotation = false;

	GetCharacterMovement()->bOrientRotationToMovement = true;
	GetCharacterMovement()->RotationRate = FRotator(0.0f, 720.0f, 0.0f);

	GetCharacterMovement()->GravityScale = 2.0f;
	GetCharacterMovement()->AirControl = 0.8f;
	GetCharacterMovement()->JumpZVelocity = 1000.0f;
	GetCharacterMovement()->GroundFriction = 3.0f;
	GetCharacterMovement()->MaxWalkSpeed = 600.0f;
	GetCharacterMovement()->MaxFlySpeed = 600.0f;

	TempPos = GetActorLocation();
	zPosition = tempPos.Z + 300.0f;

}
				
			
Let’s break down the code we wrote line by line.
 
Line 6: First we get the reference to the Capsule component and set its initial size for the width and the height.
 
Line 8: We use the CreateDefaultSubobject function to create the Camera component. Inside the <> we pass the type of the object we want to create, in our case the Camera component, and using the TEXT we pass the name of that object which will be visible in the blueprint editor.
 
Line 10: We get the reference to the CharacterMovement component and we specify that the actor who is holding the CharacterMovement component should rotate towards the direction he is moving.
 
Line 11: We use the rotation rate e.g the rate by which the CharacterMovement component will rotate. The player actor is only going to rotate on the Y axis that is why we used 0 value for X and Z.
 
Line 13: We set the gravity scale to 2, which determines how gravity affects the player actor. 1 is normal gravity, 2 means the gravity will affect the player actor twice as much.
 
Line 14: We set the air control to 0.8 which affects the control the player actor has of its movement while in the air.
 
Line 15: Jump velocity is set to 1000, which is basically the jump force of the actor.
 
Line 16: Ground friction is set at 3, which affects the friction between the ground and the actor.
 
Line 17 and 18: Max walk speed is self explanatory as well as max fly speed. One affects the speed of the player actor the other affects the speed of the player while in the air.
 
Line 21: We store the current position of the player actor in the TempPos variable.
 
Line 22: We set the value of zPosition to the current position of TempPos.Z + 300, which means the offset of the camera from the player actor is going to be 300.
 
The movement of the player actor will happen in the MoveRight function, so inside add the following lines of code:
 
				
					void ARunnerCharacter::MoveRight(float Value)
{
	if (CanMove)
		AddMovementInput(FVector(0.0f, 1.0f, 0.0f), Value);
}
				
			

We use the CanMove bool variable to control if the player actor can move. When CanMove is true, then we can move, when CanMove is false which will happen when the player actor collides with an obstacle, then we will not be able to move.

Inside the BeginPlay function we need to set the CanMove to be true because when the game starts the player actor will be able to move:

				
					void ARunnerCharacter::BeginPlay()
{
	Super::BeginPlay();

	CanMove = true;
	
}
				
			

To make this work, we need to bind the MoveRight function to the input that we set up. In the SetupLayerInputComponent function add the following lines of code:

				
					void ARunnerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
	PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);

	PlayerInputComponent->BindAxis("MoveRight", this, &ARunnerCharacter::MoveRight);

}
				
			

We use BindAction function from the InputComponent class to bind functions from our class to the actions we defined in Project Settings -> Input. And we use BindAxis to bind functions to the axis we defined in Input settings:

Img 24
We use the built in Jump function that is defined in the Character class that we inherited from, and bind it to the Jump action we set up in the Input.
 
On line 5 we use the IE_Pressed parameter which means that the function will be executed when we press the button that triggers the Jump action, and on line 6 we use IE_Released which means the function will be called when we release the button that triggers the Jump action.
 
And you can see that when we press the button we will call the Jump function defined in the Character class, and when we release it, we will call the StopJumping function also defined in the Character class.
 
And when we press the buttons that trigger the MoveRight axis mapping, we will call the MoveRight function defined in the RunnerCharacter class.
 
When we pass the mapping names as parameters, it needs to match the case name we defined in the action or axis mappings in the input. If we defined an axis mapping like MoveRight, then in the code we also need to call MoveRight:
 
Img 25

If we type moveRight, it will not work because we typed m with lower case but we defined it with capital M, this is really important to keep in mind.

The last step is to make the camera follow the player actor which is going to happen in the Tick function:

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

	TempPos = GetActorLocation();
	TempPos.X -= 850.0f;
	TempPos.Z = zPosition;
	SideViewCamera->SetWorldLocation(TempPos);
}
				
			

The Tick function is called every frame and you can use it to update any part of your game that needs to be updated while the game is running, such as the camera that is following the player in this case.

Before we proceed make sure that you compile the code using CTRL + B or Build ->Build Solution.

As we already mentioned, we need to do this every time we make a change to the class.

Creating The Runner Character Blueprint

While the RunnerCharacter class is ready, we can’t test the game until we create a blueprint from that class.

The blueprint will represent the RunnerCharacter actor in the game because we can’t add a class in the game, we need to create a blueprint from the class, and use that blueprint in the game. That blueprint will have all the functionality we created in the class.

Before we do this, first we are going to create a new folder in the Content top hierarchy. Right Click -> New Folder and name it Blueprints.

In the Blueprint folder, Right Click -> Blueprint Class and from the Pick Parent Class window, click on the drop down list for all classes and search for the RunnerCharacter class and select the RunnerCharacter class that we created and click on the Select button:

Img 26
When the blueprint is created name it BP_RunnerCharacter and open it in the blueprint editor.
 
Since we inherited the Character class we already have the Capsule component, Skeletal Mesh component and the Character Movement component available at our disposal:
 
Img 27
You can also see the Capsule component in the Viewport tab:
 
Img 28
If you followed any Unreal Engine tutorial you probably already saw this, but when we are working with code and accessing these components via code we don’t see them visually, and since I am assuming that this is your first C++ tutorial with Unreal Engine that is why I am showing you the components that we accessed in the code in the previous steps of this tutorial.
 
Another component that you noticed is the Camera component that we created in the code. You can see the name of the component is Side View Camera, the same name we set in the code, and the camera is also visible in the Viewport tab:
 
Img 29

Moving forward, select the Mesh component in the Components tab and under the Mesh settings in the Details tab, for the Skeletal Mesh select the SK_Mannequin model that is available from the third person project files:

Img 30
Set the Z Location and Z Rotation to -90 for the Mesh component:
 
Img 31

In the Animation settings in the Details tab, click on the Anim Class drop down list and select the ThirdPerson_AnimBP as the animator blueprint for the Mesh component:

Img 32

Make sure that you Compile and Save all the changes we make, and when you do that you will see how the character is being animated in the Viewport window:

Img 33


Side Runner Game Mode Blueprint

If we run the game now we will see the default player actor that comes with the Third Person project in the level. In order to place our own actor that we just created, e.g. BP_RunnerCharacter, we need to create a custom game mode.

If you don’t know what is a game mode and what is the purpose of game modes, then please, before you proceed with the tutorial, learn about that concept by clicking here.

Inside the Content -> Blueprints folder, Right Click -> Blueprint Class. Inside the pop up window in the search bar filter for game mode and select the GameMode class from the list:

Img 34

Name the new blueprint BP_SideRunner_GameMode. Next, go to Edit -> Project Settings -> Maps & Modes, and under the Default Modes select the BP_SideRunner_GameMode and for the Default Pawn Class select the BP_RunnerCharacter:

Img 35

Now we run the game and test it out:

So we have our BP_RunnerCharacter player actor in the level, he can move, jump, and the camera is following him.

The camera is using the offset we defined in the RunnerCharacter.cpp class using the ZPosition variable. You can play with the offset value and test the game to see the different outcomes that you will get.

You can also change the value of the CanMove variable to false and try to move the player actor and see that he will not be able to move.

I am mentioning these small changes to get you used to experimenting with projects and changing things around to see the outcome. This is the best way to learn and the fastest way to understand how things work in Unreal Engine and C++.

We do have one problem when it comes to the player actor, and that is, he is not facing the direction where is going, instead he looks in one direction, and because of that his back is always turned towards the camera.

Rotating The Player Actor In The Moving Direction

To fix the rotation issue we need to open the BP_RunnerCharacter in the editor.

In the Components window select the BP_RunnerCharacter(self):

Img 36

In the Details tab under Pawn settings, uncheck the checkbox for Use Controller Rotation Yaw:

Img 37
Compile and Save the new changes and let’s test the game again:
 


Where To Go From Here

In this tutorial we created the RunnerCharacter class and modeled the behaviour of the player actor. We also created a blueprint out of that class and tested the player’s movement in the level.

In the next part titled Creating Obstacles And Level Parts For Our Game we will create C++ classes for the obstacles and level parts for our game, and we will create blueprints out of those classes.

Leave a Comment

With a FREE Awesome Tuts account

you can download assets and project files, bookmark your favorite posts and more

Already have an account? Sign in