본문 바로가기

프로젝트/Pollute

플레이어 캐릭터 빙의 변경 - (사람, 몬스터, 관전자)

게임 Pollute 는 플레이어가 사람, 몬스터, 관전자 3가지 캐릭터를 사용한다.

컨트롤러는 3가지 캐릭터에 대한 ChangePossess 를 진행해야한다.

 

구현하면서 배운 것과 놓친 부분들

1. Possess/UnPossess 는 항상 Server 에서 진행한다.

2. 리플리케이트 되어 있는 액터의 생성과 파괴가 서버에서 이루어진다면 동기화된다.

3. 클라에서는 캐릭터 생성하면서 Possess 시 Beginplay에서 컨트롤러를 정상적으로 가져올 수 있지만 Server 에서는 안된다. 안전하게 PossessedBy 함수를 사용한다.

4. 사람이 몬스터로 변한다면 PlayerHUD 를 Off 해야하며 만약 아이템을 들고 있다면 Detach 해야한다.

5. 몬스터로 변했다면 다시 무작위로 남아있는 사람 플레이어에게 저주를 적용해야한다.

 

캐릭터 변경에 대한 함수는 Controller 에서 관리한다.

 

ChangeToSpector 는 ServerRPC 이고 ChangeToMonster 는 일반 함수인 이유

만들다보니 ChangeToSpector 는 클라에서 사용하고 ChangeToMonster 는 서버에서 사용하기 때문이다.
팀원들도 자주 사용하는 함수여서 용도에 맞게 바꾸어두었다.

 

구현 내용

 

플레이어가 죽었을 때 호출하며 관전자 플레이어가 된다

사람 및 몬스터에서 죽을 경우에 대한 예외처리를 진행한다.

void ALCU_PlayerController::ServerRPC_ChangeToSpector_Implementation()
{
	// 현재 Possess 하고 있는 폰 가져오기
	APawn* player = GetPawn();
    ALCU_PlayerCharacter* PlayerCharacter = Cast<ALCU_PlayerCharacter>(player);
    if(PlayerCharacter && HasAuthority())
    {
        PlayerCharacter->NetMulticast_DetachItem();
    }

    // 저주를 다시 시작합니다.
    if(PlayerCharacter && PlayerCharacter->GetHasCurse())
    {
        AP_GameState* GS = Cast<AP_GameState>(UGameplayStatics::GetGameState(GetWorld()));
        if (GS)
        {
            GS->RestartCurse();
        }
    }
    
    ClientRPC_ItemUIOff();
	UnPossess();

	// Spector Pawn 생성
	AGameModeBase* gm = GetWorld()->GetAuthGameMode();
	ASpectatorPawn* spector = GetWorld()->SpawnActor<ASpectatorPawn>(gm->SpectatorClass,player->GetActorTransform());

	// 생성된 Spector 로 Possess
	Possess(spector);
    
    if (IsValid(player))
    {
        player->Destroy();
    }
    
    AP_GameState* GS =Cast<AP_GameState>(UGameplayStatics::GetGameState(GetWorld()));
    if (GS)
    {
        GS->GetAllCharacters();
    }
}

 

 

void ALCU_PlayerController::ChangeToMonster()
{
    if(!IsValid(MonChar)) return;
    // 현재 Possess 하고 있는 폰 가져오기
    APawn* player = GetPawn();
    ALCU_PlayerCharacter* PlayerCharacter = Cast<ALCU_PlayerCharacter>(player);
    if(PlayerCharacter && HasAuthority())
    {
        PlayerCharacter->NetMulticast_DetachItem();
    }
    ClientRPC_ItemUIOff();
    UnPossess();

    // Spector Pawn 생성
    AGameModeBase* gm = GetWorld()->GetAuthGameMode();
    ALCU_MonsterCharacter* MonSter = GetWorld()->SpawnActor<ALCU_MonsterCharacter>(MonChar,player->GetActorTransform());

    // 생성된 Spector 로 Possess
    Possess(MonSter);

    player->Destroy();

    // 사람 플레이어가 얼마나 남았는지 확인하고 다시 
    AP_GameState* GS =Cast<AP_GameState>(UGameplayStatics::GetGameState(GetWorld()));
    if (GS)
    {
        GS->GetAllCharacters();
    }
}