[89. Changing Levels in Game]

 

UGameplayStatics::OpenLevel을 이용해서 레벨을 바꿀 수 있다.

 

UGameplayStatics::OpenLevel(World, LevelName);

 

[90. Saving the Game]

 

레벨이 전환된다는 것은 모든 액터들이 새롭게 스폰되는것과 같다.

그래서 이동하기 전의 레벨에서 유지했던 정보들(체력, 무기 등등)은 모두 초기화가 되버린다.

그렇기 때문에 다음 레벨로 넘어가기 전에 현재 상태를 저장했다가 레벨로 넘어갔을 때 다시 갱신할 필요가 있다.

 

현재 상태를 세이브하기 위해서는 SaveGame 클래스가 필요하다.

SaveGame 클래스를 상속받는 클래스를 만들어서 세이브해야 할 정보들을 미리 선언해둔다.

 

// SaveGame 인스턴스 생성
UFirstSaveGame* SaveGameInstance = Cast<UFirstSaveGame>(UGameplayStatics::CreateSaveGameObject(UFirstSaveGame::StaticClass()));

// todo: 데이터 저장
// ex) SaveGameInstance->CharacterStats.Health = Health;

// 슬롯에 저장
UGameplayStatics::SaveGameToSlot(SaveGameInstance, SaveGameInstance->PlayerName, SaveGameInstance->UserIndex);

 

// SaveGame 인스턴스 생성
UFirstSaveGame* LoadGameInstance = Cast<UFirstSaveGame>(UGameplayStatics::CreateSaveGameObject(UFirstSaveGame::StaticClass()));

// 슬롯에서 불러옴
LoadGameInstance = Cast<UFirstSaveGame>(UGameplayStatics::LoadGameFromSlot(LoadGameInstance->PlayerName, LoadGameInstance->UserIndex));

// todo: 데이터 갱신

 

세이브, 로드 둘다 SaveGame 인스턴스를 만드는것 까지는 똑같다.

세이브는 인스턴스 생성 -> 데이터 저장 -> 슬롯에 인스턴스 저장

로드는 인스턴스 생성 -> 슬롯에서 인스턴스 로드 -> 데이터 갱신 순으로 이뤄진다.

 

한가지 고려 사항이 있다.

레벨을 이동하기 전에 저장한 위치는 레벨 이동 후에도 유효하리라는 보장이 없다. 맵이 다르기 때문이다.

 

 

그리고 사용시 반드시 알아야할 주의점이 몇가지 있다.

우선 저장하는 데이터들은 반드시 UPROPERTY 매크로가 붙어있어야 한다. 그렇지 않으면 데이터가 저장되지 않는다.

 

두번째로 장착 무기와 같은 포인터는 값이 아닌 주소가 저장되는 문제가 있다.

이 문제는 다음 장에서 해결해 보도록 한다.

 

[91. Saving the Weapon]

 

무기의 컨테이너 역할을 하는 새로운 액터를 만들어서 해결해 보려고 한다.

 

무기별로 블루프린트를 만들고 그 무기들을 담을 C++ 클래스를 블루프린트 클래스로 파생시킨다.

관리는 Map으로 할 것이다. Key는 무기의 이름, Value는 무기의 블루프린트이다.

 

UPROPERTY(EditDefaultsOnly, Category="SaveData")
TMap<FString, TSubclassOf<class AWeapon>> WeaponMap;

 

위의 구조가 구현의 핵심이다. 블루프린트로 관리하는 것이다.

 

Key 검색을 위해서 무기마다 이름을 지정해주고 무기 컨테이너에 각 블루프린트를 넣어준다.

ItemStorage가 4개의 무기 블루프린트를 가지고 Save/Load할 때 ItemStorage에 접근해서 저장할 때 장착하고 있던 무기의 이름과 ItemStorage의 이름과 비교해서 같은 것을 SpawnActor로 월드에 스폰시키고 캐릭터에 장착시켜주는 매커니즘으로 작동한다.

 

덧붙여서 Map의 Value에 접근할 때 STL의 map처럼 값의 존재 유무를 따지지 않고 []연산으로 접근 시 에러가 발생하므로 꼭 Contain으로 값의 존재 여부를 파악하고 사용하는 것이 좋다.

 

[92. Pause Menu #1]

 

Pause Menu 위젯 블루프린트를 만들고 키 바인딩을 해준다.

 

[93. Pause Menu #2]

 

UI에 키프레임 애니메이션을 적용시킬 수 있다.

 

[94. Pause Menu #3]

 

SetInputMode(const FInputModeBase &InData);
// FInputModeGameAndUI, FInputModeGameOnly, FInputModeUIOnly
bShowMouseCursor = true;

 

SetInputMode를 통해 입력 모드를 바꿀 수 있다.

입력 모드가 바뀌더라도 마우스 커서가 자동으로 보여지는것은 아니므로 따로 보여지게 설정하여야 한다.

 

 

InputModeUIOnly

 

기존에 InputComponent에 매핑시켰던 키(액션, 축)들은 모두 사용할 수 없다.

마우스 커서가 보이지 않지만 UI 조작이 가능하다.

만약 UI를 열고 닫는 키가 InputComponent에 매핑 되어있다면 UI를 여는것은 가능하지만 이후 조작이 안되기 때문에 닫는 것은 안된다.

 

InputModeGameOnly

 

위와 반대로 UI를 열수는 있지만 UI의 조작이 불가능하다.

(마우스 커서 true인 경우 확인 필요)

 

InputModeGameAndUI

 

UI와 게임 조작이 모두 가능하다.

 

[95. Pause Menu #4]

 

UI만 조작하고 싶어서 UIOnly를 사용하면 매핑된 키를 사용할 수 없는 문제가 있고 그걸 해결하려고 GameAndUI를 사용하면 캐릭터도 조작이 되는 문제가 있다.

해당 실습에서는 UI의 On/Off 여부에 따라 bool체크를 해서 조작을 일일이 막았는데 더 좋은 방법이 있는지는 찾아봐야 할 것 같다.

 

[정리]

 

  • 구조체를 만들때도 GENERATED_BODY() 매크로를 써줘야 한다.
  • 저장하는 데이터는 반드시 UPROPERTY로 관리되어야 한다.
  • 게임의 저장(현재 상태를 캡처에 가까움)은 SaveGame 인스턴스를 이용하면 된다.
  • 포인터는 값이 아닌 주소가 있으므로 바로 저장하는것은 문제가 생길 수 있다.
  • UI(UMG)에도 키 프레임 애니메이션을 적용시킬 수 있다.
  • 입력 모드 변경을 통해 조작을 제어할 수 있다.

'언리얼 엔진 > UE4 C++' 카테고리의 다른 글

[UE C++] Level Changing and Saving the Game #2 -完-  (0) 2022.09.16
[UE C++] Combat #10  (0) 2022.09.15
[UE C++] Combat #9  (0) 2022.09.14
[UE C++] Combat #8  (0) 2022.09.14
[UE C++] Combat #7  (0) 2022.09.13

+ Recent posts