AssignRoles 호출 위치 이동 

기존엔 PostLogin에서 5초 타이머로 AssignRoles()를 예약했는데 그것보단 StartPlay()에 작성하는 게 더 깔끔할 것 같아서 이동 

 

Phase 값을 enum class로 교체

처음엔 CurrentPhase를 그냥 uint8로 선언해뒀는데 나중에 보수할 때 알기 어려울 것 같아서 미리 이름 붙은 타입으로 변경

UENUM(BlueprintType)
enum class EMatchPhase : uint8 { Warmup, AssignRole, Scouting, InGame, GameOver };

 

 

StartWarmup() 삭제

원래 설계는 본게임 레벨 안에서 "대기 → 역할배정 → 정찰 → 본게임 → 종료"를 전부 처리할 생각이었어서 Warmup 단계가 있었는데 이번에 시작화면/로비를 별도 레벨로 분리하면서 Warmup 단계가 필요없어짐 

-> StartWarmup() 함수(선언·정의 둘 다)는 삭제

 

다만 EMatchPhase::Warmup 값 자체는 남겨둠

AssignRoles가 실행되기 전까지 로딩 중 같은 안내를 띄울수도 있어서

 

정찰단계 구현

정찰 단계에서 중요한건 술래가 맵 구조를 미리 파악하는동안 숨는 사람들의 캐릭터가 보이면 안 되는 것

 

처음엔 튜터님이 제안주신 대로 정찰단계일 때 술래를 오프라인 시키려고 했음

그래서 Netconnection을 끊으려고 했는데 다시 재접속 시키니까 PlayerController가 통째로 새로 만들어지고, PostLogin이 다시 실행되면서 Role이 다시 배정됨

그래서 그냥 원래 하려던 대로 IsNetRelevantFor을 사용함

(Hider 캐릭터에 구현해서 이 캐릭터가 정찰모드동안은 Tag가 Tagger(술래)인 사람에게 전달되지 않도록)

  • AFDHiderCharacter::IsNetRelevantFor : 술래에게 숨는 사람 데이터 자체를 안 보내는 로직
  • AFDTaggerCharacter::SetScoutingMode : 술래를 정찰모드로 바꾸는 로직

GameMode가 CurrentPhase를 Replicated 값으로 바꾸기만 하면 그 값을 각 캐릭터가 구독해서 스스로 반응하는 구조 (GameMode에서 StartPlay 같은 함수에 Phase 지정하는 방식)

 

bool AFDHiderCharacter::IsNetRelevantFor(const AActor* RealViewer, const AActor* ViewTarget,
    const FVector& SrcLocation) const
{
    if (const AController* ViewerController = Cast<AController>(RealViewer))
    {
        if (const AFDPlayerState* FDViewerPS = ViewerController->GetPlayerState<AFDPlayerState>())
        {
            if (const AFDGameState* FDGameState = GetWorld()->GetGameState<AFDGameState>())
            {
                if (FDGameState->CurrentPhase == EMatchPhase::Scouting &&
                    FDViewerPS->RoleTag == EFDRole::Tagger)
                {
                    return false;
                }
            }
        }
    }
    return Super::IsNetRelevantFor(RealViewer, ViewTarget, SrcLocation);
}

 

bool IsNetRelevantFor(const AActor* RealViewer, const AActor* ViewTarget, const FVector& SrcLocation) const

 

이 함수 전체는 "나(this = 숨는 사람 캐릭터)를, RealViewer라는 그 사람에게 보내줘도 되는가?"라는 질문에 답하는 함수

 

판단해야 했던 건 "보고 있는 쪽(RealViewer)이 술래인지" 임 -> Tag로 확인

 

술래쪽은 정찰모드일 때 

걷기 속도 올리고 메시 안보이게 하는 걸로 설정함 

(숨는 사람이 숨고 있는데 술래가 보이면 이상하니까)

void AFDTaggerCharacter::SetScoutingMode(bool bEnable)
{
    UCharacterMovementComponent* Movement = GetCharacterMovement();
    if (!Movement) return;
    
    if (bEnable)
    {
       Movement->MaxWalkSpeed = 1200.f;
    }
    else
    {
       Movement->MaxWalkSpeed = 600.0f;
    }
    
    Multicast_SetMeshVisibility(!bEnable);
    // 관전 모드 진입하면 메시 숨겨야 하니까 반대값 전달 (false가 전달됨)
}

void AFDTaggerCharacter::Multicast_SetMeshVisibility_Implementation(bool bVisible)
{
    GetMesh()->SetVisibility(bVisible, true);
}

 

메시 가시성은 왜 Multicast를 썼냐면

처음엔 SetVisibility를 서버에서 그냥 호출하면 되는 줄 알았는데 반영이 안됨

이건 로컬에만 영향을 주는 거였음

NetMulticast RPC로 감싸야 서버 자신을 포함한 모든 클라이언트에서 동일하게 실행됨

(캐릭터는 모두에게 복제되니까 숨는 캐릭터 자체에 작성)

+ Recent posts