728x90
반응형
15강 게임의 완성
- 정리
- 게임 제작의 완성
- 게임 모드를 활용한 게임 규칙의 완성
- 전용 이벤트 함수를 활용한 블루프린트와의 연동
- 게임 데이터의 저장 방식의 이해
- 게임의 최종 빌드
- 게임 제작의 완성
- 게임 모드
- 멀티플레이를 포함해 게임에서 유일하게 존재하는 게임의 심판 오브젝트
- 최상단에서 게임의 진행을 관리하며, 게임 판정에 관련된 중요한 행동을 주관하는데 적합함
- 다양한 게임 규칙을 적용할 수 있도록 핵심 기능과 분리해 설계하는 것이 바람직함
- 게임의 상태와 플레이어의 상태를 별도로 저장할 수 있는 프레임웍을 제공함
- 하나의 운동장에서 발야구, 축구, 야구등을 할 수 있도록 게임을 관장하는 규칙을 관리하는 부분이라고 이해하면 편하다. 그렇기 때문에 핵심 기능과는 분리해서 설계!
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "ABGameInterface.generated.h"
// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UABGameInterface : public UInterface
{
GENERATED_BODY()
};
class ARENABATTLE_API IABGameInterface
{
GENERATED_BODY()
public:
// 플레이어의 스코어가 변경될 때 호출
virtual void OnPlayerScoreChanged(int32 NewPlayerScore) = 0;
// 플레이어가 죽었을 때
virtual void OnPlayerDead() = 0;
// 현재 게임이 클리어 되었는지 확인하는 함수
virtual bool IsGameCleared() = 0;
};
- ABGameInterface.h
- 인터페이스를 하나 만들어서, 다른 스코어가 변경되거나, 플레이어가 죽었을 때, 게임이 클리어가 되었는지 확인할 때 GameMode에 대한 직접적인 참조보다는 간접 참조를 위해 인터페이스를 구성한다.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "Interface/ABGameInterface.h"
#include "ABGameMode.generated.h"
UCLASS()
class ARENABATTLE_API AABGameMode : public AGameModeBase, public IABGameInterface
{
GENERATED_BODY()
public:
AABGameMode();
virtual void OnPlayerScoreChanged(int32 NewPlayerScore) override;
virtual void OnPlayerDead() override;
virtual bool IsGameCleared() override;
// 게임을 클리어하기 위한 조건을 위한 점수
// 현재 진행되고 있는 게임의 점수
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite, Category = Game)
int32 ClearScrore;
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = Game)
int32 CurrentScore;
// 게임을 클리어했는지 판단하기 위한 변수
UPROPERTY(VisibleInstanceOnly,BlueprintReadOnly, Category = Game)
uint8 bIsCleared : 1;
};
- AABGameMode.h
#include "Game/ABGameMode.h"
#include "ABGameMode.h"
#include "Player/ABPlayerController.h"
AABGameMode::AABGameMode()
{
// ...
ClearScrore = 3;
// CurrentScore의 경우 게임의 규모가 조금 더 커진다면 PlayerState같은 객체에 보관하는 것이 좋다.
CurrentScore = 0;
bIsCleared = false;
}
// 플레이어의 현재 점수가 변경되었을 때
void AABGameMode::OnPlayerScoreChanged(int32 NewPlayerScore)
{
CurrentScore = NewPlayerScore;
// 스코어가 변했을 때 신호를 날려주기 위한
// 1인 플레이기 때문에 FirstPlayerController를 가져와도 된다.
AABPlayerController* ABPlayerController = Cast<AABPlayerController>(GetWorld()->GetFirstPlayerController());
if (ABPlayerController)
{
ABPlayerController->GameScoreChanged(CurrentScore);
}
// 게임을 클리어했을 때
if (CurrentScore >= ClearScrore)
{
bIsCleared = true;
if (ABPlayerController)
{
ABPlayerController->GameClear();
}
}
}
// 플레이어가 죽었을 때
void AABGameMode::OnPlayerDead()
{
// 플레이어가 죽었을 때 관련된 UI를 날리는 이벤트를 PlayerController에게 알려주기 위한
AABPlayerController* ABPlayerController = Cast<AABPlayerController>(GetWorld()->GetFirstPlayerController());
if (ABPlayerController)
{
ABPlayerController->GameOver();
}
}
// 현재 게임을 클리어 하였는가?
bool AABGameMode::IsGameCleared()
{
return bIsCleared;
}
- AABGameMode.cpp
#include "Interface/ABGameInterface.h"
// ...
// 플레이어가 죽으면 게임이 종료되도록 GameMode를 통해 전달하기
IABGameInterface* ABGameMode = Cast<IABGameInterface>(GetWorld()->GetAuthGameMode());
if (ABGameMode)
{
ABGameMode->OnPlayerDead();
}
// ...
- AABCharacterPlayer.cpp
- GameMode 클래스에 다음과 같이 게임모드에 필요한 변수와 함수들을 추가해준다.
- Gimmick 클래스와 CharacterPlayer 클래스에서 인터페이스 헤더를 추가해준 뒤, 다음과 같이 인터페이스와 GetAuthGameMode를 통해 GameMode의 함수들을 호출해주도록 한다.
- 이후, PlayerController 클래스에서 UI 이벤트를 위해 로직을 구성해준다.
- 간단히 게임을 저장하는 방법
- SaveGame이라는 부모 클래스를 가진 코드를 만들어 주고 사용해주면 된다.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/SaveGame.h"
#include "ABSaveGame.generated.h"
/**
*
*/
UCLASS()
class ARENABATTLE_API UABSaveGame : public USaveGame
{
GENERATED_BODY()
public:
UABSaveGame();
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = Game)
int32 RetryCount;
};
- ABSaveGame.h
#include "Player/ABSaveGame.h"
UABSaveGame::UABSaveGame()
{
RetryCount = 0;
}
- ABSaveGame.cpp
- RetryCount라는 변수를 통해 다시 플레이한 횟수를 카운팅 해준다. Save된 카운트는 다음 위치에 저장되어진다. BP에서 쓸 수 있도록 프로퍼티 설정을 해준다.
- 플레이어0번의 세이브 기록이기 때문에 Player0으로 저장되는 모습을 볼 수 있다. 다음 파일을 삭제하면 0부터 시작된다.
UFUNCTION(BlueprintImplementableEvent, Category = Game, Meta = (DisplayName = "OnGameRetryCountCpp"))
void K2_OnGameRetryCount(int32 NewRetryCount);
protected:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = SaveGame)
TObjectPtr<class UABSaveGame> SaveGameInstance;
- ABPlayerController.h
void AABPlayerController::GameOver()
{
K2_OnGameOver();
// 게임이 끝나면 저장하기
if (!UGameplayStatics::SaveGameToSlot(SaveGameInstance, TEXT("Player0"), 0))
{
UE_LOG(LogABPlayerController, Error, TEXT("Save Game Error!"));
}
K2_OnGameRetryCount(SaveGameInstance->RetryCount);
}
void AABPlayerController::BeginPlay()
{
Super::BeginPlay(); // override의 경우 Super 붙이기
FInputModeGameOnly GameOnlyInputMode; // 구조체 선언
SetInputMode(GameOnlyInputMode); // 구조체 넘기기 (시작하자마자 포커스가 뷰 포트 안으로 들어가게 된다.)
SaveGameInstance = Cast<UABSaveGame>(UGameplayStatics::LoadGameFromSlot(TEXT("Player0"), 0));
if (SaveGameInstance)
{
SaveGameInstance->RetryCount++;
}
else
{
SaveGameInstance = NewObject<UABSaveGame>();
}
K2_OnGameRetryCount(SaveGameInstance->RetryCount);
}
- ABPlayerController.cpp
- ABPlayerController.h에서 ABSaveGAme에 대한 인스턴스를 만들어주고, BP에서 사용할 K2_OnGameRetryCount함수를 만들어 준다.
- ABPlayerController.cpp에서 다음과 같이 BeginPlay에서 SaveGameInstance를 통해 세이브 파일이 존재한다면 RetryCount를 증가시켜주고, 아니라면 생성해주고 BP에 적용될 수 있도록 RetryCount를 넘겨준다.
- ABPlayerController.cpp의 BeginPlay에 RetryCount를 바탕으로 BP에서 SetRetryCount 값을 채워주는 모습
- BP를 통해 게임을 플레이하면 UI가 생성되고 보여지도록 만들어주고, 게임을 플레이할 수 있도록 조금 다듬어 준다.
- 게임 패키징
- 패키징을 하게 되면 map에 참조된 에셋들만 포함되서 패키징이 된다. 하지만, 우리는 코드단에서 아이템등을 참조했기 때문에 함께 패키징 해줘야 하는데, 다음 셋팅에서 함께 패키징할 수 있게 설정할 수 있다.
- Additional Asset Directories to Cook을 통해 함께 빌드 해주도록 정확히 명시해준다. 또한, 현재 사용할 map을 정확히 명시해주는 것도 좋다.
- Shipping 빌드의 경우 가장 작은 용량으로 패키징을 진행할 수 있는 방법. 다만, 디버그라인 등 디버깅용 기능들은 포함되지 않은 채로 패키징 된다.
- 전체화면이 되거나 전체화면을 풀기 위해서는 Alt+Enter를 입력해주면 된다.
해당 포스트는 인프런의 <이득우의 언리얼 프로그래밍 Part2 -언리얼 게임 프레임웍의 이해>
강의를 수강하고 정리한 내용입니다.
이득우의 언리얼 프로그래밍 Part2 - 언리얼 게임 프레임웍의 이해 강의 | 이득우 - 인프런
이득우 | 대기업 현업자들이 수강하는 언리얼 C++ 프로그래밍 전문 과정입니다. 언리얼 C++ 프로그래밍을 사용해 핵&슬래시 로그라이크 게임 예제를 처음부터 끝까지 체계적으로 제작하는 방법을
www.inflearn.com
728x90
'공부 > 이득우의 언리얼 프로그래밍' 카테고리의 다른 글
[Study] Part 3 - 게임 모드와 로그인 (2/15) (0) | 2024.08.10 |
---|---|
[Study] Part 3 - 언리얼 네트웍 멀티플레이어 프레임웍 개요 (1/15) (0) | 2024.08.09 |
[Study] Part 2 - 게임플로우 다듬기 (14/15) (0) | 2024.06.24 |
[Study] Part 2 - 헤드업디스플레이의 구현 (13/15) (0) | 2024.06.21 |
[Study] Part 2 - 행동 트리 모델의 구현 (12/15) (0) | 2024.06.20 |