알라딘MGG와이드바


[UE4] SideRunner Practice

https://youtu.be/RzzpIp1XbX4 를 따라서 구현.

///////////////////////////////////////////////////////////////////////////
// UCLASS() 의 기본값은 NotBlueprintable.
// 그러나 AActor 는 Blueprintable 이고 Blueprintable 속성은 파생클래스에게도 적용되므로 ABaseLevel 도 Blueprintable 이다.
UCLASS()
class SIDERUNNER2_API ABaseLevel : public AActor {
GENERATED_BODY()

public:
ABaseLevel();

protected:
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "My Triggers")
USceneComponent* DefaultSceneRoot;

UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "My Triggers")
UBoxComponent* Trigger;

UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "My Triggers")
UBoxComponent* SpawnLocation;

public:
UBoxComponent* GetTrigger() { return Trigger; }
UBoxComponent* GetSpawnLocation() { return SpawnLocation; }
};

///////////////////////////////////////////////////////////////////////////
ABaseLevel::ABaseLevel() {
// DefaultSceneRoot 없이 바로 Trigger 를 Root 로 만들면
// BP -> Details 에서 Scale, Location 값을 변경할 수 없다.
DefaultSceneRoot = CreateDefaultSubobject<USceneComponent>(TEXT("DefaultSceneRoot"));
SetRootComponent(DefaultSceneRoot);

Trigger = CreateDefaultSubobject<UBoxComponent>(TEXT("Trigger"));
Trigger->AttachToComponent(DefaultSceneRoot, FAttachmentTransformRules::KeepRelativeTransform);

SpawnLocation = CreateDefaultSubobject<UBoxComponent>(TEXT("SpawnLocation"));
SpawnLocation->AttachToComponent(DefaultSceneRoot, FAttachmentTransformRules::KeepRelativeTransform);
}

///////////////////////////////////////////////////////////////////////////
UCLASS()
class SIDERUNNER2_API ARunnerCharacter : public ACharacter {
GENERATED_BODY()

UPROPERTY(VisibleAnywhere)
class UCameraComponent* SideViewCamera;

public:
ARunnerCharacter();

protected:
virtual void BeginPlay() override;
void MoveRight(float InValue);

public:
virtual void Tick(float DeltaTime) override;
void RestartLevel();
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

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

float ZPosition = 0.f;
bool CanMove = false;
};

///////////////////////////////////////////////////////////////////////////
ARunnerCharacter::ARunnerCharacter() {
PrimaryActorTick.bCanEverTick = true;

UCapsuleComponent* CapsuleCom = GetCapsuleComponent();
CapsuleCom->InitCapsuleSize(42.f, 96.f);
CapsuleCom->SetCollisionResponseToChannel(ECC_GameTraceChannel1, ECR_Overlap);

bUseControllerRotationPitch = false;
bUseControllerRotationRoll = false;
bUseControllerRotationYaw = false;

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

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

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

FVector TempPos = GetActorLocation();
ZPosition = TempPos.Z + 300.0f;
}

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

GetCapsuleComponent()->OnComponentBeginOverlap.AddDynamic(this, &ARunnerCharacter::OnOverlapBegin);

CanMove = true;
}

void ARunnerCharacter::MoveRight(float InValue) {
if (CanMove) {
AddMovementInput(FVector(0.0f, 1.0f, 0.0f), InValue);
}
}

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

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

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);
}

void ARunnerCharacter::RestartLevel() {
UGameplayStatics::OpenLevel(this, FName(*GetWorld()->GetName()));
}

void ARunnerCharacter::OnOverlapBegin(UPrimitiveComponent* OverlappedComp,
AActor* OtherActor, UPrimitiveComponent* OtherComp,
int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult) {
if (OtherActor) {
if (AWallSpike* WallSpike = Cast<AWallSpike>(OtherActor)) {
USkeletalMeshComponent* InMesh = GetMesh();
InMesh->Deactivate();
InMesh->SetVisibility(false);

CanMove = false;

FTimerHandle UnusedHandle;
GetWorldTimerManager().SetTimer(UnusedHandle, this, &ARunnerCharacter::RestartLevel, 2.f, false);
}
}
}

///////////////////////////////////////////////////////////////////////////
UCLASS()
class SIDERUNNER2_API ASpawnLevel : public AActor {
GENERATED_BODY()

protected:
virtual void BeginPlay() override;

public:
UFUNCTION()
void SpawnLevel(bool IsFirst);

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

protected:
UPROPERTY(EditAnywhere)
TArray<TSubclassOf<ABaseLevel>> LevelClasses;

TArray<ABaseLevel*> LevelList;
};

///////////////////////////////////////////////////////////////////////////
void ASpawnLevel::BeginPlay() {
Super::BeginPlay();

// 미리 레벨을 4개 스폰해 둔다.
SpawnLevel(true);
SpawnLevel(false);
SpawnLevel(false);
SpawnLevel(false);
}

void ASpawnLevel::SpawnLevel(bool IsFirst) {
if (LevelClasses.Num() <= 0) { return; }

FVector SpawnLocation = FVector(0.f, 1000.f, 0.f);
FRotator SpawnRotation = FRotator(0, 90, 0);

if (!IsFirst) {
ABaseLevel* LastLevel = LevelList.Last();
SpawnLocation = LastLevel->GetSpawnLocation()->GetComponentTransform().GetTranslation();
SpawnRotation = FRotator(0, 90, 0);
}

const int32 RandomLevel = FMath::RandRange(0, LevelClasses.Num() - 1);
FActorSpawnParameters SpawnInfo;
if (ABaseLevel* NewLevel = GetWorld()->SpawnActor<ABaseLevel>(LevelClasses[RandomLevel], SpawnLocation, SpawnRotation, SpawnInfo)) {
if (UBoxComponent* Trigger = NewLevel->GetTrigger()) {
Trigger->OnComponentBeginOverlap.AddDynamic(this, &ASpawnLevel::OnOverlapBegin);
}

LevelList.Add(NewLevel);
if (LevelList.Num() > 5) {
LevelList.RemoveAt(0);
}
}
}

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

///////////////////////////////////////////////////////////////////////////
UCLASS()
class SIDERUNNER2_API AWallSpike : public AActor {
GENERATED_BODY()

public:
AWallSpike();
virtual void Tick(float DeltaTime) override;
};

///////////////////////////////////////////////////////////////////////////
static TAutoConsoleVariable<float> CVarWallSpikeSpeed(TEXT("WallSpikeSpeed"), 350.f, TEXT(""));

AWallSpike::AWallSpike() {
PrimaryActorTick.bCanEverTick = true;
}

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

SetActorLocation(GetActorLocation() + FVector(0, CVarWallSpikeSpeed.GetValueOnGameThread() * DeltaTime, 0), true);
}


NuRi's Tools - iframe 변환기


덧글

댓글 입력 영역


Yes24위대한게임의탄생3

위대한 게임의 탄생 3
예스24 | 애드온2