* HUD UI 오른쪽 상당에 위치한 게임의 스코어 부분을 구현해본다
* 게임을 처음 시작하면 입장한 플레이어는 0의 점수를 가진다. 문을 통과해 새롭게 생성된 섹션에서 나타난 NPC를 처치하면 플레이어는 1의 점수를 획득한다. 플레이어는 레벨을 계속 탐험하면서 NPC를 처치하고 점수를 획득하는데, 이 점수는 플레이어의 점수를 의미하면서 동시에 게임스코어라고도 할 수 있다.
* 멀티플레이 콘텐츠를 기획한다면, 플레이어에 설정된 데이터 외에도 게임의 데이터를 관리하는 기능을 추가로 고려해야 한다. 언리얼 엔진은 이를 관리하도록 게임스테이트라는 클래스를 제공한다.
* 학습을 위해 게임 스테이트를 사용해 게임데이터만 분리함으로 관리하는 기능을 추가해본다.
* GameStateBase 기반의 클래스를 생성한다.
* 전체 게임 스코어를 저장하는 속성을 추가한다.
//class ABGameState
//h
#include "ArenaBattle.h"
#include "GameFramework/GameStateBase.h"
#include "ABGameState.generated.h"
UCLASS()
class ARENABATTLE_API AABGameState : public AGameStateBase
{
GENERATED_BODY()
public:
AABGameState();
public:
int32 GetTotalGameScore() const;
void AddGameScore();
private:
UPROPERTY(Transient)
int32 TotalGameScore;
};
//cpp
#include "ABGameState.h"
AABGameState::AABGameState()
{
TotalGameScore = 0;
}
int32 AABGameState::GetTotalGameScore() const
{
return TotalGameScore;
}
void AABGameState::AddGameScore()
{
TotalGameScore++;
}
//AABGameMode.cpp
#include "ABGameMode.h"
#include "ABCharacter.h"
#include "ABPlayerController.h"
#include "ABPlayerState.h"
#include "ABGameState.h"
AABGameMode::AABGameMode()
{
....
GameStateClass = AABGameState::StaticClass();
}
* 이번에는 섹션 액터의 로직으로 이동해 섹션에서 생성한 NPC가 플레이어에 의해 제거되면, 이를 감지해 섹션 액터의 스테이트를 COMPLETE로 변경하는 기능을 추가한다.
* NPC가 제거될 떄 마지막으로 대미지를 입힌 컨트롤러의 기록은 LastHitBy 속성에 저장된다. 이를 사용하면 액터가 제거될 떄 마지막에 피격을 가한 플레이어의 정보를 바로 얻어올 수 있다.
* 이전에 구현한 경험치의 경우 대미지를 입을 떄마다 Instigator를 검사하는 방식보다 소멸될 떄 LastHitBy를 사용해 처리하는 것이 효율적이지만, 학습을 위해 두가지 모두 공부
//ABSection.h
UCLASS()
class ARENABATTLE_API AABSection : public AActor
{
private:
UFUNCTION()
void OnKeyNPCDestroyed(AActor* DestoryedActor);
}
//ABSection.cpp
#include "ABPlayerController.h"
void AABSection::OnNPCSpawn()
{
GetWorld()->GetTimerManager().ClearTimer(SpawnNPCTimerHandle);
auto KeyNPC = GetWorld()->SpawnActor<AABCharacter>(GetActorLocation() + FVector::UpVector * 88.0f, FRotator::ZeroRotator);
if (nullptr != KeyNPC)
{
KeyNPC->OnDestroyed.AddDynamic(this, &AABSection::OnKeyNPCDestroyed);
}
}
void AABSection::OnKeyNPCDestroyed(AActor* DestoryedActor)
{
auto ABCharacter = Cast<AABCharacter>(DestoryedActor);
ABCHECK(nullptr != ABCharacter);
auto ABPlayerController = Cast<AABPlayerController>(ABCharacter->LastHitBy);
ABCHECK(nullptr != ABPlayerController);
SetState(ESectionState::COMPLETE);
}
* NPC를 제거해 섹션을 클리어하면 게임모드에게 스코어를 올리라는 명령을 내린다
* 여기서 마지막 피격을 가한 플레이어 컨트롤러 정보를 함꼐 념겨서 해당 플레이어 스테이트의 스코어를 높이고, 더불어 전체 스코어에 해당하는 게임 스테이트의 스코어도 같이 올린다.
* 현재 게임에 참여 중인 플레이어 컨트롤러의 목록은 월드에서 제공하는 GetPlayerControllerIterator를 사용해 얻어올 수 있다. 이를 사용해 게임 스코어를 구현한 코드는 다음과 같다.
//AABPlayerState.h
{
public:
void AddGameScore();
}
//cpp
void AABPlayerState::AddGameScore()
{
GameScore++;
OnPlayerStateChanged.Broadcast();
}
//ABPlayerController.h
class ARENABATTLE_API AABPlayerController : public APlayerController
{
public:
...
void AddGameScore() const;
}
//ABPlayerController.cpp
void AABPlayerController::AddGameScore() const
{
ABPlayerState->AddGameScore();
}
//ABGameMode.h
UCLASS()
class ARENABATTLE_API AABGameMode : public AGameModeBase
{
GENERATED_BODY()
public:
AABGameMode();
virtual void PostInitializeComponents() override;
virtual void PostLogin(APlayerController* NewPlayer) override;
void AddScore(class AABPlayerController * ScoredPlayer);
private:
UPROPERTY()
class AABGameState* ABGameState;
};
//cpp
#include "ABGameMode.h"
#include "ABCharacter.h"
#include "ABPlayerController.h"
#include "ABPlayerState.h"
#include "ABGameState.h"
AABGameMode::AABGameMode()
{
DefaultPawnClass = AABCharacter::StaticClass();
PlayerControllerClass = AABPlayerController::StaticClass();
PlayerStateClass = AABPlayerState::StaticClass();
GameStateClass = AABGameState::StaticClass();
}
void AABGameMode::PostLogin(APlayerController* NewPlayer)
{
Super::PostLogin(NewPlayer);
auto ABPlayerState = Cast<AABPlayerState>(NewPlayer->PlayerState);
ABCHECK(nullptr != ABPlayerState);
ABPlayerState->InitPlayerData();
}
void AABGameMode::PostInitializeComponents()
{
Super::PostInitializeComponents();
ABGameState = Cast<AABGameState>(GameState);
}
void AABGameMode::AddScore(class AABPlayerController * ScoredPlayer)
{
for (FConstPlayerControllerIterator It = GetWorld()->GetPlayerControllerIterator(); It; ++It)
{
const auto ABPlayerController = Cast<AABPlayerController>(It->Get());
if ((nullptr != ABPlayerController) && (ScoredPlayer == ABPlayerController))
{
ABPlayerController->AddGameScore();
break;
}
}
ABGameState->AddGameScore();
}
//ABSection.cpp
#include "ABGameMode.h"
void AABSection::OnKeyNPCDestroyed(AActor* DestoryedActor)
{
.......
auto ABGameMode = Cast<AABGameMode>(GetWorld()->GetAuthGameMode());
ABCHECK(nullptr != ABGameMode);
ABGameMode->AddScore(ABPlayerController);
SetState(ESectionState::COMPLETE);
}
* 컴파일 하고 실행결과 NPC가 제거되면 우측 상단의 스코어가 하나씩 올라간다.
'Unreal > Game 1 (C++)' 카테고리의 다른 글
22. 게임의 완성 2 (전투 시스템의 설계) (0) | 2019.05.10 |
---|---|
22. 게임의 완성 1 (게임 데이터의 저장과 로딩) (0) | 2019.05.10 |
21. 게임플레이 제작 2 (플레이어 데이터와 UI 연동) (0) | 2019.05.08 |
21. 게임플레이 제작 1 (캐릭터 스테이트) (0) | 2019.05.08 |
20. 프로젝트이 설정과 무한 맵의 제작 4 (타이머기능 + 네비게이션 메시 시스템 설정) (0) | 2019.05.08 |