Unreal Engine

[ UE ] 훈련장모드 베이스 설계

닿메_dahme 2025. 4. 3. 22:52

훈련장 모드를 만들기 위해 베이스 구조를 설계해보았따.

가장 필요한 GameMode와 GameState를 설계했다.

 

BaseInGameMode

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/GameMode.h"
#include "BaseInGameMode.generated.h"

UCLASS()
class CCFF_API ABaseInGameMode : public AGameMode
{
	GENERATED_BODY()

public:
	ABaseInGameMode(const FObjectInitializer& ObjectInitializer);

	virtual void BeginPlay() override;

	UFUNCTION(BlueprintCallable, Category = "CCFF|GameMode|Round")
	virtual void StartRound();

	UFUNCTION(BlueprintCallable, Category = "CCFF|GameMode|Round")
	virtual void EndRound();

	UFUNCTION(BlueprintCallable, Category = "CCFF|GameMode|Round")
	virtual void CheckGameConditions();

protected:
	UPROPERTY(EditAnywhere, Category = "CCFF|GameMode|Round")
	float RoundDuration;

	UPROPERTY(EditAnywhere, Category = "CCFF|GameMode|Round")
	int32 MaxHP;

	FTimerHandle GameTimerHandle;

};
#include "Framework/GameMode/BaseInGameMode.h"
#include "Framework/GameState/BaseInGameState.h"

ABaseInGameMode::ABaseInGameMode(const FObjectInitializer & ObjectInitializer) : Super(ObjectInitializer)
{
	GameStateClass = ABaseInGameState::StaticClass();

	RoundDuration = 60.0f;
	MaxHP = 3;
}

void ABaseInGameMode::BeginPlay()
{
	Super::BeginPlay();

	StartRound();
}

void ABaseInGameMode::StartRound()
{
	UE_LOG(LogTemp, Log, TEXT("Start Round!"));

	GetWorldTimerManager().SetTimer(
		GameTimerHandle, this, &ABaseInGameMode::CheckGameConditions, 1.0f, true
		);
}

void ABaseInGameMode::EndRound()
{
	UE_LOG(LogTemp, Log, TEXT("End Round!"));

	GetWorldTimerManager().ClearTimer(GameTimerHandle);
}

void ABaseInGameMode::CheckGameConditions()
{
}

 

이렇게 게임 모드가 확장될 때마다 사용할 수 있게 필요한 부분들만 정의해주었다.

그리고 인게임에서는 항상 타이머가 작동되기때문에 타이머를 넣어주었다.

 

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/GameState.h"
#include "BaseInGameState.generated.h"


UENUM(BlueprintType)
enum class ERoundProgress : uint8
{
	NotStarted UMETA(DisplayName = "Not Started"),
	InProgress UMETA(DisplayName = "In Progress"),
	Ended UMETA(DisplayName = "Ended")
};


UCLASS()
class CCFF_API ABaseInGameState : public AGameState
{
	GENERATED_BODY()

public:
	ABaseInGameState();

	virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;

	UFUNCTION(BlueprintCallable, Category = "CCFF|GameState|HUD")
	virtual void UpdateHUDData();
	UFUNCTION(BlueprintCallable, Category = "CCFF|GameState|HUD")
	virtual void SetRemainingTime(float NewTime);
	UFUNCTION(BlueprintCallable, Category = "CCFF|GameState|HUD")
	virtual void SetRoundProgress(ERoundProgress NewProgress);

	UPROPERTY(BlueprintReadOnly, Replicated, Category = "CCFF|GameState|HUD")
	float RemainingTime;

	UPROPERTY(BlueprintReadOnly, Replicated, Category = "CCFF|GameState|HUD")
	ERoundProgress RoundProgress;

};
#include "Framework/GameState/BaseInGameState.h"
#include "Net/UnrealNetwork.h"

ABaseInGameState::ABaseInGameState()
{
	RemainingTime = 0.0f;
	RoundProgress = ERoundProgress::NotStarted;
}

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

	DOREPLIFETIME(ThisClass, RemainingTime);
	DOREPLIFETIME(ThisClass, RoundProgress);
}

void ABaseInGameState::UpdateHUDData()
{
	UE_LOG(LogTemp, Log, TEXT("HUD Updated: RemainingTime: %f, RoundProgress: %d"), RemainingTime, (uint8)RoundProgress);
}

void ABaseInGameState::SetRemainingTime(float NewTime)
{
	RemainingTime = NewTime;
	UpdateHUDData();
}

void ABaseInGameState::SetRoundProgress(ERoundProgress NewProgress)
{
	RoundProgress = NewProgress;
	UpdateHUDData();
}

 

그리고 GameState에서는 HUD 정보들과 필요한 정보들을 업데이트해주고, 복제할 수 있게 설정해주었다.

 

훈련장 배치는 이렇게 허수아비를 하나 두고, 시작하려고 설계했다.

 

UI  구조는 다음과 같이 설정했따.

네모박스는 BaseWidget으로 설정할려고 한다. 모든 모드에서 사용할 부분이라..

그리고 오른쪽 하단 부분은 훈련장에서만 필요한 부분들을 모아서 작업하려고 한다.

 

 

내일은 UI 위젯을 본격적으로 만들고 기능을 붙일 생각이다.

아자아자