Add core game mode framework
This commit is contained in:
@@ -6,3 +6,7 @@ CommonButtonAcceptKeyHandling=TriggerClick
|
||||
ProjectID=E7C26E1F4D195F0DBE49C2A3E5017988
|
||||
CopyrightNotice=
|
||||
|
||||
[/Script/EngineSettings.GameMapsSettings]
|
||||
GlobalDefaultGameMode=/Script/PHY.PHYGameModeBase
|
||||
GlobalDefaultServerGameMode=/Script/PHY.PHYGameModeBase
|
||||
|
||||
|
||||
@@ -3,3 +3,13 @@ ConfigVersion=1
|
||||
bMultiplayerFirst=True
|
||||
bPreferCodeAndConfig=True
|
||||
TargetPlatformName=Win64
|
||||
|
||||
[/Script/PHY.PHYGameFrameworkSettings]
|
||||
DefaultPawnClass="/Script/PHY.PHYPlayerCharacter"
|
||||
PlayerControllerClass="/Script/PHY.PHYPlayerController"
|
||||
PlayerStateClass="/Script/PHY.PHYPlayerState"
|
||||
GameStateClass="/Script/PHY.PHYGameState"
|
||||
HUDClass="/Script/PHY.PHYHUD"
|
||||
SpectatorClass="/Script/Engine.SpectatorPawn"
|
||||
bUseSeamlessTravel=True
|
||||
bStartPlayersAsSpectators=False
|
||||
|
||||
@@ -10,10 +10,14 @@
|
||||
#include "Class/PHYClassComponent.h"
|
||||
#include "Class/PHYClassSettings.h"
|
||||
#include "GGA_AbilitySystemComponent.h"
|
||||
#include "AI/PHYAIController.h"
|
||||
|
||||
APHYAICharacter::APHYAICharacter(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
AIControllerClass = APHYAIController::StaticClass();
|
||||
AutoPossessAI = EAutoPossessAI::PlacedInWorldOrSpawned;
|
||||
|
||||
AbilitySystemComponent = CreateDefaultSubobject<UGGA_AbilitySystemComponent>(TEXT("AbilitySystemComponent"));
|
||||
AbilitySystemComponent->SetIsReplicated(true);
|
||||
AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Mixed);
|
||||
|
||||
22
Source/PHY/Private/Game/PHYGameFrameworkSettings.cpp
Normal file
22
Source/PHY/Private/Game/PHYGameFrameworkSettings.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "Game/PHYGameFrameworkSettings.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYGameFrameworkSettings)
|
||||
|
||||
#include "Characters/PHYPlayerCharacter.h"
|
||||
#include "Game/PHYGameState.h"
|
||||
#include "Game/PHYHUD.h"
|
||||
#include "GameFramework/SpectatorPawn.h"
|
||||
#include "Player/PHYPlayerController.h"
|
||||
#include "Player/PHYPlayerState.h"
|
||||
|
||||
UPHYGameFrameworkSettings::UPHYGameFrameworkSettings()
|
||||
{
|
||||
DefaultPawnClass = APHYPlayerCharacter::StaticClass();
|
||||
PlayerControllerClass = APHYPlayerController::StaticClass();
|
||||
PlayerStateClass = APHYPlayerState::StaticClass();
|
||||
GameStateClass = APHYGameState::StaticClass();
|
||||
HUDClass = APHYHUD::StaticClass();
|
||||
SpectatorClass = ASpectatorPawn::StaticClass();
|
||||
}
|
||||
116
Source/PHY/Private/Game/PHYGameModeBase.cpp
Normal file
116
Source/PHY/Private/Game/PHYGameModeBase.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "Game/PHYGameModeBase.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYGameModeBase)
|
||||
|
||||
#include "Characters/PHYPlayerCharacter.h"
|
||||
#include "Game/PHYGameFrameworkSettings.h"
|
||||
#include "Game/PHYGameState.h"
|
||||
#include "Game/PHYHUD.h"
|
||||
#include "GameFramework/SpectatorPawn.h"
|
||||
#include "Player/PHYPlayerController.h"
|
||||
#include "Player/PHYPlayerState.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename TBase>
|
||||
void ApplyConfiguredClass(const TSoftClassPtr<TBase>& ConfiguredClass, TSubclassOf<TBase>& TargetClass)
|
||||
{
|
||||
if (ConfiguredClass.IsNull())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (UClass* LoadedClass = ConfiguredClass.LoadSynchronous())
|
||||
{
|
||||
TargetClass = LoadedClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
APHYGameModeBase::APHYGameModeBase(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
DefaultPawnClass = APHYPlayerCharacter::StaticClass();
|
||||
PlayerControllerClass = APHYPlayerController::StaticClass();
|
||||
PlayerStateClass = APHYPlayerState::StaticClass();
|
||||
GameStateClass = APHYGameState::StaticClass();
|
||||
HUDClass = APHYHUD::StaticClass();
|
||||
SpectatorClass = ASpectatorPawn::StaticClass();
|
||||
|
||||
bUseSeamlessTravel = true;
|
||||
bStartPlayersAsSpectators = false;
|
||||
}
|
||||
|
||||
void APHYGameModeBase::InitGame(const FString& MapName, const FString& Options, FString& ErrorMessage)
|
||||
{
|
||||
ApplyGameFrameworkSettings();
|
||||
|
||||
Super::InitGame(MapName, Options, ErrorMessage);
|
||||
}
|
||||
|
||||
void APHYGameModeBase::InitGameState()
|
||||
{
|
||||
Super::InitGameState();
|
||||
|
||||
SetGameFrameworkReady(false);
|
||||
}
|
||||
|
||||
void APHYGameModeBase::StartPlay()
|
||||
{
|
||||
Super::StartPlay();
|
||||
|
||||
SetGameFrameworkReady(true);
|
||||
}
|
||||
|
||||
void APHYGameModeBase::PostLogin(APlayerController* NewPlayer)
|
||||
{
|
||||
Super::PostLogin(NewPlayer);
|
||||
|
||||
// 玩家登录后的队伍、职业、存档恢复由后续对应系统在这里挂接。
|
||||
}
|
||||
|
||||
void APHYGameModeBase::Logout(AController* Exiting)
|
||||
{
|
||||
// 玩家退出前的持久化和队伍清理由后续对应系统在这里挂接。
|
||||
Super::Logout(Exiting);
|
||||
}
|
||||
|
||||
UClass* APHYGameModeBase::GetDefaultPawnClassForController_Implementation(AController* InController)
|
||||
{
|
||||
(void)InController;
|
||||
return DefaultPawnClass ? DefaultPawnClass.Get() : Super::GetDefaultPawnClassForController_Implementation(InController);
|
||||
}
|
||||
|
||||
APHYGameState* APHYGameModeBase::GetPHYGameState() const
|
||||
{
|
||||
return GetGameState<APHYGameState>();
|
||||
}
|
||||
|
||||
void APHYGameModeBase::ApplyGameFrameworkSettings()
|
||||
{
|
||||
const UPHYGameFrameworkSettings* Settings = GetDefault<UPHYGameFrameworkSettings>();
|
||||
if (!Settings)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ApplyConfiguredClass(Settings->DefaultPawnClass, DefaultPawnClass);
|
||||
ApplyConfiguredClass(Settings->PlayerControllerClass, PlayerControllerClass);
|
||||
ApplyConfiguredClass(Settings->PlayerStateClass, PlayerStateClass);
|
||||
ApplyConfiguredClass(Settings->GameStateClass, GameStateClass);
|
||||
ApplyConfiguredClass(Settings->HUDClass, HUDClass);
|
||||
ApplyConfiguredClass(Settings->SpectatorClass, SpectatorClass);
|
||||
|
||||
bUseSeamlessTravel = Settings->bUseSeamlessTravel;
|
||||
bStartPlayersAsSpectators = Settings->bStartPlayersAsSpectators;
|
||||
}
|
||||
|
||||
void APHYGameModeBase::SetGameFrameworkReady(const bool bNewReady)
|
||||
{
|
||||
if (APHYGameState* PHYGameState = GetPHYGameState())
|
||||
{
|
||||
PHYGameState->SetGameFrameworkReady(bNewReady);
|
||||
}
|
||||
}
|
||||
36
Source/PHY/Private/Game/PHYGameState.cpp
Normal file
36
Source/PHY/Private/Game/PHYGameState.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "Game/PHYGameState.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYGameState)
|
||||
|
||||
#include "Net/UnrealNetwork.h"
|
||||
|
||||
APHYGameState::APHYGameState(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
bReplicates = true;
|
||||
}
|
||||
|
||||
void APHYGameState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
|
||||
{
|
||||
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
||||
|
||||
DOREPLIFETIME(ThisClass, bGameFrameworkReady);
|
||||
}
|
||||
|
||||
void APHYGameState::SetGameFrameworkReady(const bool bNewReady)
|
||||
{
|
||||
if (!HasAuthority())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bGameFrameworkReady = bNewReady;
|
||||
OnRep_GameFrameworkReady();
|
||||
}
|
||||
|
||||
void APHYGameState::OnRep_GameFrameworkReady()
|
||||
{
|
||||
// 预留给 HUD、UI 或战局阶段系统监听框架就绪状态。
|
||||
}
|
||||
28
Source/PHY/Private/Game/PHYHUD.cpp
Normal file
28
Source/PHY/Private/Game/PHYHUD.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "Game/PHYHUD.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYHUD)
|
||||
|
||||
APHYHUD::APHYHUD(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
}
|
||||
|
||||
void APHYHUD::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
InitializeHUDForPlayer(GetOwningPlayerController());
|
||||
}
|
||||
|
||||
void APHYHUD::InitializeHUDForPlayer(APlayerController* OwningPlayerController)
|
||||
{
|
||||
if (!OwningPlayerController || bHUDInitialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// UI 专家后续在这里接入 GenericUISystem/CommonUI 的根层级。
|
||||
bHUDInitialized = true;
|
||||
}
|
||||
63
Source/PHY/Public/Game/PHYGameFrameworkSettings.h
Normal file
63
Source/PHY/Public/Game/PHYGameFrameworkSettings.h
Normal file
@@ -0,0 +1,63 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "UObject/Object.h"
|
||||
#include "UObject/SoftObjectPtr.h"
|
||||
#include "PHYGameFrameworkSettings.generated.h"
|
||||
|
||||
class AGameStateBase;
|
||||
class AHUD;
|
||||
class APawn;
|
||||
class APlayerController;
|
||||
class APlayerState;
|
||||
class ASpectatorPawn;
|
||||
|
||||
/**
|
||||
* @brief PHY 游戏框架默认类配置。
|
||||
*
|
||||
* GameMode 会优先使用这里配置的类,未配置时回退到项目 C++ 原生骨架。
|
||||
* 这样后续需要替换为蓝图子类时,只需要改配置,不需要改业务代码。
|
||||
*/
|
||||
UCLASS(Config=PHYCore, DefaultConfig)
|
||||
class PHY_API UPHYGameFrameworkSettings : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/** @brief 构造默认 C++ 框架类引用。 */
|
||||
UPHYGameFrameworkSettings();
|
||||
|
||||
/** @brief 默认玩家 Pawn 类。 */
|
||||
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Game")
|
||||
TSoftClassPtr<APawn> DefaultPawnClass;
|
||||
|
||||
/** @brief 默认玩家控制器类。 */
|
||||
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Game")
|
||||
TSoftClassPtr<APlayerController> PlayerControllerClass;
|
||||
|
||||
/** @brief 默认玩家状态类。 */
|
||||
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Game")
|
||||
TSoftClassPtr<APlayerState> PlayerStateClass;
|
||||
|
||||
/** @brief 默认游戏状态类。 */
|
||||
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Game")
|
||||
TSoftClassPtr<AGameStateBase> GameStateClass;
|
||||
|
||||
/** @brief 默认 HUD 类。 */
|
||||
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Game")
|
||||
TSoftClassPtr<AHUD> HUDClass;
|
||||
|
||||
/** @brief 默认旁观者 Pawn 类。 */
|
||||
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Game")
|
||||
TSoftClassPtr<ASpectatorPawn> SpectatorClass;
|
||||
|
||||
/** @brief 是否启用无缝旅行,默认按多人优先启用。 */
|
||||
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Game")
|
||||
bool bUseSeamlessTravel = true;
|
||||
|
||||
/** @brief 是否让玩家默认以旁观者身份开始。 */
|
||||
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Game")
|
||||
bool bStartPlayersAsSpectators = false;
|
||||
};
|
||||
54
Source/PHY/Public/Game/PHYGameModeBase.h
Normal file
54
Source/PHY/Public/Game/PHYGameModeBase.h
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/GameModeBase.h"
|
||||
#include "PHYGameModeBase.generated.h"
|
||||
|
||||
class APHYGameState;
|
||||
|
||||
/**
|
||||
* @brief PHY 游戏模式根类。
|
||||
*
|
||||
* GameMode 是服务端玩法框架入口,负责绑定默认 Pawn、Controller、PlayerState、
|
||||
* GameState 和 HUD。具体玩法系统仍通过 Character、ASC、输入和组件完成。
|
||||
*/
|
||||
UCLASS(BlueprintType, Blueprintable)
|
||||
class PHY_API APHYGameModeBase : public AGameModeBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/** @brief 构造默认项目框架类。 */
|
||||
APHYGameModeBase(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());
|
||||
|
||||
/** @brief 初始化地图参数并应用项目框架配置。 */
|
||||
virtual void InitGame(const FString& MapName, const FString& Options, FString& ErrorMessage) override;
|
||||
|
||||
/** @brief GameState 初始化后同步项目框架状态。 */
|
||||
virtual void InitGameState() override;
|
||||
|
||||
/** @brief 游戏正式开始时标记框架就绪。 */
|
||||
virtual void StartPlay() override;
|
||||
|
||||
/** @brief 玩家登录后执行项目级初始化扩展点。 */
|
||||
virtual void PostLogin(APlayerController* NewPlayer) override;
|
||||
|
||||
/** @brief 玩家退出时执行项目级清理扩展点。 */
|
||||
virtual void Logout(AController* Exiting) override;
|
||||
|
||||
/** @brief 按控制器返回默认 Pawn 类,后续可扩展职业或模式差异。 */
|
||||
virtual UClass* GetDefaultPawnClassForController_Implementation(AController* InController) override;
|
||||
|
||||
/** @brief 获取强类型 PHY GameState。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Game")
|
||||
APHYGameState* GetPHYGameState() const;
|
||||
|
||||
protected:
|
||||
/** @brief 从 UPHYGameFrameworkSettings 应用可配置框架类。 */
|
||||
virtual void ApplyGameFrameworkSettings();
|
||||
|
||||
/** @brief 标记 GameState 框架是否就绪。 */
|
||||
virtual void SetGameFrameworkReady(bool bNewReady);
|
||||
};
|
||||
43
Source/PHY/Public/Game/PHYGameState.h
Normal file
43
Source/PHY/Public/Game/PHYGameState.h
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/GameStateBase.h"
|
||||
#include "PHYGameState.generated.h"
|
||||
|
||||
/**
|
||||
* @brief PHY 游戏状态。
|
||||
*
|
||||
* 当前只承载项目框架是否完成初始化的复制状态,后续战局阶段、队伍比分、
|
||||
* 复活队列等多人状态都应优先汇总到这里,而不是散落在关卡蓝图。
|
||||
*/
|
||||
UCLASS(BlueprintType, Blueprintable)
|
||||
class PHY_API APHYGameState : public AGameStateBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/** @brief 构造游戏状态并启用复制。 */
|
||||
APHYGameState(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());
|
||||
|
||||
/** @brief 声明需要复制的属性。 */
|
||||
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
|
||||
|
||||
/** @brief 查询游戏框架是否已由服务端标记为就绪。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Game")
|
||||
bool IsGameFrameworkReady() const { return bGameFrameworkReady; }
|
||||
|
||||
/** @brief 服务端设置游戏框架就绪状态。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category="PHY|Game")
|
||||
void SetGameFrameworkReady(bool bNewReady);
|
||||
|
||||
protected:
|
||||
/** @brief 客户端接收框架就绪状态后的扩展点。 */
|
||||
UFUNCTION()
|
||||
virtual void OnRep_GameFrameworkReady();
|
||||
|
||||
/** @brief 服务端确认 GameMode 已完成基础类和玩家流程初始化。 */
|
||||
UPROPERTY(ReplicatedUsing=OnRep_GameFrameworkReady, BlueprintReadOnly, Category="PHY|Game")
|
||||
bool bGameFrameworkReady = false;
|
||||
};
|
||||
39
Source/PHY/Public/Game/PHYHUD.h
Normal file
39
Source/PHY/Public/Game/PHYHUD.h
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/HUD.h"
|
||||
#include "PHYHUD.generated.h"
|
||||
|
||||
/**
|
||||
* @brief PHY HUD 根入口。
|
||||
*
|
||||
* 首期只提供 C++ HUD 生命周期入口。真正 UI 由后续 GenericUISystem/CommonUI
|
||||
* 专家接入,避免在 GameMode 或 PlayerController 中直接堆 UMG 装配逻辑。
|
||||
*/
|
||||
UCLASS(BlueprintType, Blueprintable)
|
||||
class PHY_API APHYHUD : public AHUD
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/** @brief 构造 HUD 根入口。 */
|
||||
APHYHUD(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());
|
||||
|
||||
/** @brief HUD 开始运行时初始化玩家 UI 入口。 */
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
/** @brief 初始化当前玩家的 HUD 逻辑。 */
|
||||
UFUNCTION(BlueprintCallable, Category="PHY|UI")
|
||||
virtual void InitializeHUDForPlayer(APlayerController* OwningPlayerController);
|
||||
|
||||
/** @brief 查询 HUD 是否已经完成初始化。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|UI")
|
||||
bool IsHUDInitialized() const { return bHUDInitialized; }
|
||||
|
||||
protected:
|
||||
/** @brief HUD 是否已经完成基础初始化。 */
|
||||
UPROPERTY(Transient, BlueprintReadOnly, Category="PHY|UI")
|
||||
bool bHUDInitialized = false;
|
||||
};
|
||||
Reference in New Issue
Block a user