게임 플레이 보완 (3) 게임 데이터 관리

유영준·2023년 1월 28일
0

오늘은 적이 죽으면 점수가 오르고 맵이 열려 실제로 게임 플레이가 어느정도 진행되게끔 진행하도록 하겠다

시작 레벨세팅

먼저 현재까지의 레벨을 다른 이름으로 저장한다 (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);
}

마지막으로 피격을 가한 플레이어 컨트롤러의 정보를 게임모드에 넘겨 플레이어 스테이트의 점수를 높이고,

전체 스코어에 해당하는 게임 스테이트의 스코어도 올린다


완성된 화면을 보자

적이 죽으면 문이 열리며 스코어가 올라가게 된다

profile
토비폭스가 되고픈 게임 개발자

0개의 댓글