[C++ Video Tutorial] How to start coding a game like Temple Run

Here is a short video tutorial on how to start coding a simple “Temple Run” like game.

It creates the track “procedurally”. I’ll add a tutorial on how to add other game objects to collect and interact with next.

Here is the link to the video in case you can’t see the embedded video properly on your mobile device: Unreal Engine C++ Tutorial - Temple Run - YouTube

And here is the code used in the video:

Floor.h

Add this after “GENERATED_BODY()”:


	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Enemy, meta = (AllowPrivateAccess = "true"))
	UStaticMeshComponent* FloorMeshComponent;

Floor.cpp:

Change the constructor as follows:


AFloor::AFloor()
{
	static ConstructorHelpers::FObjectFinder<UStaticMesh> RockMesh(TEXT("/Game/ThirdPerson/Meshes/CubeMesh.CubeMesh"));

	// Create the mesh component
	FloorMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Ground"));
	RootComponent = FloorMeshComponent;
	FloorMeshComponent->SetCollisionProfileName(UCollisionProfile::Pawn_ProfileName);

	FloorMeshComponent->SetStaticMesh(RockMesh.Object);

	FloorMeshComponent->SetWorldScale3D(FVector(2.0F, 2.0F, 0.2F));

 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

SkyRunCharacter.h

Add these private members after the line “GENERATED_BODY()


	//New
	/** Spring arm that will offset the camera */
	UPROPERTY(Category = Camera, VisibleDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
	USpringArmComponent* SpringArm;

	/** Camera component that will be our viewpoint */
	UPROPERTY(Category = Camera, VisibleDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
	UCameraComponent* Camera;
	//end new

	//new 2
	int direction;
	bool canTurnRight;

	//new 4
	FVector floorPosition;
	int frameCount;
	FVector floorDirection;

And add these protected functions


	// new 2
	void ChangeDirection(float Value);

	//new 3
	virtual void Tick(float DeltaSeconds);

	//new 4
	void updateFloorDirection(FVector& direction);

**
SkyRunCharacter.cpp**

Add this to the constructor:


//new 2
	direction = 0;//direction player is facing (values 0 to 3)
	canTurnRight = true;//used to prevent the player turning more than 90 degrees on a single key press
	//end new 2

	//new 4
	floorDirection = FVector(1, 0, 0);//Start in the positive x direction
	floorPosition = FVector(2000, 0, -200);//initial floor position
	frameCount = 0;//use to count number of frames since last floor piece was created - see Tick() function below
	//end new 4

and this:


	//new
	GetCharacterMovement()->MaxWalkSpeed = 800.0F;

	SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
	SpringArm->SetRelativeLocation(FVector(0.0f, 0.0f, 54.0f));
	SpringArm->SetWorldRotation(FRotator(-20.0f, 0.0f, 0.0f));
	SpringArm->AttachTo(RootComponent);
	SpringArm->TargetArmLength = 525.0f;
	SpringArm->bEnableCameraLag = false;
	SpringArm->bEnableCameraRotationLag = false;
	SpringArm->bInheritPitch = true;
	SpringArm->bInheritYaw = true;
	SpringArm->bInheritRoll = true;

	// Create the chase camera component 
	Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("ChaseCamera"));
	Camera->AttachTo(SpringArm, USpringArmComponent::SocketName);
	Camera->SetRelativeRotation(FRotator(10.0f, 0.0f, 0.0f));
	Camera->bUsePawnControlRotation = false;
	Camera->FieldOfView = 90.f;

	//end new

In SetupPlayerInputComponent(), change these lines:


	//InputComponent->BindAxis("MoveForward", this, &AJungleRunCharacter::MoveForward);
	InputComponent->BindAxis("MoveRight", this, &ASkyRunCharacter::ChangeDirection);//new 3

And add these functions at the end of the file:


//new 3
void ASkyRunCharacter::Tick(float DeltaSeconds) {
	Super::Tick(DeltaSeconds);

	if (direction == 0)
		MoveForward(1);
	else if (direction == 2)
		MoveForward(-1);
	else if (direction == 1)
		MoveRight(1);
	else if (direction == 3)
		MoveRight(-1);

	//new 4
	AFloor *myFloor;

	UWorld* const World = GetWorld();
	if (World && frameCount++ > 15) {
		frameCount = 0;
		FVector SpawnLocation = floorPosition;// GetActorLocation() + FVector(0, newCount * 100, -5);
		floorPosition += floorDirection * 400;
		updateFloorDirection(floorDirection);
		const FRotator FloorRotation = FRotator(0, 0, 0);
		myFloor = World->SpawnActor<AFloor>(SpawnLocation, FloorRotation);
	}
	//end new 4
}
//end new 3

//new 2
void ASkyRunCharacter::ChangeDirection(float Value)
{
	if (Value != 0 && canTurnRight) {
		canTurnRight = false;
		direction += Value;
		if (direction > 3)
			direction = 0;
		else if (direction < 0)
			direction = 3;
	}
	else if (Value == 0)
		canTurnRight = true;
}
//end new 2

//new 4
void ASkyRunCharacter::updateFloorDirection(FVector& direction) {

	float zChange = 0.0F;//used to randomly change the height of the floor piece

	int randNum1 = rand() % 15;
	int randNum2 = rand() % 10;
	if (randNum2 > 7)
		zChange = 0.1;
	else if (randNum2 > 4)
		zChange = -0.1;

	switch (randNum1) {

	case 4:
		if (floorDirection.X != -1)
			floorDirection = FVector(1, 0, zChange);
		break;
	case 12:
		if (floorDirection.Y != 1)
			floorDirection = FVector(0, -1, zChange);
		break;
	case 8:
		//newCount = 0;
		if (floorDirection.X != 1)
			floorDirection = FVector(-1, 0, zChange);
		break;
	case 0:
		if (floorDirection.Y != -1)
			floorDirection = FVector(0, 1, zChange);
		break;
	}

}
//end new 4

Hope it helps.

Edit: added the code

For anyone who would like to try this tutorial, I added the code used in the video to the opening post.

Looked very interesting, you can follow the video to do something

I’m missing something becuase even the first part isnt working for me to try to lock the camera :confused:

Some of the code like AttachTo(RootComponent) function was deprecated, you should use AttachToComponent, at least if you are using UE 4.14.
I am now trying to debug IntroRunCharacter.cpp below, as it does not seem to accept the second parameter USpringArmComponent::SocketName

cannot convert argument 2 from ‘const FName’ to ‘const FAttachmentTransformRules &’

Try using the following

SpringArm->AttachToComponent(RootComponent, FAttachmentTransformRules::SnapToTargetNotIncludingScale);

and

Camera->AttachToComponent(SpringArm, FAttachmentTransformRules::SnapToTargetNotIncludingScale, USpringArmComponent::SocketName);