ue-game-features
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseUE Game Features and Modular Gameplay
UE Game Features 与模块化玩法
You are an expert in Unreal Engine's Game Features plugin system and modular gameplay architecture.
你是Unreal Engine的Game Features插件系统和模块化玩法架构方面的专家。
Context Check
上下文检查
Read before proceeding. Determine:
.agents/ue-project-context.md- Whether the and
GameFeaturesplugins are enabledModularGameplay - Which actors register as component receivers ()
AddReceiver - Whether the project uses an init state system or experience-based loading
- Existing subclasses or modular component base classes
UGameFeatureAction
在开始操作前,请阅读,确定以下内容:
.agents/ue-project-context.md- 和
GameFeatures插件是否已启用ModularGameplay - 哪些Actor注册为组件接收者(调用)
AddReceiver - 项目是否使用初始化状态系统或基于体验的加载机制
- 已有的子类或模块化组件基类
UGameFeatureAction
Information Gathering
信息收集
Ask the developer:
- Are you creating a new Game Feature plugin or extending an existing one?
- What components or abilities should the feature inject into gameplay actors?
- Does the feature need async loading or runtime activation/deactivation?
- Is there an experience/game mode composition system (Lyra-style)?
- Do components need ordered initialization across features?
请向开发者询问以下问题:
- 你是要创建新的Game Feature插件,还是扩展现有插件?
- 该功能需要向游戏玩法Actor中注入哪些组件或能力?
- 该功能是否需要异步加载或运行时激活/停用?
- 项目是否有体验/游戏模式组合系统(Lyra风格)?
- 组件是否需要跨功能按顺序初始化?
Game Feature Plugin Structure
Game Feature插件结构
A Game Feature plugin is a standard UE plugin with set to in its descriptor. This tells the engine to manage its lifecycle through the Game Features subsystem rather than loading it as a regular plugin.
Type"GameFeature".upluginGame Feature插件是标准的UE插件,其描述文件中的需设置为。这会告知引擎通过Game Features子系统管理其生命周期,而非作为常规插件加载。
.upluginType"GameFeature".uplugin Descriptor
.uplugin描述文件
cpp
{
"Type": "GameFeature",
"BuiltInInitialFeatureState": "Active", // or "Registered", "Installed"
"Plugins": [
{ "Name": "GameFeatures", "Enabled": true },
{ "Name": "ModularGameplay", "Enabled": true }
]
}BuiltInInitialFeatureState"Active""Registered""Installed"cpp
{
"Type": "GameFeature",
"BuiltInInitialFeatureState": "Active", // 可选值:"Registered"、"Installed"
"Plugins": [
{ "Name": "GameFeatures", "Enabled": true },
{ "Name": "ModularGameplay", "Enabled": true }
]
}BuiltInInitialFeatureState"Active""Registered""Installed"UGameFeatureData
UGameFeatureData
Each Game Feature plugin contains a primary data asset (extends ) that defines what the feature does:
UGameFeatureDataUPrimaryDataAssetcpp
// From GameFeatureData.h
UPROPERTY(EditDefaultsOnly, Instanced, Category = "Game Feature | Actions")
TArray<TObjectPtr<UGameFeatureAction>> Actions;
UPROPERTY(EditAnywhere, Category = "Game Feature | Asset Manager")
TArray<FPrimaryAssetTypeInfo> PrimaryAssetTypesToScan;ActionsUGameFeatureAction每个Game Feature插件都包含一个主数据资产(继承自),用于定义该功能的作用:
UGameFeatureDataUPrimaryDataAssetcpp
// 来自GameFeatureData.h
UPROPERTY(EditDefaultsOnly, Instanced, Category = "Game Feature | Actions")
TArray<TObjectPtr<UGameFeatureAction>> Actions;
UPROPERTY(EditAnywhere, Category = "Game Feature | Asset Manager")
TArray<FPrimaryAssetTypeInfo> PrimaryAssetTypesToScan;ActionsUGameFeatureActionDirectory Convention
目录规范
Plugins/GameFeatures/
├── ShooterCore/
│ ├── ShooterCore.uplugin (Type: GameFeature)
│ ├── Content/
│ │ └── ShooterCore.uasset (UGameFeatureData)
│ └── Source/ShooterCoreRuntime/
└── DeathmatchRules/
├── DeathmatchRules.uplugin
└── Content/DeathmatchRules.uassetPlugins/GameFeatures/
├── ShooterCore/
│ ├── ShooterCore.uplugin (Type: GameFeature)
│ ├── Content/
│ │ └── ShooterCore.uasset (UGameFeatureData)
│ └── Source/ShooterCoreRuntime/
└── DeathmatchRules/
├── DeathmatchRules.uplugin
└── Content/DeathmatchRules.uassetPlugin State Machine
插件状态机
Game Feature plugins transition through a well-defined state machine. Actions fire at specific transitions and runtime activation must target valid destination states.
Game Feature插件会按照定义明确的状态机进行状态转换。动作会在特定转换节点触发,且运行时激活必须针对有效的目标状态。
EGameFeaturePluginState Lifecycle
EGameFeaturePluginState生命周期
Uninitialized → Terminal → UnknownStatus → StatusKnown
→ Installed → Registered → Loaded → ActiveEach major state has transition states between them (e.g., , , ). You target a destination state and the subsystem walks the chain.
RegisteringLoadingActivatingUninitialized → Terminal → UnknownStatus → StatusKnown
→ Installed → Registered → Loaded → Active每个主要状态之间都有过渡状态(例如、、)。你只需指定目标状态,子系统就会自动完成整个状态链的转换。
RegisteringLoadingActivatingDestination States
目标状态
| State | Description |
|---|---|
| Plugin removed from tracking entirely |
| Availability confirmed (exists on disk or bundle) |
| Files on local storage, not yet registered |
| Assets registered with Asset Manager, actions notified |
| Assets loaded into memory |
| Actions fully activated, components injected |
URL protocols: for built-in disk plugins, for downloadable features. Convert descriptor path to URL with .
file:installbundle:UGameFeaturesSubsystem::GetPluginURL_FileProtocol(Path)| 状态 | 描述 |
|---|---|
| 插件完全从跟踪列表中移除 |
| 确认插件可用(存在于磁盘或包中) |
| 文件已存储在本地,但尚未注册 |
| 资产已在Asset Manager中注册,动作已收到通知 |
| 资产已加载到内存中 |
| 动作已完全激活,组件已注入 |
URL协议:内置磁盘插件使用,可下载功能使用。使用将描述文件路径转换为URL。
file:installbundle:UGameFeaturesSubsystem::GetPluginURL_FileProtocol(Path)UGameFeatureAction
UGameFeatureAction
UGameFeatureActionUCLASS(MinimalAPI, DefaultToInstanced, EditInlineNew, Abstract)DefaultToInstancedEditInlineNewUGameFeatureDataActionsUGameFeatureActionUCLASS(MinimalAPI, DefaultToInstanced, EditInlineNew, Abstract)DefaultToInstancedEditInlineNewUGameFeatureDataActionsLifecycle Methods
生命周期方法
cpp
// Registration phase
virtual void OnGameFeatureRegistering();
virtual void OnGameFeatureUnregistering();
// Loading phase
virtual void OnGameFeatureLoading();
virtual void OnGameFeatureUnloading();
// Activation — primary override point
virtual void OnGameFeatureActivating(FGameFeatureActivatingContext& Context);
virtual void OnGameFeatureActivating(); // legacy no-arg fallback
// Post-activation confirmation
virtual void OnGameFeatureActivated();
// Deactivation — supports async via context
virtual void OnGameFeatureDeactivating(FGameFeatureDeactivatingContext& Context);OnGameFeatureActivating(Context)cpp
// 注册阶段
virtual void OnGameFeatureRegistering();
virtual void OnGameFeatureUnregistering();
// 加载阶段
virtual void OnGameFeatureLoading();
virtual void OnGameFeatureUnloading();
// 激活——主要重写点
virtual void OnGameFeatureActivating(FGameFeatureActivatingContext& Context);
virtual void OnGameFeatureActivating(); // 遗留的无参回退方法
// 激活后确认
virtual void OnGameFeatureActivated();
// 停用——通过上下文支持异步操作
virtual void OnGameFeatureDeactivating(FGameFeatureDeactivatingContext& Context);OnGameFeatureActivating(Context)Async Deactivation
异步停用
When deactivation requires async work, pause it via the context:
cpp
void UMyAction::OnGameFeatureDeactivating(FGameFeatureDeactivatingContext& Context)
{
FSimpleDelegate ResumeDelegate = Context.PauseDeactivationUntilComplete(
TEXT("MyAction_AsyncCleanup"));
// Start async work — MUST invoke ResumeDelegate when done or deactivation hangs
AsyncTask(ENamedThreads::GameThread, [ResumeDelegate]()
{
// ... cleanup ...
ResumeDelegate.ExecuteIfBound();
});
}See for complete custom action subclass templates.
references/game-feature-patterns.md当停用需要异步操作时,可通过上下文暂停停用流程:
cpp
void UMyAction::OnGameFeatureDeactivating(FGameFeatureDeactivatingContext& Context)
{
FSimpleDelegate ResumeDelegate = Context.PauseDeactivationUntilComplete(
TEXT("MyAction_AsyncCleanup"));
// 启动异步操作——完成后必须调用ResumeDelegate,否则停用流程会挂起
AsyncTask(ENamedThreads::GameThread, [ResumeDelegate]()
{
// ... 清理操作 ...
ResumeDelegate.ExecuteIfBound();
});
}完整的自定义动作子类模板请查看。
references/game-feature-patterns.mdBuilt-in Actions
内置动作
UGameFeatureAction_AddComponents
UGameFeatureAction_AddComponents
UCLASS(MinimalAPI, meta=(DisplayName="Add Components"), final)UGameFrameworkComponentManagerConfiguration uses :
FGameFeatureComponentEntrycpp
UPROPERTY(EditAnywhere) TSoftClassPtr<AActor> ActorClass;
UPROPERTY(EditAnywhere) TSoftClassPtr<UActorComponent> ComponentClass;
UPROPERTY(EditAnywhere) uint8 bClientComponent : 1;
UPROPERTY(EditAnywhere) uint8 bServerComponent : 1;Internally stores — RAII removes components when the handle drops (feature deactivates). Set both and for components needed everywhere, server-only for gameplay logic, client-only for cosmetic.
TSharedPtr<FComponentRequestHandle>bClientComponentbServerComponentUCLASS(MinimalAPI, meta=(DisplayName="Add Components"), final)UGameFrameworkComponentManager配置使用:
FGameFeatureComponentEntrycpp
UPROPERTY(EditAnywhere) TSoftClassPtr<AActor> ActorClass;
UPROPERTY(EditAnywhere) TSoftClassPtr<UActorComponent> ComponentClass;
UPROPERTY(EditAnywhere) uint8 bClientComponent : 1;
UPROPERTY(EditAnywhere) uint8 bServerComponent : 1;内部存储——当句柄销毁时(功能停用),RAII机制会自动移除组件。如果组件需要在客户端和服务端都存在,则同时设置和;仅游戏逻辑使用的组件设为服务端专用;仅 cosmetic(外观)组件设为客户端专用。
TSharedPtr<FComponentRequestHandle>bClientComponentbServerComponentOther Built-in Actions
其他内置动作
| Action | Purpose |
|---|---|
| Register cheat manager extensions |
| Register data registry sources |
| 动作 | 用途 |
|---|---|
| 注册作弊管理器扩展 |
| 注册数据注册表源 |
UGameFeaturesSubsystem
UGameFeaturesSubsystem
UGameFeaturesSubsystemUEngineSubsystemcpp
UGameFeaturesSubsystem& GFS = UGameFeaturesSubsystem::Get();UGameFeaturesSubsystemUEngineSubsystemcpp
UGameFeaturesSubsystem& GFS = UGameFeaturesSubsystem::Get();Runtime Activation and Deactivation
运行时激活与停用
cpp
FString PluginURL = UGameFeaturesSubsystem::GetPluginURL_FileProtocol(
TEXT("/MyProject/Plugins/GameFeatures/MyFeature/MyFeature.uplugin"));
// Activate — callback receives const UE::GameFeatures::FResult&
GFS.LoadAndActivateGameFeaturePlugin(PluginURL,
FGameFeaturePluginLoadComplete::CreateUObject(this, &UMyMgr::OnLoaded));
// Deactivate and unload
GFS.DeactivateGameFeaturePlugin(PluginURL);
GFS.UnloadGameFeaturePlugin(PluginURL, /*bKeepRegistered=*/ false);
// Or target a specific state:
GFS.ChangeGameFeatureTargetState(PluginURL, EGameFeatureTargetState::Registered,
FGameFeaturePluginChangeStateComplete());cpp
FString PluginURL = UGameFeaturesSubsystem::GetPluginURL_FileProtocol(
TEXT("/MyProject/Plugins/GameFeatures/MyFeature/MyFeature.uplugin"));
// 激活——回调接收const UE::GameFeatures::FResult&
GFS.LoadAndActivateGameFeaturePlugin(PluginURL,
FGameFeaturePluginLoadComplete::CreateUObject(this, &UMyMgr::OnLoaded));
// 停用并卸载
GFS.DeactivateGameFeaturePlugin(PluginURL);
GFS.UnloadGameFeaturePlugin(PluginURL, /*bKeepRegistered=*/ false);
// 或者指定特定目标状态:
GFS.ChangeGameFeatureTargetState(PluginURL, EGameFeatureTargetState::Registered,
FGameFeaturePluginChangeStateComplete());Query and Observe
查询与监听
cpp
bool bActive = GFS.IsGameFeaturePluginActive(PluginURL, /*bCheckForActivating=*/ false);
EGameFeaturePluginState State = GFS.GetPluginState(PluginURL);
// Global observer — implement IGameFeatureStateChangeObserver
GFS.AddObserver(MyObserver, UGameFeaturesSubsystem::EObserverPluginStateUpdateMode::CurrentAndFuture);
GFS.RemoveObserver(MyObserver);IGameFeatureStateChangeObserverOnGameFeatureRegistering(Data, PluginName, URL)OnGameFeatureActivating(Data, URL)OnGameFeatureDeactivating(Data, Context, URL)cpp
bool bActive = GFS.IsGameFeaturePluginActive(PluginURL, /*bCheckForActivating=*/ false);
EGameFeaturePluginState State = GFS.GetPluginState(PluginURL);
// 全局监听——实现IGameFeatureStateChangeObserver
GFS.AddObserver(MyObserver, UGameFeaturesSubsystem::EObserverPluginStateUpdateMode::CurrentAndFuture);
GFS.RemoveObserver(MyObserver);IGameFeatureStateChangeObserverOnGameFeatureRegistering(Data, PluginName, URL)OnGameFeatureActivating(Data, URL)OnGameFeatureDeactivating(Data, Context, URL)Component Injection System
组件注入系统
UGameFrameworkComponentManagerUGameInstanceSubsystemcpp
UGameFrameworkComponentManager* CompMgr =
GetGameInstance()->GetSubsystem<UGameFrameworkComponentManager>();UGameFrameworkComponentManagerUGameInstanceSubsystemcpp
UGameFrameworkComponentManager* CompMgr =
GetGameInstance()->GetSubsystem<UGameFrameworkComponentManager>();Actor Registration (Receivers)
Actor注册(接收者)
Actors must register as receivers to accept injected components:
cpp
void AMyCharacter::BeginPlay()
{
Super::BeginPlay();
UGameFrameworkComponentManager::AddGameFrameworkComponentReceiver(this);
}
void AMyCharacter::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
UGameFrameworkComponentManager::RemoveGameFrameworkComponentReceiver(this);
Super::EndPlay(EndPlayReason);
}Actor必须注册为接收者才能接受注入的组件:
cpp
void AMyCharacter::BeginPlay()
{
Super::BeginPlay();
UGameFrameworkComponentManager::AddGameFrameworkComponentReceiver(this);
}
void AMyCharacter::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
UGameFrameworkComponentManager::RemoveGameFrameworkComponentReceiver(this);
Super::EndPlay(EndPlayReason);
}Component Requests (RAII)
组件请求(RAII机制)
cpp
TSharedPtr<FComponentRequestHandle> Handle = CompMgr->AddComponentRequest(
TSoftClassPtr<AActor>(AMyCharacter::StaticClass()),
UMyHealthComponent::StaticClass(),
EGameFrameworkAddComponentFlags::AddUnique);
// Handle is RAII — destroying it removes the request and cleans up injected components| Flag | Value | Behavior |
|---|---|---|
| 0 | Default, allows duplicates |
| 1 | Skip if same class already exists |
| 2 | Skip if a child class already exists |
| 4 | Auto-generated name instead of class name |
cpp
TSharedPtr<FComponentRequestHandle> Handle = CompMgr->AddComponentRequest(
TSoftClassPtr<AActor>(AMyCharacter::StaticClass()),
UMyHealthComponent::StaticClass(),
EGameFrameworkAddComponentFlags::AddUnique);
// Handle遵循RAII机制——销毁它会移除请求并清理注入的组件| 标志 | 值 | 行为 |
|---|---|---|
| 0 | 默认值,允许重复添加 |
| 1 | 如果已存在相同类的组件,则跳过 |
| 2 | 如果已存在子类组件,则跳过 |
| 4 | 使用自动生成的名称而非类名 |
Extension Handlers and Events
扩展处理器与事件
cpp
TSharedPtr<FComponentRequestHandle> ExtHandle = CompMgr->AddExtensionHandler(
TSoftClassPtr<AActor>(AMyCharacter::StaticClass()),
FExtensionHandlerDelegate::CreateUObject(this, &UMyAction::OnExtension));
void UMyAction::OnExtension(AActor* Actor, FName EventName)
{
if (EventName == UGameFrameworkComponentManager::NAME_GameActorReady)
{ /* Actor fully initialized */ }
}Standard event names: , , , , . Send custom events with .
NAME_ReceiverAddedNAME_ReceiverRemovedNAME_ExtensionAddedNAME_ExtensionRemovedNAME_GameActorReadyCompMgr->SendExtensionEvent(Actor, FName("MyEvent"))cpp
TSharedPtr<FComponentRequestHandle> ExtHandle = CompMgr->AddExtensionHandler(
TSoftClassPtr<AActor>(AMyCharacter::StaticClass()),
FExtensionHandlerDelegate::CreateUObject(this, &UMyAction::OnExtension));
void UMyAction::OnExtension(AActor* Actor, FName EventName)
{
if (EventName == UGameFrameworkComponentManager::NAME_GameActorReady)
{ /* Actor已完全初始化 */ }
}标准事件名称:、、、、。使用发送自定义事件。
NAME_ReceiverAddedNAME_ReceiverRemovedNAME_ExtensionAddedNAME_ExtensionRemovedNAME_GameActorReadyCompMgr->SendExtensionEvent(Actor, FName("MyEvent"))Init State System
初始化状态系统
The init state system solves ordered initialization across independently-loaded features. Without it, Component A might read from Component B before B exists — a common problem in modular architectures.
初始化状态系统解决了独立加载的功能之间的有序初始化问题。如果没有该系统,组件A可能会在组件B存在之前读取其数据——这是模块化架构中的常见问题。
Registering Init States
注册初始化状态
Define project-wide init states as values in a fixed order:
FGameplayTagcpp
CompMgr->RegisterInitState(TAG_InitState_Spawning, false, FGameplayTag());
CompMgr->RegisterInitState(TAG_InitState_DataAvailable, false, TAG_InitState_Spawning);
CompMgr->RegisterInitState(TAG_InitState_DataInitialized, false, TAG_InitState_DataAvailable);
CompMgr->RegisterInitState(TAG_InitState_GameplayReady, false, TAG_InitState_DataInitialized);将项目级的初始化状态定义为值,并按固定顺序排列:
FGameplayTagcpp
CompMgr->RegisterInitState(TAG_InitState_Spawning, false, FGameplayTag());
CompMgr->RegisterInitState(TAG_InitState_DataAvailable, false, TAG_InitState_Spawning);
CompMgr->RegisterInitState(TAG_InitState_DataInitialized, false, TAG_InitState_DataAvailable);
CompMgr->RegisterInitState(TAG_InitState_GameplayReady, false, TAG_InitState_DataInitialized);Changing and Observing Init State
更改与监听初始化状态
cpp
// Advance a feature's state
bool bChanged = CompMgr->ChangeFeatureInitState(
MyActor, FName("MyComponent"), this, TAG_InitState_DataAvailable);
// Wait for another feature to reach a state
FDelegateHandle DH = CompMgr->RegisterAndCallForActorInitState(
MyActor, FName("OtherComp"), TAG_InitState_DataInitialized,
FActorInitStateChangedDelegate::CreateUObject(this, &UMyComp::OnOtherReady),
/*bCallImmediately=*/ true);
// Check if all features reached a state
bool bAllReady = CompMgr->HaveAllFeaturesReachedInitState(
MyActor, TAG_InitState_GameplayReady, /*ExcludingFeature=*/ NAME_None);cpp
// 推进某个功能的状态
bool bChanged = CompMgr->ChangeFeatureInitState(
MyActor, FName("MyComponent"), this, TAG_InitState_DataAvailable);
// 等待另一个功能达到指定状态
FDelegateHandle DH = CompMgr->RegisterAndCallForActorInitState(
MyActor, FName("OtherComp"), TAG_InitState_DataInitialized,
FActorInitStateChangedDelegate::CreateUObject(this, &UMyComp::OnOtherReady),
/*bCallImmediately=*/ true);
// 检查所有功能是否都达到指定状态
bool bAllReady = CompMgr->HaveAllFeaturesReachedInitState(
MyActor, TAG_InitState_GameplayReady, /*ExcludingFeature=*/ NAME_None);IGameFrameworkInitStateInterface
IGameFrameworkInitStateInterface
Implement on components for structured init state progression:
cpp
UCLASS()
class UMyModularComponent : public UPawnComponent,
public IGameFrameworkInitStateInterface
{
GENERATED_BODY()
public:
virtual FName GetFeatureName() const override { return TEXT("MyFeature"); }
virtual bool CanChangeInitState(UGameFrameworkComponentManager* Manager,
FGameplayTag CurrentState, FGameplayTag DesiredState) const override;
virtual void HandleChangeInitState(UGameFrameworkComponentManager* Manager,
FGameplayTag CurrentState, FGameplayTag DesiredState) override;
virtual void CheckDefaultInitialization() override;
virtual void BeginPlay() override
{
Super::BeginPlay();
RegisterInitStateFeature();
}
virtual void EndPlay(const EEndPlayReason::Type Reason) override
{
UnregisterInitStateFeature();
Super::EndPlay(Reason);
}
};ContinueInitStateChain(TArray<FGameplayTag>{State1, State2, State3})CheckDefaultInitialization在组件上实现该接口以实现结构化的初始化状态推进:
cpp
UCLASS()
class UMyModularComponent : public UPawnComponent,
public IGameFrameworkInitStateInterface
{
GENERATED_BODY()
public:
virtual FName GetFeatureName() const override { return TEXT("MyFeature"); }
virtual bool CanChangeInitState(UGameFrameworkComponentManager* Manager,
FGameplayTag CurrentState, FGameplayTag DesiredState) const override;
virtual void HandleChangeInitState(UGameFrameworkComponentManager* Manager,
FGameplayTag CurrentState, FGameplayTag DesiredState) override;
virtual void CheckDefaultInitialization() override;
virtual void BeginPlay() override
{
Super::BeginPlay();
RegisterInitStateFeature();
}
virtual void EndPlay(const EEndPlayReason::Type Reason) override
{
UnregisterInitStateFeature();
Super::EndPlay(Reason);
}
};ContinueInitStateChain(TArray<FGameplayTag>{State1, State2, State3})CheckDefaultInitializationModular Component Hierarchy
模块化组件层级
The plugin provides typed base components for gameplay framework actors:
ModularGameplay| Base Class | Parent | Typed Accessor |
|---|---|---|
| | None (generic base) |
| | |
| | |
| | |
| | |
Use these instead of raw for type-safe owner access and init state integration.
UActorComponentModularGameplay| 基类 | 父类 | 类型化访问器 |
|---|---|---|
| | 无(通用基类) |
| | |
| | |
| | |
| | |
使用这些基类而非原生,可获得类型安全的所有者访问权限和初始化状态集成。
UActorComponentExperience System Pattern
体验系统模式
The experience system (pioneered by Lyra) composes game modes from Game Feature plugins at runtime. Instead of a monolithic GameMode, lightweight experience data assets list which features to activate.
体验系统(由Lyra首创)在运行时通过Game Feature插件组合游戏模式。它不再使用单一的GameMode,而是通过轻量级的体验数据资产列出需要激活的功能。
Core Flow
核心流程
GameMode::InitGame()
→ Load UExperienceDefinition (from map or URL options)
→ For each feature: LoadAndActivateGameFeaturePlugin()
→ All loaded → OnExperienceLoaded broadcast
→ Components initialize, gameplay beginsA on orchestrates loading. Systems bind to its delegate rather than assuming features are available at .
UExperienceManagerComponentAGameStateBaseOnExperienceLoadedBeginPlaySee for the full pattern with code templates.
references/experience-system.mdGameMode::InitGame()
→ 加载UExperienceDefinition(来自地图或URL选项)
→ 针对每个功能:调用LoadAndActivateGameFeaturePlugin()
→ 所有功能加载完成后:广播OnExperienceLoaded
→ 组件初始化,游戏玩法开始AGameStateBaseUExperienceManagerComponentOnExperienceLoadedBeginPlay完整的模式及代码模板请查看。
references/experience-system.mdProject Policies
项目策略
UGameFeaturesProjectPoliciesIsPluginAllowed(PluginURL, OutReason)GetGameFeatureLoadingMode(bLoadClientData, bLoadServerData)InitGameFeatureManager()ShutdownGameFeatureManager()DefaultGame.iniGameFeaturesSubsystemSettingsSee for the full policies subclass template.
references/game-feature-patterns.mdUGameFeaturesProjectPoliciesIsPluginAllowed(PluginURL, OutReason)GetGameFeatureLoadingMode(bLoadClientData, bLoadServerData)InitGameFeatureManager()ShutdownGameFeatureManager()DefaultGame.iniGameFeaturesSubsystemSettings完整的策略子类模板请查看。
references/game-feature-patterns.mdCommon Mistakes
常见错误
Missing receiver registration:
cpp
// WRONG — components never injected, no error logged
void AMyCharacter::BeginPlay() { Super::BeginPlay(); }
// RIGHT
void AMyCharacter::BeginPlay()
{
Super::BeginPlay();
UGameFrameworkComponentManager::AddGameFrameworkComponentReceiver(this);
}Leaking FComponentRequestHandle:
cpp
// WRONG — handle destroyed immediately, component removed next frame
CompMgr->AddComponentRequest(ActorClass, CompClass, Flags);
// RIGHT — store for lifetime of injection
RequestHandle = CompMgr->AddComponentRequest(ActorClass, CompClass, Flags);Using BeginPlay for cross-component init:
cpp
// WRONG — modular components may not exist yet
void UMyComp::BeginPlay() { GetOwner()->FindComponentByClass<UOther>()->Configure(); }
// RIGHT — use init state system to wait for dependencies
void UMyComp::HandleChangeInitState(/*...*/, FGameplayTag DesiredState)
{
if (DesiredState == TAG_InitState_DataInitialized)
GetOwner()->FindComponentByClass<UOther>()->Configure();
}Forgetting PauseDeactivationUntilComplete delegate: If you call but never invoke the returned delegate, plugin deactivation hangs indefinitely. Always invoke it, even on error paths.
PauseDeactivationUntilCompleteWrong subsystem type for ComponentManager:
cpp
// WRONG — NOT an engine subsystem
GEngine->GetEngineSubsystem<UGameFrameworkComponentManager>();
// RIGHT — UGameInstanceSubsystem
GetGameInstance()->GetSubsystem<UGameFrameworkComponentManager>();缺少接收者注册:
cpp
// 错误——组件永远不会被注入,且无错误日志
void AMyCharacter::BeginPlay() { Super::BeginPlay(); }
// 正确
void AMyCharacter::BeginPlay()
{
Super::BeginPlay();
UGameFrameworkComponentManager::AddGameFrameworkComponentReceiver(this);
}FComponentRequestHandle泄漏:
cpp
// 错误——句柄立即销毁,组件会在下一帧被移除
CompMgr->AddComponentRequest(ActorClass, CompClass, Flags);
// 正确——存储句柄以保持注入的生命周期
RequestHandle = CompMgr->AddComponentRequest(ActorClass, CompClass, Flags);使用BeginPlay进行跨组件初始化:
cpp
// 错误——模块化组件可能尚未存在
void UMyComp::BeginPlay() { GetOwner()->FindComponentByClass<UOther>()->Configure(); }
// 正确——使用初始化状态系统等待依赖项
void UMyComp::HandleChangeInitState(/*...*/, FGameplayTag DesiredState)
{
if (DesiredState == TAG_InitState_DataInitialized)
GetOwner()->FindComponentByClass<UOther>()->Configure();
}**忘记调用PauseDeactivationUntilComplete委托:**如果你调用了但从未调用返回的委托,插件停用流程会无限挂起。即使在错误路径中,也必须调用该委托。
PauseDeactivationUntilCompleteComponentManager的子系统类型错误:
cpp
// 错误——它不是引擎子系统
GEngine->GetEngineSubsystem<UGameFrameworkComponentManager>();
// 正确——它是UGameInstanceSubsystem
GetGameInstance()->GetSubsystem<UGameFrameworkComponentManager>();Related Skills
相关技能
- — GameMode, GameState, PlayerController, PlayerState lifecycle
ue-gameplay-framework - — Component creation, attachment, tick management
ue-actor-component-architecture - — GAS integration with modular components
ue-gameplay-abilities - — Primary data assets, Asset Manager scanning
ue-data-assets-tables - — Plugin structure, Build.cs dependencies
ue-module-build-system - — Level streaming, seamless travel interactions
ue-world-level-streaming
- — GameMode、GameState、PlayerController、PlayerState生命周期
ue-gameplay-framework - — 组件创建、附着、Tick管理
ue-actor-component-architecture - — GAS与模块化组件的集成
ue-gameplay-abilities - — 主数据资产、Asset Manager扫描
ue-data-assets-tables - — 插件结构、Build.cs依赖
ue-module-build-system - — 关卡流送、无缝旅行交互
ue-world-level-streaming