1. 범위 순회 - 종료 조건 전달하기 (AKillEmAllGameMode)

미래에 적을 다수 배치하고 승리하는 조건을 고려하기 위해, 모든 폰의 컨트롤러에게 게임이 끝났다는 조건을 전달해야 한다.

UCLASS()
class SIMPLESHOOTER_API AKillEmAllGameMode : public ASimpleShooterGameModeBase
{
	GENERATED_BODY()

public:
	virtual void PawnKilled(APawn* PawnKilled) override;

private:
	void EndGame(bool bIsPlayerWinner);
};

아래 헤더를 추가한다.

#include "EngineUtils.h"
#include "GameFramework/Controller.h"
void AKillEmAllGameMode::PawnKilled(APawn* PawnKilled)
{
    Super::PawnKilled(PawnKilled);

    auto PlayerController = Cast<APlayerController>(PawnKilled->GetController());
    if (PlayerController != nullptr)
    {
        EndGame(false);
    }
}

void AKillEmAllGameMode::EndGame(bool bIsPlayerWinner)
{
    // Scene의 모든 컨트롤러를 호출하여 GameHasEnded 호출
    for (AController* Controller : TActorRange<AController>(GetWorld()))
    {
        bool bIsWinner = Controller->IsPlayerController() == bIsPlayerWinner;

        // 승리 시 포커스를 플레이어 폰에 유지
        Controller->GameHasEnded(Controller->GetPawn(), bIsWinner);
    }
}

TActorRange 템플릿을 사용하여 월드 내의 컨트롤러를 모두 찾고 범위 순회를 실행한다.

이후 조건을 체크하여, 플레이어 컨트롤러이며 플레이어가 이겼다면 GameHasEnded에 True를 넘겨 승리했다는 것을 알린다.

그 이외의 AI 컨트롤러이며 플레이어가 패배했다면 False를 넘겨 게임이 패배로 끝났다는 것을 알린다.

위와 같이 코드를 작성하면 3가지 예외 케이스를 한 줄로 줄일 수 있다.

 

 

2. 승리 조건

(1) 사망 판정 - ShooterAIController

폰의 사망을 판정할 수 있도록 코드를 추가한다.

bool AShooterAIController::IsDead() const
{
    AShooterCharacter* ControlledCharacter = Cast<AShooterCharacter>(GetPawn());

    if (ControlledCharacter)
    {
        return ControlledCharacter->IsDead();
    }

    return true;
}

 

 

(2) 승리 조건 추가 - ShooterPlayerController

private:
	UPROPERTY(EditAnywhere)
	TSubclassOf<class UUserWidget> LoseScreenClass;

	UPROPERTY(EditAnywhere)
	TSubclassOf<class UUserWidget> WinScreenClass;
void AShooterPlayerController::GameHasEnded(AActor* EndGameFocus, bool bIsWinner)
{
    Super::GameHasEnded(EndGameFocus, bIsWinner);

    if (bIsWinner)
    {
        // UI 노출
        UUserWidget* WinScreen = CreateWidget(this, WinScreenClass);
        if (WinScreen)
        {
            WinScreen->AddToViewport();
        } 
    }
    else
    {
        // UI 노출
        UUserWidget* LoseScreen = CreateWidget(this, LoseScreenClass);
        if (LoseScreen)
        {
            LoseScreen->AddToViewport();
        } 
    } 
 
    // 재시작
    GetWorldTimerManager().SetTimer(RestartTimer, this, &APlayerController::RestartLevel, RestartDelay);

}

이제 플레이어가 이겼을 경우도 판정해야하므로 코드를 수정한다.

 

 

(3) 승리 조건 판정하기 - KillEmAllGameMode

아래 헤더를 추가한다.

#include "ShooterAIController.h"
void AKillEmAllGameMode::PawnKilled(APawn* PawnKilled)
{
    Super::PawnKilled(PawnKilled);

    auto PlayerController = Cast<APlayerController>(PawnKilled->GetController());
    if (PlayerController != nullptr)
    {
        EndGame(false);
    }

    // 월드에 있는 AI 슈터를 찾기
        // IsDead == false
            // return;
    // AI 슈터가 더 이상 없으면 게임 종료
    for (AShooterAIController* Controller : TActorRange<AShooterAIController>(GetWorld()))
    {
        // 아직 사망하지 않았다면 종료하지 않음
        if (!Controller->IsDead())
            return;
    }
    
    // 모두 사망했다면 종료
    EndGame(true);
}

이제 TActorRange를 통해 AI 컨트롤러를 전부 찾아 사망을 판정한다.

하나라도 살아있다면 아직 게임이 종료되지 않은 것이므로 함수를 얼리 리턴한다.