Unreal Engine - 데디케이티드 서버 8 (게임 흐름)

2025. 5. 2. 13:00·Unreal Engine

1. PlayerController


타이틀 전용 컨트롤러 및 맵 추가

 

동작 모습

  • 게임 시작 전 start 화면 구현
  • Start 버튼을 누르면 Join Server 수행

위쪽 : 서버 로그인 메시지 / 왼쪽 : Start를 눌러 접속한 모습 / 오른쪽 : 접속 전 Title 모습

 

구조

  • Title Level (새로운 레벨 추가)
  • GameModeBase_Title (새로운 GameMode 추가)
  • DXTitlePlayerController (새로운 PlayerController 추가 -> 위젯 띄워주기)

구현 내용

  • ADXTitlePlayerController
void ADXTitlePlayerController::BeginPlay()
{
	Super::BeginPlay();
	
	if (!IsLocalController())
	{
		return;
	}
	//not server
	if (IsValid(UIWidgetClass))
	{
		UIWidgetInstance = CreateWidget<UUserWidget>(this, UIWidgetClass);
		if (IsValid(UIWidgetInstance))
		{
			UIWidgetInstance->AddToViewport();

			FInputModeUIOnly Mode;
			Mode.SetWidgetToFocus(UIWidgetInstance->GetCachedWidget());
			SetInputMode(Mode);

			bShowMouseCursor = true;
		}
	}
}

void ADXTitlePlayerController::JoinServer(const FString& InIPAddress)
{
	FName NextLevelName = FName(*InIPAddress);
	UGameplayStatics::OpenLevel(GetWorld(), NextLevelName, true);
}
  • UUW_TitleLayout
...
void UUW_TitleLayout::OnPlayButtonClicked()
{
	ADXTitlePlayerController* PlayerController = GetOwningPlayer<ADXTitlePlayerController>();
	if (IsValid(PlayerController))
	{
		FText ServerIP = ServerIPEditableText->GetText();
		PlayerController->JoinServer(ServerIP.ToString());
	}
}

void UUW_TitleLayout::OnExitButtonClicked()
{
	UKismetSystemLibrary::QuitGame(this, GetOwningPlayer(), EQuitPreference::Quit, false);
}

 

2. GameMode & GameState


 

2 - 1. Overview

게임의 흐름

  • 서버 실행
  • 플레이어 접속을 체크
  • 인원 수가 채워지면 카운트다운 이후 게임 실행

이러한 서버 로직에 대해서는 "게임 모드"에서 처리해주어야 한다.

 

이후 서버가 모든 클라이언트에게 게임의 흐름에 있어서 발생한 정보를 전해주기 위해서 "게임 스테이트"를 사용

  • 게임 스테이트 액터는 각 클라이언트에게 복제된다.
  • Replicated 지정자 사용
UPROPERTY(Replicated, VisibleAnywhere, BlueprintReadOnly)
int32 AlivePlayerControllerCount = 0;
  • 클라이언트의 UI 구현에 있어서 게임 스테이트에 접근해서 정보를 가져오도록 한다.

 

2 - 2. 접속 관련 구현

  • DXGameModeBase
    • PostLogin, Logout 함수 override 하여 접속한 플레이어의 정보를 저장
//헤더 파일
virtual void PostLogin(APlayerController* NewPlayer) override;
virtual void Logout(AController* Existing) override;

//cpp 파일
void ADXGameModeBase::PostLogin(APlayerController* NewPlayer)
{
	Super::PostLogin(NewPlayer);

	ADXPlayerController* NewPlayerController = Cast<ADXPlayerController>(NewPlayer);
	if (IsValid(NewPlayerController))
	{
		AlivePlayerControllers.Add(NewPlayerController);
                //UI 출력
		NewPlayerController->NotificationText = FText::FromString(TEXT("Connected to the game server"));
	}	
}

void ADXGameModeBase::Logout(AController* Existing)
{
	Super::Logout(Existing);

	ADXPlayerController* ExistingPlayerController = Cast<ADXPlayerController>(Existing);
	if (IsValid(ExistingPlayerController) && AlivePlayerControllers.Find(ExistingPlayerController) != INDEX_NONE)
	{
		AlivePlayerControllers.Remove(ExistingPlayerController);
		DeadPlayerControllers.Add(ExistingPlayerController);
	}
}
  • DXPlayerController
    • 접속한 플레이어는 위쪽에 현재 상태(대기, 게임 시작 등)를 알려주는 Text UI 표시
    • 실제 UI에 text를 세팅하는 것은 BP의 Bind를 통해 구현
void ADXPlayerController::BeginPlay()
{
	Super::BeginPlay();

	//server check
	if (!IsLocalController())
	{
		return;
	}

	if (IsValid(NotificationTextUIClass))
	{
		UUserWidget* NotificationTextUI = CreateWidget<UUserWidget>(this, NotificationTextUIClass);
		if (IsValid(NotificationTextUI))
		{
			NotificationTextUI->AddToViewport(1);

			NotificationTextUI->SetVisibility(ESlateVisibility::Visible);
		}
	}
}

void ADXPlayerController::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);

	DOREPLIFETIME(ThisClass, NotificationText);
}

 

2 - 3. 게임 상태 관련 구현

게임 스테이트에서 플레이어를 기다리는 상태, 게임 시작 상태, 게임 종료 상태 등의 정보를 저장해두고

게임 모드에서는 게임 스테이트에서 상태를 가져와 그에 따라 처리를 해준다.

 

구현

  • DXGameStateBase
//헤더
UENUM(BlueprintType)
enum class EMatchState : uint8
{
	None,
	Waiting,
	Playing,
	Enging,
	End
};

UCLASS()
class SCC_DEDICATEDX_API ADXGameStateBase : public AGameStateBase
{
	GENERATED_BODY()
	
public:
	virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;

public:
	UPROPERTY(Replicated, VisibleAnywhere, BlueprintReadOnly)
	int32 AlivePlayerControllerCount = 0;

	UPROPERTY(Replicated, VisibleAnywhere, BlueprintReadOnly)
	EMatchState MatchState = EMatchState::Waiting;
};


//cpp
void ADXGameStateBase::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);

	DOREPLIFETIME(ThisClass, AlivePlayerControllerCount);
	DOREPLIFETIME(ThisClass, MatchState);
}
  • DXGameModeBase
    • 타이머를 통해 Main Loop를 돌리기
      • 매 틱마다 돌리는 것보다 과부화 줄일 수 있음
      • 타이머로 해도 괜찮을 정도로 널널한 생각해 봐야한다. (현재는 1초마다)
void ADXGameModeBase::BeginPlay()
{
	Super::BeginPlay();

	GetWorld()->GetTimerManager().SetTimer(MainTimerHandle, this, &ThisClass::OnMainTimerElapsed, 1.f, true);

	RemainWaitingTimeForPlaying = WaitingTime;
}

void ADXGameModeBase::OnMainTimerElapsed()
{
	ADXGameStateBase* DXGameState = GetGameState<ADXGameStateBase>();

	if (!IsValid(DXGameState))
	{
		return;
	}

	switch (DXGameState->MatchState)
	{
	case EMatchState::None:
		break;
	case EMatchState::Waiting:
	{
		FString NotificationString = FString::Printf(TEXT(""));
		if (AlivePlayerControllers.Num() < MinimumPlayerCountForPlaying)
		{
			NotificationString = FString::Printf(TEXT("Wait another players for playing"));

			RemainWaitingTimeForPlaying = WaitingTime;
		}
		else
		{
			NotificationString = FString::Printf(TEXT("Wait %d seconds for playing"), RemainWaitingTimeForPlaying);

			--RemainWaitingTimeForPlaying;
		}
		if (RemainWaitingTimeForPlaying <= 0)
		{
			NotificationString = FString::Printf(TEXT(""));
			DXGameState->MatchState = EMatchState::Playing;
		}
		NotifyToAllPlayer(NotificationString);
		break;
	}	
	case EMatchState::Playing:
		break;
	case EMatchState::Enging:
		break;
	case EMatchState::End:
		break;
	default:
		break;
	}
}

 

 

3. 


 

 

 

'Unreal Engine' 카테고리의 다른 글

Unreal Engine - 데디케이티드 서버 9 (게임 종료)  (0) 2025.05.04
Unreal Engine - AI (2)  (0) 2025.04.29
Unreal Engine - AI (1)  (1) 2025.04.25
Unreal Engine - 멀티플레이 네트워크 최적화 2  (0) 2025.04.23
Unreal Engine - 멀티플레이 네트워크 최적화 1  (0) 2025.04.22
'Unreal Engine' 카테고리의 다른 글
  • Unreal Engine - 데디케이티드 서버 9 (게임 종료)
  • Unreal Engine - AI (2)
  • Unreal Engine - AI (1)
  • Unreal Engine - 멀티플레이 네트워크 최적화 2
gbleem
gbleem
gbleem 님의 블로그 입니다.
  • gbleem
    gbleem 님의 블로그
    gbleem
  • 전체
    오늘
    어제
    • 분류 전체보기 (176)
      • Unreal Engine (66)
      • C++ (19)
      • 알고리즘(코딩테스트) (26)
      • TIL (60)
      • CS (4)
      • 툴 (1)
  • 블로그 메뉴

    • 홈
    • 카테고리
  • 링크

    • 과제용 깃허브
    • 깃허브
    • velog
  • 공지사항

  • 인기 글

  • 태그

    character animation
    템플릿
    싱글턴
    addonscreendebugmessage
    const
    motion matching
    enhanced input system
    C++
    상속
    DP
    BFS
    gamestate
    applydamage
    매크로 지정자
    additive animation
    map을 vector로 복사
    actor 클래스
    blend pose
    cin함수
    Vector
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
gbleem
Unreal Engine - 데디케이티드 서버 8 (게임 흐름)
상단으로

티스토리툴바