오늘은 적이 죽으면 점수가 오르고 맵이 열려 실제로 게임 플레이가 어느정도 진행되게끔 진행하도록 하겠다
먼저 현재까지의 레벨을 다른 이름으로 저장한다 (GamePlay)
그 후, 시작 레벨을 현재의 레벨로 설정해준다
원래 존재하던 NPC와 ItemBox는 이제 지워주고, Player Start 액터를 (0.0, 0.0, 88.0) 지점에 생성해준다
다음은 네브메시의 볼륨을 크게 만들어준다
사이즈의 크기만큼 확장된 맵에서도 NPC가 추적이 가능하기 때문에, 자신의 프로젝트 규모를 생각하며 사이즈를 설정하면 된다
언리얼 엔진에서는 게임의 데이터를 관리하는 기능인 클래스 GameState 가 존재한다
GameStateBase 를 부모로 하는 클래스 ABGameState 를 생성한다
ABGameState.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#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;
};
ABGameState.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "ABGameState.h"
AABGameState::AABGameState()
{
TotalGameScore = 0;
}
int32 AABGameState::GetTotalGameScore() const
{
return TotalGameScore;
}
void AABGameState::AddGameScore()
{
TotalGameScore++;
}
NPC 를 제거하면, 스코어가 오르며 문이 열리도록 설정해주어야 한다
먼저 ABSection에서 마지막으로 대미지를 입힌 컨트롤러의 기록 lastHitBy
를 통해 플레이어가 NPC를 제거했을 경우
문이 열리도록 설정해주자
ABSection.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "ArenaBattle.h"
#include "GameFramework/Actor.h"
#include "ABSection.generated.h"
{
...
private:
...
UFUNCTION()
void OnKeyNPCDestroyed(AActor* DestroyedActor);
}
ABSection.cpp
void AABSection::SetState(ESectionState NewState)
{
switch (NewState)
{
case ESectionState::READY:
{
Trigger->SetCollisionProfileName(TEXT("ABTrigger"));
for (UBoxComponent* GateTrigger : GateTriggers)
GateTrigger->SetCollisionProfileName(TEXT("NoCollision"));
OperateGate(true);
break;
}
case ESectionState::BATTLE:
{
Trigger->SetCollisionProfileName(TEXT("NoCollision"));
for (UBoxComponent* GateTrigger : GateTriggers)
GateTrigger->SetCollisionProfileName(TEXT("NoCollision"));
OperateGate(false);
GetWorld()->GetTimerManager().SetTimer(SpawnNPCTimerHandle,
FTimerDelegate::CreateLambda([this]()->void
{
auto KeyNPC = GetWorld()->SpawnActor<AABCharacter>
(GetActorLocation() + FVector::UpVector * 88.0f, FRotator::ZeroRotator);
if (nullptr != KeyNPC)
KeyNPC->OnDestroyed.AddDynamic(this, &AABSection::OnKeyNPCDestroyed);
}), EnemySpawnTime, false);
GetWorld()->GetTimerManager().SetTimer(SpawnItemBoxTimerHandle,
FTimerDelegate::CreateLambda([this]() -> void
{
FVector2D RandXY = FMath::RandPointInCircle(600.0f);
GetWorld()->SpawnActor<AABItem>(GetActorLocation() + FVector(RandXY, 20.0f), FRotator::ZeroRotator);
}), ItemBoxSpawnTime, false);
break;
...
}
...
void AABSection::OnKeyNPCDestroyed(AActor* DestroyedActor)
{
auto ABCharacter = Cast<AABCharacter>(DestroyedActor);
auto ABPlayerController = Cast<AABPlayerController>(ABCharacter->LastHitBy);
SetState(ESectionState::COMPLETE);
}
이제 NPC가 제거되면 스코어가 오르도록 설정해준다
ABPlayerState.cpp
int32 AABPlayerState::GetGameScore() const
{
return GameScore;
}
ABPlayerController.cpp
void AABPlayerController::AddGameScore() const
{
ABPlayerState->AddGameScore();
}
ABGameMode.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "ArenaBattle.h"
#include "GameFramework/GameModeBase.h"
#include "ABGameMode.generated.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;
};
ABGameMode.cpp
...
void AABGameMode::PostInitializeComponents()
{
Super::PostInitializeComponents();
ABGameState = Cast<AABGameState>(GameState);
}
...
void AABGameMode::AddScore(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
void AABSection::OnKeyNPCDestroyed(AActor* DestroyedActor)
{
auto ABCharacter = Cast<AABCharacter>(DestroyedActor);
auto ABPlayerController = Cast<AABPlayerController>(ABCharacter->LastHitBy);
auto ABGameMode = Cast<AABGameMode>(GetWorld()->GetAuthGameMode());
ABGameMode->AddScore(ABPlayerController);
SetState(ESectionState::COMPLETE);
}
마지막으로 피격을 가한 플레이어 컨트롤러의 정보를 게임모드에 넘겨 플레이어 스테이트의 점수를 높이고,
전체 스코어에 해당하는 게임 스테이트의 스코어도 올린다
완성된 화면을 보자
적이 죽으면 문이 열리며 스코어가 올라가게 된다