mcpField
U
ue-actor-component-architecture

ue-actor-component-architecture

github.com/quodsoler开发4191.2k 次安装4 周前更新
代码仓库

关于 ue-actor-component-architecture

面向 UE 5.8 C++ 的 Actor 组件化开发技能,讲解生命周期处理、组件创建与挂接、Actor 生成、Tick 配置及接口,适用于游戏开发者。

主要功能

  1. 01Actor 与组件生命周期指引
  2. 02创建、注册和挂接组件
  3. 03立即与延迟生成 Actor
  4. 04Tick 配置与调度
  5. 05C++ 接口与组合模式

适用场景

  1. 01确定 Actor 逻辑的放置位置
  2. 02在运行时添加并挂接组件
  3. 03在构造前配置并生成 Actor
  4. 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、EndPlayActor 生命周期
创建、附加、激活组件组件系统
重写组件钩子(OnRegister、InitializeComponent、TickComponent)组件生命周期钩子
SpawnActor、延迟生成、池化生成 Actor
Tick 组、Tick 间隔、前置条件、Tick 与计时器Tick
不进行类型转换即可跨 Actor 使用功能接口
将臃肿的 Actor 拆分为组件、数据驱动的配置组合模式
完整事件顺序、EEndPlayReason、网络及子 Actor 时序references/actor-lifecycle.md
应使用哪个内置组件、头文件路径、成员 APIreferences/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;两个附加调用均返回 boolActor.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():1331Actor 生成时触发原生组件;从关卡加载的组件不会触发
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->LastRenderTimeGetLastRenderTime() / 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-replicationGameFramework/Actor.h:3493-3506 中的 UE_DEPRECATED(5.7)
APawn::GetMovementBase()GetMovementBaseObject() / GetMovementBaseInterfaceData();请参阅 ue-character-movementGameFramework/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 = trueSetIsReplicatedByDefault(true)(构造函数中)或 SetIsReplicated(true)私有成员,Components/ActorComponent.h:264-267
Comp->bCreatedByConstructionScriptComp->CreationMethod == EComponentCreationMethod::UserConstructionScript 或 IsCreatedByConstructionScript()Components/ActorComponent.h:306-310 中注明“已弃用,由 CreationMethod 取代”
SceneComp->RelativeLocation = ...、SceneComp->bVisible = ...、SceneComp->AttachParentSetRelativeLocation()、SetVisibility()、GetAttachParent()私有成员,Components/SceneComponent.h:109-183
Actor->bHiddenIsHidden() / SetActorHiddenInGame(bool)私有成员,GameFramework/Actor.h:365
在 C++ 中使用 GetComponentsByClass(...)(C++ 名称为 K2_GetComponentsByClass)GetComponents<T>(OutArray) 或 TInlineComponentArray<T*>GameFramework/Actor.h:3801-3807 中注明“仅供蓝图使用”
原始组件上的 LightmapTypeGetLightmapType() / 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、子对象复制、Iris
  • ue-gameplay-cameras — USpringArmComponent、UCameraComponent、PlayerCameraManager、Gameplay Cameras 插件
  • ue-blueprint-cpp-interop — 可由 Blueprint 实现的接口、BlueprintNativeEvent 规则、延迟操作、meta 限定符
  • ue-character-movement — CharacterMovementComponent、移动基类 API、CMC 与 Mover
  • ue-animation-system — USkeletalMeshComponent 动画、AnimInstance、蒙太奇
  • ue-audio-system — UAudioComponent 播放、衰减、MetaSounds
  • ue-niagara-effects — UNiagaraComponent、系统生成、用户参数
  • ue-game-features — ModularGameplay 组件、UGameFrameworkComponentManager、Game Feature 操作
  • ue-gameplay-abilities — 在 Actor 上放置 UAbilitySystemComponent
  • ue-state-trees — Actor 和 AI 控制器上的 UStateTreeComponent
  • ue-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 Graph
  • ue-world-level-streaming — World Partition、关卡流送、数据层和场景切换

评论

支持 Markdown