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