게임 개발 (언리얼 엔진)

UE4 게임 개발 EscapeGame - 5 : 트리거 클래스 구성

종황이 2020. 11. 26. 00:26

트리거 클래스를 두가지로 구성하면 훨씬 다양한 기능을 연출할 수 있습니다.

1. 트리거 클래스

// TriggerBoxRock.h

#pragma once

#include "GameInfo.h"
#include "GameFramework/Actor.h"
#include "ObstacleRock.h"
#include "TriggerBoxRock.generated.h"

UCLASS()
class ESCAPEGAME_API ATriggerBoxRock : public AActor
{
	GENERATED_BODY()

public:	
	// Sets default values for this actor's properties
	ATriggerBoxRock();

protected:
	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
	class UBoxComponent* Box;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
	AObstacleRock* Rock;

	bool bRollEnable;

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

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

public:
	UFUNCTION()
	void TriggerBeginOverlap(
		UPrimitiveComponent* OverlappedComponent,
		AActor* OtherActor,
		UPrimitiveComponent* OtherComp,
		int32 OtherBodyIndex,
		bool bFromSweep,
		const FHitResult& SweepResult);

	UFUNCTION()
	void TriggerEndOverlap(
		UPrimitiveComponent* OverlappedComponent,
		AActor* OtherActor,
		UPrimitiveComponent* OtherComp,
		int32 OtherBodyIndex);

public:
	void RollRock(float DeltaTime);
	bool IsRoll();
};
// TriggerBoxRock.cpp


#include "TriggerBoxRock.h"

// Sets default values
ATriggerBoxRock::ATriggerBoxRock()
{
 	// 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;

	Box = CreateDefaultSubobject<UBoxComponent>(TEXT("Box"));

	SetRootComponent(Box);

	Box->SetCollisionProfileName(TEXT("Trigger"));

	Rock = nullptr;
}

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

	// 델리게이트에 함수 등록
	Box->OnComponentBeginOverlap.AddDynamic(this, &ATriggerBoxRock::TriggerBeginOverlap);
	Box->OnComponentEndOverlap.AddDynamic(this, &ATriggerBoxRock::TriggerEndOverlap);

	if (IsValid(Rock))
		Rock->GetRootComponent()->SetVisibility(false);
}

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

	if (IsRoll())
	{
		RollRock(DeltaTime);
	}
}

void ATriggerBoxRock::TriggerBeginOverlap(
	UPrimitiveComponent* OverlappedComponent,
	AActor* OtherActor,
	UPrimitiveComponent* OtherComp,
	int32 OtherBodyIndex,
	bool bFromSweep,
	const FHitResult& SweepResult)
{
	bRollEnable = true;

	if (IsValid(Rock))
		Rock->GetRootComponent()->SetVisibility(true);
}

void ATriggerBoxRock::TriggerEndOverlap(
	UPrimitiveComponent* OverlappedComponent,
	AActor* OtherActor,
	UPrimitiveComponent* OtherComp,
	int32 OtherBodyIndex)
{

}

void ATriggerBoxRock::RollRock(float DeltaTime)
{
	if (Rock->GetActorLocation().X > -1400) {
		Rock->SetActorLocation(FVector(Rock->GetActorLocation().X - 1000 * DeltaTime, Rock->GetActorLocation().Y, Rock->GetActorLocation().Z));
		Rock->AddActorLocalRotation(FRotator(DeltaTime * 250, 0.f, 0.f)); }
}

bool ATriggerBoxRock::IsRoll()
{
	if (bRollEnable)
	{
		return true;
	}
	else
	{
		return false;
	}
}

Box Component와 굴러올 돌의 액터를 가지고 있고, 델리게이트에 함수를 등록하고 오버랩 됐을 때, 호출할 함수를 정의해주면 됩니다.

굴러올 돌 액터는 UPROPERTY 형식으로 선언했으므로, 에디터상에서 편하게 설정해서 사용합니다.

 

2. 굴러올 돌 클래스

// ObstacleRock.h

#pragma once

#include "GameInfo.h"
#include "GameFramework/Actor.h"
#include "ObstacleRock.generated.h"

UCLASS()
class ESCAPEGAME_API AObstacleRock : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	AObstacleRock();

protected:
	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
	class UBoxComponent* Box;

	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
	class UStaticMeshComponent* Mesh;

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

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

public:
	UFUNCTION()
	void TriggerBeginOverlap(
		UPrimitiveComponent* OverlappedComponent,
		AActor* OtherActor,
		UPrimitiveComponent* OtherComp,
		int32 OtherBodyIndex,
		bool bFromSweep,
		const FHitResult& SweepResult);

	UFUNCTION()
	void TriggerEndOverlap(
		UPrimitiveComponent* OverlappedComponent,
		AActor* OtherActor,
		UPrimitiveComponent* OtherComp,
		int32 OtherBodyIndex);
};
// ObstacleRock.cpp


#include "ObstacleRock.h"
#include "MyPlayerCharacter.h"
#include "MyPlayerController.h"
#include "CameraShakeObstacle.h"

// Sets default values
AObstacleRock::AObstacleRock()
{
 	// 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;

	Box = CreateDefaultSubobject<UBoxComponent>(TEXT("Box"));
	Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));

	SetRootComponent(Box);

	Mesh->SetupAttachment(Box);

	Mesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);

	Box->SetSimulatePhysics(true);
	Box->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
	Box->SetCollisionProfileName(TEXT("Obstacle"));
}

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

	Box->OnComponentBeginOverlap.AddDynamic(this, &AObstacleRock::TriggerBeginOverlap);
	Box->OnComponentEndOverlap.AddDynamic(this, &AObstacleRock::TriggerEndOverlap);
}

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

}

void AObstacleRock::TriggerBeginOverlap(
	UPrimitiveComponent* OverlappedComponent,
	AActor* OtherActor,
	UPrimitiveComponent* OtherComp,
	int32 OtherBodyIndex,
	bool bFromSweep,
	const FHitResult& SweepResult)
{
	// 게임오버 시네마틱 영상 ON
	PrintViewport(1.f, FColor::Green, "Death"); 
	
	AMyPlayerController* pController = Cast<AMyPlayerController>(GetWorld()->GetFirstPlayerController());

	if (IsValid(pController))
	{
		AMyPlayerCharacter* pCharacter = Cast<AMyPlayerCharacter>(pController->GetPawn());

		if (IsValid(pCharacter))
		{
			pCharacter->GetController<AMyPlayerController>()->ClientPlayCameraShake(UCameraShakeObstacle::StaticClass(),
				1.f, ECameraAnimPlaySpace::CameraLocal);
			
			pCharacter->Death();
		}
	}
	
}

void AObstacleRock::TriggerEndOverlap(
	UPrimitiveComponent* OverlappedComponent,
	AActor* OtherActor,
	UPrimitiveComponent* OtherComp,
	int32 OtherBodyIndex)
{

}

 

플레이어와 돌이 닿았을 때, 카메라쉐이크하고, 게임오버시킵니다.
대부분의 트리거가 디테일만 조금씩 다르지, 이러한 방식으로 동작합니다.  

게임오버 영상은 생각해봐야하고, 카메라쉐이크는 다음 글에 자세히 정리하겠습니다.