关于 ue-actor-component-architecture
面向 UE 5.8 C++ 的 Actor 组件化开发技能,讲解生命周期处理、组件创建与挂接、Actor 生成、Tick 配置及接口,适用于游戏开发者。
主要功能
- 01Actor 与组件生命周期指引
- 02创建、注册和挂接组件
- 03立即与延迟生成 Actor
- 04Tick 配置与调度
- 05C++ 接口与组合模式
适用场景
- 01确定 Actor 逻辑的放置位置
- 02在运行时添加并挂接组件
- 03在构造前配置并生成 Actor
- 04将 Actor 能力拆分到组件中
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ quodsoler/ unreal-engine-skills --skill ue-actor-component-architecture安装后在 Claude Code 中输入/ue-actor-component-architecture确认已加载。
附带文件references/actor-lifecycle.mdreferences/component-types.md
详细介绍
UE Actor-Component 架构
目标引擎:UE 5.8。以下 API 已根据 5.8 头文件验证;旧版形式列在“已弃用 — 请勿使用”部分。
使用组件构建 Actor:按正确顺序调用生命周期钩子、生成 Actor(即时、延迟、池化)、创建并附加组件、处理 Tick,以及使用 C++ 接口。此处所有内容都位于 CoreUObject 之上的 Engine 模块中(GameFramework/Actor.h、Components/ActorComponent.h、Components/SceneComponent.h、Engine/World.h);游戏模块的 Build.cs 需要 "Core", "CoreUObject", "Engine"。
上下文
如果 .agents/ue-project-context.md 存在,请阅读该文件(模块名称、约定、已启用的插件、GAS/网络设置)。如果文件不存在,请继续操作。
根据请求和代码库确定所属领域。只有当两种合理解读会导致不同代码时才提问。
| 请求涉及…… | 转到 |
|---|---|
| 代码应放置的位置:构造函数、PostInitializeComponents、BeginPlay、EndPlay | Actor 生命周期 |
| 创建、附加、激活组件 | 组件系统 |
| 重写组件钩子(OnRegister、InitializeComponent、TickComponent) | 组件生命周期钩子 |
| SpawnActor、延迟生成、池化 | 生成 Actor |
| Tick 组、Tick 间隔、前置条件、Tick 与计时器 | Tick |
| 不进行类型转换即可跨 Actor 使用功能 | 接口 |
| 将臃肿的 Actor 拆分为组件、数据驱动的配置 | 组合模式 |
| 完整事件顺序、EEndPlayReason、网络及子 Actor 时序 | references/actor-lifecycle.md |
| 应使用哪个内置组件、头文件路径、成员 API | references/component-types.md |
心智模型
UObject
└── AActor placeable/spawnable; owns components GameFramework/Actor.h
└── UActorComponent logic only, no transform Components/ActorComponent.h
└── USceneComponent transform + attachment tree Components/SceneComponent.h
└── UPrimitiveComponent rendering + collision + physics Components/PrimitiveComponent.h
绝不要对 Actor 或组件使用 new/delete。Actor:使用 UWorld::SpawnActor 和 AActor::Destroy(bool bNetForce = false, bool bShouldModifyLevel = true)(Actor.h:2327)。组件:使用 CreateDefaultSubobject/NewObject 和 UActorComponent::DestroyComponent(bool bPromoteChildren = false)(ActorComponent.h:1328)。
Actor 生命周期
AActor 类注释中的顺序(Actor.h:243-278);带引用的完整表格见 references/actor-lifecycle.md。
AActor::AActor() CDO + every instance. No world. CreateDefaultSubobject, tick config, defaults
UObject::PostLoad() level-placed actors only (not spawned)
UActorComponent::OnComponentCreated() native components on spawn (not when loaded from a level)
AActor::PreRegisterAllComponents() → RegisterComponent() per component → AActor::PostRegisterAllComponents()
AActor::PostActorCreated() spawned actors only, before construction scripts
UserConstructionScript() → AActor::OnConstruction(const FTransform&)
AActor::PreInitializeComponents() gameplay only
UActorComponent::Activate() if bAutoActivate
UActorComponent::InitializeComponent() if bWantsInitializeComponent, once per session
AActor::PostInitializeComponents() components initialized; bind to own components here
AActor::BeginPlay() level is ticking; may be delayed for networked or child actors
AActor::Tick(float DeltaSeconds) if PrimaryActorTick.bCanEverTick
AActor::EndPlay(const EEndPlayReason::Type) base implementation forwards EndPlay to components
AActor::Destroyed() explicit Destroy() only; not on level streaming or game end
构造函数与 BeginPlay
构造函数会在 Class Default Object 上运行,此时 GetWorld() 为 nullptr。任何需要 World 或其他 Actor 的操作,都应放在 PostInitializeComponents(自身组件)或 BeginPlay(游戏逻辑)中。
// MyActor.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyActor.generated.h"
class UStaticMeshComponent;
class UMyHealthComponent;
UCLASS()
class MYGAME_API AMyActor : public AActor
{
GENERATED_BODY()
public:
AMyActor();
protected:
virtual void PostInitializeComponents() override;
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
UFUNCTION()
void HandleDeath();
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Components")
TObjectPtr<UStaticMeshComponent> MeshComp;
UPROPERTY(VisibleAnywhere, Category="Components")
TObjectPtr<UMyHealthComponent> HealthComp;
};
// MyActor.cpp
#include "MyActor.h"
#include "Components/StaticMeshComponent.h"
#include "TimerManager.h"
#include "MyHealthComponent.h"
AMyActor::AMyActor()
{
PrimaryActorTick.bCanEverTick = true;
PrimaryActorTick.bStartWithTickEnabled = false;
MeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
SetRootComponent(MeshComp); // SetupAttachment(MeshComp) parents a scene component here; no world needed
HealthComp = CreateDefaultSubobject<UMyHealthComponent>(TEXT("Health")); // logic-only: no attachment
}
void AMyActor::PostInitializeComponents()
{
Super::PostInitializeComponents();
HealthComp->OnDeath.AddDynamic(this, &AMyActor::HandleDeath); // own components are initialized
}
void AMyActor::BeginPlay()
{
Super::BeginPlay();
SetActorTickEnabled(true); // gameplay starts here
}
void AMyActor::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
GetWorldTimerManager().ClearAllTimersForObject(this);
Super::EndPlay(EndPlayReason); // base forwards EndPlay to components
}
void AMyActor::HandleDeath() { Destroy(); }
EEndPlayReason::Type(Engine/EngineTypes.h:3670-3685):Destroyed、LevelTransition、EndPlayInEditor、RemovedFromWorld、Quit。无论出于何种原因结束游戏,都要清除计时器并解除委托绑定,然后调用 Super::EndPlay(EndPlayReason)。
网络说明
在客户端上,BeginPlay“可能会因网络 Actor 或子 Actor 而延迟”(Actor.h:275)。属性到达钩子为 PreNetReceive()/PostNetReceive()(Actor.h:2943-2946)和 PostNetInit();该钩子“始终在生成 Actor 并读取复制属性后立即调用”(Actor.h:2958)。复制规则、OnRep_ 函数和 RPC 由 ue-networking-replication 负责。
组件系统
| 类 | 变换 | 渲染/碰撞 | 用途 |
|---|---|---|---|
UActorComponent | 否 | 否 | 纯逻辑和数据:生命值、物品栏、冷却 |
USceneComponent | 是 | 否 | 锚点、枢轴、分组、附加点 |
UPrimitiveComponent | 是 | 是 | 网格体、形状,以及任何可见或可碰撞的内容 |
内置子类、头文件路径和成员 API: references/component-types.md。
编写组件
// MyHealthComponent.h
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "MyHealthComponent.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FMyOnDeathSignature);
UCLASS(ClassGroup=(MyGame), meta=(BlueprintSpawnableComponent))
class MYGAME_API UMyHealthComponent : public UActorComponent
{
GENERATED_BODY()
public:
UMyHealthComponent();
UPROPERTY(BlueprintAssignable, Category="Health")
FMyOnDeathSignature OnDeath;
UFUNCTION(BlueprintCallable, Category="Health")
void ApplyDamage(float Amount);
protected:
virtual void InitializeComponent() override;
UPROPERTY(EditAnywhere, Category="Health")
float MaxHealth = 100.f;
UPROPERTY(VisibleInstanceOnly, Transient, Category="Health")
float CurrentHealth = 0.f;
};
// MyHealthComponent.cpp
#include "MyHealthComponent.h"
UMyHealthComponent::UMyHealthComponent()
{
PrimaryComponentTick.bCanEverTick = false; // event-driven: no per-frame work
bWantsInitializeComponent = true; // opt in to InitializeComponent()
}
void UMyHealthComponent::InitializeComponent()
{
Super::InitializeComponent();
CurrentHealth = MaxHealth; // once per gameplay session, before BeginPlay
}
void UMyHealthComponent::ApplyDamage(float Amount)
{
CurrentHealth = FMath::Max(0.f, CurrentHealth - Amount);
if (CurrentHealth <= 0.f) { OnDeath.Broadcast(); }
}
组件复制:bReplicates 在 UActorComponent 中是私有成员(ActorComponent.h:267);在构造函数中调用 SetIsReplicatedByDefault(true),或稍后调用 SetIsReplicated(true),并且所属 Actor 必须启用复制。详情见 ue-networking-replication。
在运行时创建组件
// In AMyActor (declared: void AddRuntimeLight();)
#include "Components/PointLightComponent.h"
void AMyActor::AddRuntimeLight()
{
// NewObject creates the UObject only; RegisterComponent creates render/physics state and enables tick.
UPointLightComponent* Light = NewObject<UPointLightComponent>(this, TEXT("RuntimeLight"));
Light->SetupAttachment(GetRootComponent()); // allowed before RegisterComponent
Light->RegisterComponent();
AddInstanceComponent(Light); // adds to InstanceComponents: visible in Details, serialized per instance
Light->SetIntensity(5000.f);
}
UnregisterComponent() 会移除组件在世界中的存在,但保留对象(可撤销);DestroyComponent() 会取消注册并将其标记为待垃圾回收。Outer 为 Actor 的组件会添加到该 Actor 的 OwnedComponents 中(ActorComponent.cpp:600 中的 PostInitProperties,注册时见 :951),AActor::AddReferencedObjects 会将其报告给垃圾回收器(Actor.cpp:574),因此,无论是否有 UPROPERTY,它都会一直存活,直到调用 DestroyComponent() 或 Actor 被销毁。仍应将自己的指针保存在 UPROPERTY(TObjectPtr)中,以便跟踪并安全置空;调用 DestroyComponent() 后,裸指针会悬空。
附加
| 调用 | 使用位置 | 头文件 |
|---|---|---|
SetupAttachment(USceneComponent* InParent, FName InSocketName = NAME_None) | 构造函数中,或用于任何尚未注册的组件 | SceneComponent.h:734 |
AttachToComponent(USceneComponent* InParent, const FAttachmentTransformRules& AttachmentRules, FName InSocketName = NAME_None) | 运行时;可用于已注册或未注册的组件,但建议在注册前使用 SetupAttachment。返回 bool(false = 被拒绝,父级不变) | SceneComponent.h:752 |
DetachFromComponent(const FDetachmentTransformRules& DetachmentRules) | 运行时 | SceneComponent.h:786 |
AActor::AttachToComponent(...)、AttachToActor(AActor* ParentActor, const FAttachmentTransformRules&, FName SocketName = NAME_None)、DetachFromActor(const FDetachmentTransformRules&) | 通过根组件附加整个 Actor;两个附加调用均返回 bool | Actor.h:2015, 2029, 2062 |
K2_AttachToComponent(...)、K2_AttachToActor(...) | 仅限蓝图节点;C++ 调用不带 K2_ 的形式 | Actor.h:2006, 2042 |
FAttachmentTransformRules 预设(Engine/EngineTypes.h:78-81):KeepRelativeTransform、KeepWorldTransform、SnapToTargetNotIncludingScale、SnapToTargetIncludingScale;逐轴构造函数 FAttachmentTransformRules(EAttachmentRule InLocationRule, EAttachmentRule InRotationRule, EAttachmentRule InScaleRule, bool bInWeldSimulatedBodies)。FDetachmentTransformRules 预设(:125-126):KeepRelativeTransform、KeepWorldTransform。
void AMyCharacter::EquipWeapon(UStaticMeshComponent* WeaponMesh)
{
WeaponMesh->AttachToComponent(GetMesh(), FAttachmentTransformRules::SnapToTargetNotIncludingScale, TEXT("WeaponSocket"));
}
激活(ActorComponent.h)
uint8 bAutoActivate:1 是公有成员(:317):在构造函数中设置。运行时调用:virtual void Activate(bool bReset = false)(:580)、virtual void Deactivate()(:586)、virtual void SetActive(bool bNewActive, bool bReset = false)(:594)、virtual void ToggleActive()(:600)、bool IsActive() const(:607;bIsActive 是私有成员)。通过重写 virtual bool ShouldActivate() const(:807)控制激活条件。委托:OnComponentActivated / OnComponentDeactivated(:559, :563)。
组件生命周期钩子
在 UActorComponent 子类中重写这些钩子;签名直接摘自 Components/ActorComponent.h。
| 钩子 | 行号 | 触发时机 |
|---|---|---|
virtual void OnComponentCreated() | :1331 | Actor 生成时触发原生组件;从关卡加载的组件不会触发 |
virtual void OnRegister() / virtual void OnUnregister() | :830, :835 | 在世界注册前后触发;渲染/物理状态在 OnRegister 后创建 |
virtual void InitializeComponent() / virtual void UninitializeComponent() | :919, :955 | 仅当 bWantsInitializeComponent(:340)为 true 时触发;每个会话仅一次 |
virtual void BeginPlay() / virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) | :936, :949 | 开始/停止游戏时触发 |
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) | :976 | 需要 PrimaryComponentTick.bCanEverTick 为 true 且已注册 |
virtual void OnComponentDestroyed(bool bDestroyingHierarchy) | :1338 | 由 DestroyComponent 触发 |
HasBeenCreated()、HasBeenInitialized()、HasBegunPlay()、IsRegistered()、IsBeingDestroyed() | :505-520, :1316 | 状态查询;位字段为私有 |
GetOwner()(:538)和 GetOwner<T>()(:542)返回所属 Actor;注册后 GetWorld() 才有效。
生成
FActorSpawnParameters(Engine/World.h:420-519):Name、Template、Owner、Instigator、OverrideLevel、SpawnCollisionHandlingOverride、TransformScaleMethod、bNoFail、bDeferConstruction、bAllowDuringConstructionScript、NameMode、ObjectFlags、CustomPreSpawnInitialization。碰撞处理值(Engine/EngineTypes.h:4411-4423):Undefined、AlwaysSpawn、AdjustIfPossibleButAlwaysSpawn、AdjustIfPossibleButDontSpawnIfColliding、DontSpawnIfColliding。
// AMyEnemySpawner member: UPROPERTY(EditDefaultsOnly) TSubclassOf<AMyEnemy> EnemyClass;
AMyEnemy* AMyEnemySpawner::SpawnEnemy(const FVector& Location, const FRotator& Rotation)
{
FActorSpawnParameters Params;
Params.Owner = this;
Params.Instigator = GetInstigator();
Params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;
return GetWorld()->SpawnActor<AMyEnemy>(EnemyClass, Location, Rotation, Params);
}
延迟生成:在构造和 BeginPlay 前进行配置
SpawnActorDeferred<T>(UClass* Class, FTransform const& Transform, AActor* Owner = nullptr, APawn* Instigator = nullptr, ESpawnActorCollisionHandlingMethod CollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::Undefined, ESpawnActorScaleMethod TransformScaleMethod = ESpawnActorScaleMethod::MultiplyWithRoot)(World.h:3851-3870)会将 bDeferConstruction 设为 true。之后使用 FinishSpawning(const FTransform& Transform, bool bIsDefaultTransform = false, const FComponentInstanceDataCache* InstanceDataCache = nullptr, ESpawnActorScaleMethod TransformScaleMethod = ESpawnActorScaleMethod::OverrideRootScale)(Actor.h:3117)完成生成。在此之前,Actor“处于格式不正确的状态”(Actor.h:632)。
// AMyEnemy declares: void SetEnemyData(UMyEnemyData* Data);
AMyEnemy* AMyEnemySpawner::SpawnEnemyFromData(const FTransform& SpawnTransform, UMyEnemyData* Data)
{
AMyEnemy* Enemy = GetWorld()->SpawnActorDeferred<AMyEnemy>(EnemyClass, SpawnTransform, this, GetInstigator(),
ESpawnActorCollisionHandlingMethod::AlwaysSpawn);
if (!Enemy) { return nullptr; }
Enemy->SetEnemyData(Data); // runs before OnConstruction and BeginPlay
Enemy->FinishSpawning(SpawnTransform, false, nullptr, ESpawnActorScaleMethod::MultiplyWithRoot);
return Enemy;
}
这两个默认值不同:SpawnActorDeferred 使用 MultiplyWithRoot,而 FinishSpawning 使用 OverrideRootScale。当根组件的默认缩放不为单位缩放时,请显式传入缩放方法。
对象池
频繁对弹丸或弹壳执行 SpawnActor/Destroy 会增加 GC 开销。改为停放 Actor:隐藏、禁用碰撞和 Tick;复用时反向操作。AActor 没有 IsActive();使用 IsHidden()(Actor.h:4523)作为停放标志。
完整的对象池 Actor 类(使用 GC 安全存储实现 Acquire/Release):references/component-types.md。
Tick
FTickFunction 字段(Engine/EngineBaseTypes.h):bCanEverTick(:213)、bStartWithTickEnabled(:217)、bTickEvenWhenPaused(:209)、bAllowTickOnDedicatedServer(:221)、TickGroup(:196)、EndTickGroup(:204)、TickInterval(:258)。Actor 使用 PrimaryActorTick(Actor.h:318),组件使用 PrimaryComponentTick(ActorComponent.h:177)。
AMyEnemy::AMyEnemy()
{
PrimaryActorTick.bCanEverTick = true;
PrimaryActorTick.bStartWithTickEnabled = false; // later: SetActorTickEnabled(true)
PrimaryActorTick.TickInterval = 0.1f; // later: SetActorTickInterval(0.1f)
PrimaryActorTick.TickGroup = TG_PostPhysics;
}
ETickingGroup(EngineBaseTypes.h:83-109) | 用途 |
|---|---|
TG_PrePhysics | 默认。输入、移动请求、AI 决策 |
TG_DuringPhysics | 不读取本帧物理结果的工作 |
TG_PostPhysics | 摄像机、IK,以及任何读取最终物理变换的内容 |
TG_PostUpdateWork | 最后的游戏逻辑组 |
TG_StartPhysics、TG_EndPhysics、TG_LastDemotable、TG_NewlySpawned | 引擎内部使用;切勿赋值 |
特定对象之间的排序:AddTickPrerequisiteActor(AActor* PrerequisiteActor) 和 AddTickPrerequisiteComponent(UActorComponent* PrerequisiteComponent) 同时存在于 AActor(Actor.h:2093, 2097)和 UActorComponent(ActorComponent.h:1355, 1359)中。SetTickableWhenPaused(bool bTickableWhenPaused)(Actor.h:2113、ActorComponent.h:618)。使用 SetTickGroup(ETickingGroup NewTickGroup)(Actor.h:3566、ActorComponent.h:1351)在运行时更改组。定步长物理回调:bAsyncPhysicsTickEnabled(Actor.h:699)以及 virtual void AsyncPhysicsTickActor(float DeltaTime, float SimTime)(Actor.h:2930);参见 ue-physics-collision。
何时不应使用 Tick
| 需求 | 替代方案 |
|---|---|
| 延迟或重复执行工作 | GetWorldTimerManager().SetTimer(FTimerHandle& InOutHandle, UserClass* InObj, TMethodPtr InTimerMethod, float InRate, bool InbLoop = false, float InFirstDelay = -1.f)(TimerManager.h:167) |
| 响应状态变化 | 在组件上使用动态多播委托,并在 PostInitializeComponents 中绑定 |
| 碰撞 | OnComponentBeginOverlap、OnComponentHit(PrimitiveComponent.h:1457-1475)、OnActorBeginOverlap(Actor.h:1368);参见 ue-physics-collision |
| 低开销的逐帧更新 | 保留 Tick,但使用 TickInterval 降低频率,并在空闲时通过 SetActorTickEnabled(false) 禁用 |
接口
使用 UINTERFACE 表示无关 Actor 共享的能力(“可交互”);如果行为拥有状态或需要 Tick,则使用组件。面向 Blueprint 的公开规则(BlueprintImplementableEvent、meta= 说明符、潜伏操作)由 ue-blueprint-cpp-interop 负责。
// MyInteractable.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "MyInteractable.generated.h"
UINTERFACE(MinimalAPI, Blueprintable)
class UMyInteractable : public UInterface
{
GENERATED_BODY()
};
class MYGAME_API IMyInteractable
{
GENERATED_BODY()
public:
// C++ default + Blueprint override; UHT also generates Execute_OnInteract(UObject*, AActor*) for safe calls
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Interaction")
void OnInteract(AActor* InstigatorActor);
};
实现类同时继承这两个类,例如 class MYGAME_API AMyChest : public AActor, public IMyInteractable,并重载 virtual void OnInteract_Implementation(AActor* InstigatorActor) override;。调用方绝不直接调用 OnInteract:
// Caller (AMyCharacter, declared: void TryInteract(AActor* Target);)
void AMyCharacter::TryInteract(AActor* Target)
{
if (Target && Target->Implements<UMyInteractable>()) // U-class for the reflection check
{
IMyInteractable::Execute_OnInteract(Target, this); // works for C++ and Blueprint implementers
}
// Components implementing the interface: FindComponentByInterface<IMyInteractable>() takes the I-class (Actor.h:3852)
}
组合模式
优先使用扁平的 Actor 加组件,而不是深层继承层次(AMyCharacter + UMyHealthComponent + UMyInventoryComponent);对于不同变体,优先使用一个类和多个数据资产,而不是为每种变体创建一个子类。组件通过所有者(GetOwner()->FindComponentByClass<UMyHealthComponent>())或委托通信,绝不缓存指向同级组件的原始指针。数据驱动的配置可通过数据资产上的 TArray<TSubclassOf<UActorComponent>> 在运行时添加组件:
void AMyEnemy::ApplyLoadout(const UMyEnemyData* Data)
{
for (const TSubclassOf<UActorComponent>& CompClass : Data->ExtraComponents)
{
UActorComponent* Comp = NewObject<UActorComponent>(this, CompClass);
if (!Comp) { continue; }
Comp->RegisterComponent(); // starts ticking and registers with the world
AddInstanceComponent(Comp); // shows up in the details panel and is saved with the actor
}
}
对于由插件或 Game Features 注入 Actor 的组件,使用 ModularGameplay 中的 UGameFrameworkComponentManager::AddReceiver(AActor* Receiver, bool bAddOnlyInGameWorlds = true)(在 5.8 中为 Beta);参见 ue-game-features。
已弃用 — 请勿使用
| 请勿使用 | 在 5.8 中使用 | 来源 |
|---|---|---|
FindComponentByInterface<UMyInterface>() | FindComponentByInterface<IMyInterface>() | GameFramework/Actor.h:3844 中的 UE_DEPRECATED(5.5) |
PreDuplicate(FObjectDuplicationParameters&) | PreDuplicateFromRoot(FObjectDuplicationParameters& DupParams) | GameFramework/Actor.h:2413 中的 UE_DEPRECATED(5.6) |
Actor->LastRenderTime | GetLastRenderTime() / SetLastRenderTime(float) | GameFramework/Actor.h:138 中的 UE_DEPRECATED(5.6) |
NetUpdateFrequency = 30.f、MinNetUpdateFrequency = ...、NetCullDistanceSquared = ... | SetNetUpdateFrequency()、SetMinNetUpdateFrequency()、SetNetCullDistanceSquared() | GameFramework/Actor.h:898-909 中的 UE_DEPRECATED(5.5) |
重写 BeginReplication() / EndReplication() | OnReplicationStartedForIris / OnStopReplicationForIris / FillReplicationParams;请参阅 ue-networking-replication | GameFramework/Actor.h:3493-3506 中的 UE_DEPRECATED(5.7) |
APawn::GetMovementBase() | GetMovementBaseObject() / GetMovementBaseInterfaceData();请参阅 ue-character-movement | GameFramework/Pawn.h:59 中的 UE_DEPRECATED(5.8) |
AttachTo(...)、K2_AttachTo(...)、AttachRootComponentTo(...) | AttachToComponent(Parent, FAttachmentTransformRules, SocketName) | GameFramework/Actor.h:1991、Components/SceneComponent.h:740 中的 UE_DEPRECATED(4.17) |
AttachRootComponentToActor(...) | AttachToActor(ParentActor, FAttachmentTransformRules, SocketName) | GameFramework/Actor.h:2018 中的 UE_DEPRECATED(4.17) |
DetachFromParent(bool)、DetachRootComponentFromParent(bool) | DetachFromComponent(FDetachmentTransformRules)、DetachFromActor(FDetachmentTransformRules) | Components/SceneComponent.h:768 中的 UE_DEPRECATED(4.12);GameFramework/Actor.h:2045 中的 UE_DEPRECATED(4.17) |
Comp->bReplicates = true | SetIsReplicatedByDefault(true)(构造函数中)或 SetIsReplicated(true) | 私有成员,Components/ActorComponent.h:264-267 |
Comp->bCreatedByConstructionScript | Comp->CreationMethod == EComponentCreationMethod::UserConstructionScript 或 IsCreatedByConstructionScript() | Components/ActorComponent.h:306-310 中注明“已弃用,由 CreationMethod 取代” |
SceneComp->RelativeLocation = ...、SceneComp->bVisible = ...、SceneComp->AttachParent | SetRelativeLocation()、SetVisibility()、GetAttachParent() | 私有成员,Components/SceneComponent.h:109-183 |
Actor->bHidden | IsHidden() / SetActorHiddenInGame(bool) | 私有成员,GameFramework/Actor.h:365 |
在 C++ 中使用 GetComponentsByClass(...)(C++ 名称为 K2_GetComponentsByClass) | GetComponents<T>(OutArray) 或 TInlineComponentArray<T*> | GameFramework/Actor.h:3801-3807 中注明“仅供蓝图使用” |
原始组件上的 LightmapType | GetLightmapType() / SetLightmapType() | Components/PrimitiveComponent.h:359 中的 UE_DEPRECATED(5.5) |
常见错误
**在构造函数中访问 World:**在 CDO 上,GetWorld() 为 nullptr;SpawnActor、定时器和查找操作应放在 BeginPlay 中,组件绑定应放在 PostInitializeComponents 中。
**跳过 Super:::**每个生命周期重写函数都要调用对应的 Super::(BeginPlay 中首先调用;EndPlay(EndPlayReason) 中最后调用)。AActor::EndPlay 会将 EndPlay 转发给组件;RouteEndPlay 可确保在遗漏 Super::EndPlay 时进行处理(Actor.cpp:3230)。
**将池化或缓存的 Actor 放在 UPROPERTY 之外:**普通的 TArray<AMyProjectile*> 成员对 GC 不可见;应声明为 UPROPERTY() TArray<TObjectPtr<AMyProjectile>>。在非 UObject 代码中使用 TWeakObjectPtr<AActor> 保存非拥有型引用,并检查 IsValid()。
**在构造函数中调用 AttachToComponent:**头文件允许对未注册的组件调用此方法,但这里预期使用的是 SetupAttachment(SceneComponent.h:745-746);从 BeginPlay 开始使用 AttachToComponent,并检查其 bool 返回值。
**调用 NewObject 后不调用 RegisterComponent:**组件不会获得渲染或物理状态,也不会进行 Tick。此外,如果组件应显示在 Details 面板中并在序列化后保留,还要调用 AddInstanceComponent。
**延迟生成后不调用 FinishSpawning:**Actor 会停留在格式错误的状态(Actor.h:632);始终将 SpawnActorDeferred 与 FinishSpawning 配对使用。
直接调用接口方法:Target->OnInteract(...) 会绕过 Blueprint 实现者。先用 Implements<UMyInteractable>() 检查,再通过 IMyInteractable::Execute_OnInteract(Target, ...) 调用。
**在 Tick 中轮询:**每帧执行 if (HealthComp->IsDead()),应改为绑定一次 OnDeath;当不需要逐帧处理时,使用 SetActorTickEnabled(false) 禁用 Tick。
假设子 Actor 在 PostInitializeComponents 中已存在:UChildActorComponent 子项可能较晚才开始播放(Actor.h:275);应在 BeginPlay 中或之后读取 GetChildActor()。
写入私有组件标志:bReplicates、bIsActive、bHasBegunPlay、RelativeLocation 和 bVisible 都是私有的;请使用上方表格中列出的 setter 和查询方法。
相关技能
ue-cpp-foundations— UCLASS/UPROPERTY/UFUNCTION 限定符、TObjectPtr 与 TWeakObjectPtr、子系统、GC 规则ue-gameplay-framework— GameMode、GameState、PlayerController、Pawn、Character、不使用 GAS 的伤害处理ue-physics-collision— 碰撞通道和配置文件、重叠与命中事件、扫掠、异步物理帧ue-networking-replication— SetReplicates、属性复制、OnRep、RPC、子对象复制、Irisue-gameplay-cameras— USpringArmComponent、UCameraComponent、PlayerCameraManager、Gameplay Cameras 插件ue-blueprint-cpp-interop— 可由 Blueprint 实现的接口、BlueprintNativeEvent 规则、延迟操作、meta 限定符ue-character-movement— CharacterMovementComponent、移动基类 API、CMC 与 Moverue-animation-system— USkeletalMeshComponent 动画、AnimInstance、蒙太奇ue-audio-system— UAudioComponent 播放、衰减、MetaSoundsue-niagara-effects— UNiagaraComponent、系统生成、用户参数ue-game-features— ModularGameplay 组件、UGameFrameworkComponentManager、Game Feature 操作ue-gameplay-abilities— 在 Actor 上放置 UAbilitySystemComponentue-state-trees— Actor 和 AI 控制器上的 UStateTreeComponentue-ai-navigation— 感知和导航组件ue-procedural-generation— UProceduralMeshComponent、UDynamicMeshComponent、大规模实例化ue-editor-tools— 细节面板自定义、编辑器实用工具控件、UToolMenus 和编辑器子系统ue-input-system— Enhanced Input 操作、映射上下文、触发器、修饰器和用户设置ue-mass-entity— Mass 处理器、片段、查询和实体特征ue-materials-rendering— 材质实例、参数集合、渲染目标和后期处理ue-sequencer-cinematics— Level Sequence、播放、电影摄影机和 Movie Render Graphue-world-level-streaming— World Partition、关卡流送、数据层和场景切换