Class GameDev* SheepAdult

[Unreal Engine C++] CheckPoint & Load Different Animation 본문

Unreal Project

[Unreal Engine C++] CheckPoint & Load Different Animation

SheepAdult 2022. 7. 12. 19:57

 최근에 글을 작성할 만한 게 없어서 올려보는 Check Point.. 다른 튜토리얼을 보고한 게 아니라 최적의 방법은 아닐 수 있지만 본인이 구현하며 그나마 나은 방법이다.

 

 게임 개발을 하다 보면 본인이 게임의 상황이나 애니메이션들에 신경을 많이 쓴다면 리스폰하거나 게임을 다시 시작할 경우 캐릭터가 스폰되는 모습을 체크포인트마다 다르게 주고 싶을 수 있다. 예를 들어 처음엔 활발했는데 맵을 진핼할수록 무기력한 모습이라든지 오히려 활기찬 모습이라든지,, 땅굴을 기어서 나온다든지 문을 박차고 나온다든지 원하는 로드가 다를 것이다. 그래서 체크포인트 액터마다 Enum값을 줘서 이를 달리해봤다.

 

 먼저 Enum 클래스를 하나 만들어서 사용했다. 처음엔 CheckPoint 액터 클래스에 Enum 클래스를 선언하고 사용하려다 보니, 다른 클래스의 헤더파일에서 사용하는 법을 몰라 아예 액터 클래스를 하나 팠다.(헤더에서 include를 하는 건 순환 include 오류를 발생시킬 수 있으니 말이다.) Enum 클래스 작성법은 구글에 널리고 널렸으니 간단하게 코드만 올리면 아래와 같다.

#pragma once

#include "CoreMinimal.h"

#include "MyEnums.generated.h"

UENUM(BlueprintType)
enum class ECheckPointRespawnType : uint8
{
	None UMETA(DisplayName = "None"),
	Crawling UMETA(DisplayName = "Crawling"),
	Getup UMETA(DisplayName = "Getup"),
	WalkIn UMETA(DisplayName = "WalkIn")
};

나는 리스폰 시 기어가는 모션, 일어나는 모션, 걸어들어오는 모션을 구분해서 구현했다. 이제 이를 CheckPoint에서 EditAnywhere로 받아 각 액터마다 지정해주고 캐릭터가 리스폰되거나 게임을 시작할 때 원하는 이벤트를 발생시키면 된다.

// CheckPoint.h
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Status)
		TEnumAsByte<ECheckPointRespawnType> CheckPointRespawnType;

// CheckPoint.cpp
// 체크포인트 액터와 캐릭터 충돌 시
GameInstance->CheckPointRespawnType = CheckPointRespawnType;

 코드의 많은 부분을 생략했지만 중요한 부분은 아니니 생략하고 설명하자면, 체크포인트 헤더파일에서 enum 클래스를 include 하고 선언해 준다. 그리고 체크포인트 액터와 캐릭터가 충돌하면 체크포인트의 Enum값을 GameInstance 내의 SaveGameObject 객체에 저장한다.(물론 게임 정보 저장 등은 Delegate를 사용해 원하는 정보들을 저장해주면 된다. https://sheep-adult.tistory.com/21) 참고로 아래는 내가 특정 체크포인트에 설정해 둔 Enum값이다.

해당 체크포인트에서 리스폰할 시 발생하는 이벤트이다.

 그럼 이제 Enum값마다 이벤트를 구현하면 된다. 캐릭터 코드에서 Reset()함수이다. 이 함수는 캐릭터가 죽어서 부활하거나 게임을 새로 시작하거나 이어하게 되면 호출되는 함수로 GameInstance에서 Reset시 Delegate로 호출되는 함수이다.

void AMainCharacter::Reset()
{
	switch (GameInstance->SaveGameData->SavePointType)
	{
	case ECheckPointRespawnType::None:
		break;
	case ECheckPointRespawnType::Crawling:
		if (M_CrawlingCorpse)
		{
			TriggerCapsuleComponent->SetRelativeRotation(FRotator(0, 90, 0));
			PlayAnimMontage(M_CrawlingCorpse);
			bIsControllable = false;
		}
		break;
	case ECheckPointRespawnType::Getup:
		SkeletalMesh->SetCollisionProfileName("CharacterMesh");
		SkeletalMesh->SetSimulatePhysics(false);
		TriggerCapsuleComponent->SetWorldLocation(SkeletalMesh->GetComponentLocation());
		SkeletalMesh->AttachToComponent(TriggerCapsuleComponent, FAttachmentTransformRules::SnapToTargetNotIncludingScale);
		SkeletalMesh->SetRelativeLocation(FVector(0, 0, -65));
		SkeletalMesh->SetRelativeRotation(FRotator(0, -90, 0));
		SetActorRotation(FRotator(0, 180, 0));
		PlayerController->SetControlRotation(FRotator(0, 0, 180.0f));
		SetActorRotation(FRotator(0.0f, 180.0f, 0.0f));
		PlayAnimMontage(M_RespawnStand);
		bIsControllable = false;
		break;
	case ECheckPointRespawnType::WalkIn:
		break;
	default:			
		break;
	}
}

각 case는 함수로 정리하면 좋았겠지만 그냥 한 번에 볼 수 있도록 올렸다. Reset()시 SaveGameObject에 저장된 Enum값에 따라 switch로 분류해서 작성했다. 개인적인 코드라 예제 정도이니 참고만 하면 좋을 것 같다. 참고로 나는 SaveGameObject에서 Crawling을 초기값으로 줘서 게임 새로 하기에서는 Crawling 애니메이션이 발생하게 했다.

 아래는 Crawling일 때(새로하기)와 Getup일 때(CheckPoint Enum값이 GetUp)의 경우이다.

Crawling
GetUp

 

 - 정리

최근엔 레벨 디자인이나 스토리에 신경쓰느라 코딩도 많이 못했고 해도 어렵지 않은 내용 반복에 특별히 배운 내용은 없어서 거의 두 달만에 글을 올린다. 이 글은 코드 좀 정리하면서 수정한 부분 중 한 부분으로 혹시라도 괜찮은 방법일 수도 있지 않을까 해서 올려본다.