게임 개발 (언리얼 엔진)

UE4 생존게임 제작 - 14 (트리거 시스템 제작)

언린이 2020. 11. 15. 16:55

1. 플레이어 감지를 위한 프로파일 생성

 

 

프로파일을 생성한 후, 플레이어와만 Overlap이 발생하도록 설정하였습니다.

 

 

2. 프로파일을 설정할 액터 생성

 

protected:
	UPROPERTY(Category = Collision, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
	UBoxComponent* TriggerBox;

 

ATriggerMoisture::ATriggerMoisture()
{
	PrimaryActorTick.bCanEverTick = true;

	TriggerBox = CreateDefaultSubobject<UBoxComponent>(TEXT("TriggerBox"));
	SetRootComponent(TriggerBox);

	// 프로파일 지정
	TriggerBox->SetCollisionProfileName(TEXT("TriggerMoisture"));
	TriggerBox->SetBoxExtent(FVector(20.f, 20.f, 20.f));
	TriggerBox->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
}

 

박스 컴포넌트를 선언한 후, 생성자에서 박스 컴포넌트를 액터의 Root에 붙이고 만들어둔 프로파일로 지정하였습니다.

 

 

public:
	// 충돌이 시작할시에 호출되는 델리게이트에 등록하는 함수
	UFUNCTION()
	void TriggerMoistureBeginOverlap(UPrimitiveComponent* OverlappedComponent,
		AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex,
		bool bFromSweep, const FHitResult& SweepResult);

	// 충돌이 종료될시에 호출되는 델리게이트에 등록하는 함수
	UFUNCTION()
	void TriggerMoistureEndOverlap(UPrimitiveComponent* OverlappedComponent,
		AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);

 

void ATriggerMoisture::BeginPlay()
{
	Super::BeginPlay();
	
	// 델리게이트에 생성한 함수 등록
	TriggerBox->OnComponentBeginOverlap.AddDynamic(this, &ATriggerMoisture::TriggerMoistureBeginOverlap);
	TriggerBox->OnComponentEndOverlap.AddDynamic(this, &ATriggerMoisture::TriggerMoistureEndOverlap);
}

 

그리고 나서 Overlap이 시작할 때 실행될 델리게이트와 끝날 때 실행될 델리게이트에 등록할 함수를 선언한 후, BeginPlay 함수에서 등록해주었습니다.

 

 

3. 트리거 배치

 

 

지금까지 제작한 액터를 블루프린트로 생성하였습니다.

 

 

 

블루프린트에서 박스 컴포넌트의 크기를 설정한 후,

 

 

 

월드에 배치하였습니다.

이제 트리거 배치가 끝났으니 트리거의 기능을 구현하도록 하겠습니다.

 

 

4. 트리거 기능 구현

 

먼저 트리거를 만든 이유는 플레이어의 수분 게이지는 계속해서 일정한 속도로 줄어들며 0이 되면 플레이어는 죽게 됩니다. 그래서 수분 게이지를 증가시킬 기능이 필요했고 트리거를 만들게 된 것입니다.

트리거의 기능은 플레이어가 트리거 박스 내부에 있다면 플레이어의 수분 게이지를 일정한 속도로 증가시키는 것입니다.

 

 

	bool bMoistureUp;

 

	bMoistureUp = false;

 

먼저 bool 변수를 선언하고 false로 초기화해주었습니다.

 

 

	if (bMoistureUp)
	{
		MoistureUpDuration += DeltaTime;

		// 오아시스에 있을 시에 수분 게이지 증가
		if (MoistureUpDuration >= MoistureUpMax)
		{
			MoistureUpDuration = 0.f;

			SurvivorState.iMoisture += 2;

			// 수분이 100보다 클시에 100으로 설정
			if (SurvivorState.iMoisture >= 100)
				SurvivorState.iMoisture = 100;

			SurvivorStateWidget->SetMoisture(SurvivorState.iMoisture / (float)SurvivorState.iMoistureMax);
		}

		MoistureDuration = 0.f;
	}
	else
	{
		MoistureDuration += DeltaTime;

		// 오아시스에 있지 않을 시에 시간이 지남에 따라 수분 게이지 감소
		if (MoistureDuration >= MoistureMax)
		{
			MoistureDuration = 0.f;

			SurvivorState.iMoisture -= 10;

			// 수분이 0보다 작을 시에 0으로 설정
			if (SurvivorState.iMoisture <= 0)
				SurvivorState.iMoisture = 0;

			SurvivorStateWidget->SetMoisture(SurvivorState.iMoisture / (float)SurvivorState.iMoistureMax);
		}

		// 수분 게이지가 0이 되면 플레이어 사망
		if (SurvivorState.iMoisture <= 0)
		{
			if (IsValid(SurvivorController))
			{
				// 플레이어 사망시 컨트롤러 중지
				SurvivorController->EndPlay(EEndPlayReason::Quit);
			}

			GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision);

			if (IsValid(SurvivorAnim))
				SurvivorAnim->SetAnimType(ESurvivorAnim::Death);
		}
	}

 

그리고 나서 플레이어의 Tick 함수에 구현한 부분입니다.

선언한 bool 변수가 true일 경우 수분 게이지를 일정한 속도로 증가시키고 false일 경우 수분 게이지를 일정한 속도로 감소시켰습니다.

 

 

void APlayerSurvivor::SetMoistureUp(bool MoistureUp)
{
	bMoistureUp = MoistureUp;
}

 

그 다음에 다른 클래스에서 해당 bool 변수를 변화시킬 수 있도록 플레이어 클래스에 SetMoistureUp 함수를 만들어주었습니다.

이제 이 함수를 트리거 클래스에서 호출해주면 됩니다.

 

 

// Overlap이 시작할 때 호출되는 함수
void ATriggerMoisture::TriggerMoistureBeginOverlap(UPrimitiveComponent* OverlappedComponent,
	AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex,
	bool bFromSweep, const FHitResult& SweepResult)
{
	APlayerSurvivor* Survivor = Cast<APlayerSurvivor>(OtherActor);

	// Overlap이 시작되면 플레이어의 bMoistureUp 변수를
	// true로 세팅해줘서 수분 게이지가 증가하도록 한다
	if (IsValid(Survivor))
		Survivor->SetMoistureUp(true);
}

// Overlap이 끝날 때 호출되는 함수
void ATriggerMoisture::TriggerMoistureEndOverlap(UPrimitiveComponent* OverlappedComponent,
	AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
	APlayerSurvivor* Survivor = Cast<APlayerSurvivor>(OtherActor);
	
	// Overlap이 끝나면 플레이어의 bMoistureUp 변수를
	// false로 세팅해줘서 수분 게이지가 감소하도록 한다
	if (IsValid(Survivor))
		Survivor->SetMoistureUp(false);
}

 

Overlap이 시작할 때 호출되는 델리게이트에 등록한 함수에서는 bool 변수를 true로 바꿔주었고,

Overlap이 끝날 때 호출되는 델리게이트에 등록한 함수에서는 bool 변수를 false로 바꿔주었습니다.

이제 플레이어는 트리거 박스와 Overlap 중에는 수분 게이지가 증가할 것이고 Overlap이 끝나면 수분 게이지가 감소할 것입니다.

 

 

 

오아시스 외부에서는 수분 게이지가 감소하는 모습을 확인할 수 있습니다.

 

 

 

그리고 오아시스 내부에서는 수분 게이지가 증가하는 모습을 확인할 수 있습니다.

 

 

다음에 해야할 일

 

다양한 UI 제작 및 다양한 사운드 처리