Make Unreal REAL.
article thumbnail
이득우의 언리얼 C++ 게임 개발의 정석

 

현재 레벨을 다른 이름으로 새로운 레벨로 저장한다.

 

새로운 레벨에서 테스트를 위해 시작 섹션에 배치돼 있는 캐릭터와 아이템 상자를 모두 제거한 후 NavMeshBoundsVolume을 충분히 크게 만들어준다.

 

 

새로운 레벨을 생성한 후에는 필요에 따라 Project Settings > Maps & Modes에서 기본 레벨을 지정해주는 것을 잊지 말아야 한다.

 

 

시작 섹션에서 0점으로 시작해 문을 통과하면 새로운 섹션이 생성된다.

새로운 섹션에서 AI를 처치하면 1점을 획득한다.

 

이 게임은 싱글 플레이이기 때문에 플레이어의 점수가 곧 게임 스코어라고 할 수 있다.

  • 멀티 플레이의 경우 두 개가 같지 않을 수 있다.
  • 1번 플레이어는 왼쪽 지역을 탐험하고 2번 플레이어는 오른쪽 지역을 탐험하는 경우, 각자가 얻은 점수를 게임 스코어와 동일시하는 것은 불공평하기 때문이다.
  • 이럴 때 기획이 추가로 필요하다.

 

언리얼 엔진에서는 싱글 플레이뿐만 아니라 멀티 플레이에서의 게임 데이터 관리도 고려한 게임 스테이트(Game State)라는 클래스를 제공한다.

  • 싱글 플레이만 고려한다면 플레이어 스테이트만 사용해도 된다.
  • 이 게임은 싱글 플레이지만, 학습을 위해 게임 스테이트도 사용해 게임의 점수를 관리해본다.

 

 

CoreMinimal.h를 ArenaBattle.h로 변경한다.

 

 

게임 점수 변수를 선언하고 점수 반환 함수와 추가 함수를 선언한다.

  • 게임 점수는 직렬화해서 저장하고 불러오는 것이 아니라 별도의 방법을 통해 런타임에 가져올 것이므로, Transient 키워드를 지정해 디스크에 저장하지 않도록 한다.

 

 

기본값을 설정하고 함수를 구현한다.

 

 

게임 모드에서 기본 게임 스테이트를 지정해준다.

 

 

이제 ABSection 클래스로 이동해 섹션에서 생성한 AI가 플레이어에게 죽으면, 섹션의 상태를 COMPLETE로 변경하는 기능을 구현한다.

  • 액터가 죽을 때 AController 타입의 APawn::LastHitBy 프로퍼티를 통해 마지막으로 때린 사람(컨트롤러)를 가져올 수 있다.

 

APawn::TakeDamage() 의 함수 내부는 다음과 같다.

  • 실제 입는 데미지가 0이 아니고 자기 자신을 때린 것이 아니면, LastHitBy 프로퍼티에 마지막 가해자를 저장한다.

 

 

ABSection 클래스에서 생성한 AI가 죽었을 때 호출할 함수를 선언한다.

 

 

섹션에서 AI를 생성할 때, AI의 AActor::OnDestroyed 다이나믹 멀티캐스트 델리게이트에 OnKeyNPCDestroyed() 함수를 등록한다.

  • 액터가 명시적으로 소멸되었을 때 발동한다.
  • 이 게임에서는 ECharacterState::DEAD가 된 후 타이머에 의한 몇 초 뒤이다.

 

 

AI가 월드에서 사라질 때 섹션의 상태를 COMPLETE로 전환한다.

 

 

AI가 죽어 COMPLETE 상태가 될 때 게임 모드에 게임 점수를 올리라는 명령을 내리게 한다.

  • 이 게임에서는 싱글 플레이지만 플레이어 점수와 게임 점수를 둘 다 관리하므로, 게임 모드에서 점수를 올릴 때 플레이어 컨트롤러를 함께 전달해 해당 플레이어 스테이트의 점수도 함께 올리도록 한다.

 

우선 플레이어 스테이트의 점수를 올릴 수 있도록 함수를 만든다.

  • 점수를 올릴 때 HUD UI를 갱신할 수 있도록 델리게이트를 발동한다.

 

 

플레이어 컨트롤러를 통해 플레이어 스테이트의 점수를 올릴 수 있도록 제공한다.

 

 

게임 스테이트의 점수를 증가시키는 함수를 선언한다.

  • 점수를 올릴 플레이어의 플레이어 컨트롤러를 함께 받아, 해당 플레이어 스테이트의 점수도 함께 올려준다.

 

PostInitializeComponents() 함수에서 게임 스테이트를 가져와 ABGameState 변수에 저장하도록 한다.

 

 

게임 모드에서는 AGameModeBase::GameState 프로퍼티로 바로 게임 스테이트를 가져올 수 있다.

 

 

UWorld::GetPlayerControllerIterator() 함수를 통해 월드에 있는 플레이어들의 플레이어 컨트롤러를 순회 가능한 FConstPlayerControllerIterator 타입의 반복자로 받아올 수 있다.

  • 받아온 반복자에서는 It->Get() 함수를 통해 APlayerController* 타입의 플레이어 컨트롤러를 가져올 수 있다.

 

반복자를 순회하면서 전달된 플레이어 컨트롤러가 있으면 플레이어 스테이트의 점수를 증가시키고 게임 스테이트의 점수도 증가시킨다.

 

 

이제 마지막으로 섹션에서 AI가 죽어 COMPLETE 상태가 될 때 게임 모드에 게임 점수를 올리라는 명령을 내린다.

 

필요한 헤더를 포함한다.

 

 

현재 OnKeyNPCDestroyed() 함수는 섹션에서 생성한 AI의 OnDestroyed 델리게이트에 등록되어 있다.

  • 그런데, DestroyedActor는 이미 소멸된 상태인데 OnDestroyed라는 델리게이트가 발동이 가능한가..?
  • IsValid(DestroyedActor)로 체크해봐도 유효하다고 나온다..

 

죽은 AI의 AController 타입 APawn::LastHitBy 프로퍼티를 플레이어 컨트롤러로 캐스팅한다.

 

게임 모드를 가져온 후 게임 점수와 함께 플레이어 점수를 올릴 플레이어 컨트롤러를 함께 전달해 점수를 증가시킨다.

 

 

게임 스테이트를 활용해 AI를 죽일 시 게임 점수를 증가시키는 데 성공했다.

 

profile

Make Unreal REAL.

@diesuki4

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

검색 태그