All skills
quodsoler avatar

/ue-actor-component-architecture

@f3742d7
by Quod Solerquodsoler/unreal-engine-skills352 stars
59

Use when writing or debugging AActor and UActorComponent C++: constructor vs BeginPlay, PostInitializeComponents, EndPlay cleanup, SpawnActor/SpawnActorDeferred/FinishSpawning, CreateDefaultSubobject, NewObject + RegisterComponent, SetupAttachment/AttachToComponent, tick groups, UChildActorComponent, UINTERFACE, actor pooling. Also use when the user mentions 'BeginPlay', 'Tick', 'SpawnActor', 'CreateDefaultSubobject', 'attach a component', 'root component', 'lifecycle', 'PrimaryActorTick', 'FAttachmentTransformRules'. For collision and overlaps, see ue-physics-collision; for GameMode/Pawn/Controller, see ue-gameplay-framework; for replicated actors, see ue-networking-replication.

Use this Skill: https://skilld.dev/gh/quodsoler/unreal-engine-skills/ue-actor-component-architecture

This session only. Nothing lands on disk.

SKILL.md

โ‰ˆ180 tokens always: the name and description. โ‰ˆ7.3k when used: this file. โ‰ˆ12k more on demand in 2 files.

UE Actor-Component Architecture

Target engine: UE 5.8. APIs below are verified against the 5.8 headers; older forms are listed under "Deprecated โ€” do not use".

Build actors out of components: lifecycle hooks in the right order, spawning (immediate, deferred, pooled), component creation and attachment, ticking, and C++ interfaces. Everything here is in the Engine module (GameFramework/Actor.h, Components/ActorComponent.h, Components/SceneComponent.h, Engine/World.h) on top of CoreUObject; a game module's Build.cs needs "Core", "CoreUObject", "Engine".

Context

Read .agents/ue-project-context.md if it exists (module names, conventions, enabled plugins, GAS/networking setup). Do not stop if it is missing.

Identify the area from the request and the codebase. Ask only when two plausible readings would produce different code.

Request is aboutโ€ฆ Go to
Where code belongs: constructor, PostInitializeComponents, BeginPlay, EndPlay Actor Lifecycle
Creating, attaching, activating components Component System
Overriding component hooks (OnRegister, InitializeComponent, TickComponent) Component Lifecycle Hooks
SpawnActor, deferred spawn, pooling Spawning
Tick groups, tick interval, prerequisites, tick vs timer Ticking
Cross-actor capability without casting Interfaces
Splitting a fat actor into components, data-driven loadouts Composition Patterns
Full event order, EEndPlayReason, network and child-actor timing references/actor-lifecycle.md
Which built-in component to use, header paths, member APIs references/component-types.md

Mental Model

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

Never new/delete an actor or component. Actors: UWorld::SpawnActor and AActor::Destroy(bool bNetForce = false, bool bShouldModifyLevel = true) (Actor.h:2327). Components: CreateDefaultSubobject/NewObject and UActorComponent::DestroyComponent(bool bPromoteChildren = false) (ActorComponent.h:1328).

Actor Lifecycle

Order from the AActor class comment (Actor.h:243-278); full table with citations in 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

Constructor vs BeginPlay

The constructor runs on the Class Default Object, where GetWorld() is nullptr. Anything that needs the world or other actors goes in PostInitializeComponents (own components) or BeginPlay (gameplay).

// 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. Clear timers and unbind delegates for every reason, then call Super::EndPlay(EndPlayReason).

Network note

On clients, BeginPlay "can be delayed for networked or child actors" (Actor.h:275). Property arrival hooks are PreNetReceive()/PostNetReceive() (Actor.h:2943-2946) and PostNetInit(), "always called immediately after spawning and reading in replicated properties" (Actor.h:2958). Replication rules, OnRep_ functions and RPCs are owned by ue-networking-replication.

Component System

Class Transform Render/Collision Use for
UActorComponent No No Pure logic and data: health, inventory, cooldowns
USceneComponent Yes No Anchors, pivots, grouping, attach points
UPrimitiveComponent Yes Yes Meshes, shapes, anything visible or collidable

Built-in subclasses, header paths and member APIs: references/component-types.md.

Writing a component

// 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(); }
}

Component replication: bReplicates is private on UActorComponent (ActorComponent.h:267); call SetIsReplicatedByDefault(true) in the constructor or SetIsReplicated(true) later, and the owning actor must replicate. Details in ue-networking-replication.

Creating components at runtime

// 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() removes world presence but keeps the object (reversible); DestroyComponent() unregisters and marks it for GC. A component whose Outer is an actor is added to that actor's OwnedComponents (ActorComponent.cpp:600 in PostInitProperties, :951 on register), which AActor::AddReferencedObjects reports to GC (Actor.cpp:574), so it stays alive until DestroyComponent() or the actor dies, with or without a UPROPERTY. Still hold your own pointer in a UPROPERTY (TObjectPtr) so it is tracked and nulled safely; a raw pointer dangles after DestroyComponent().

Attachment

Call Where Header
SetupAttachment(USceneComponent* InParent, FName InSocketName = NAME_None) Constructor, or any unregistered component SceneComponent.h:734
AttachToComponent(USceneComponent* InParent, const FAttachmentTransformRules& AttachmentRules, FName InSocketName = NAME_None) Runtime; valid registered or not, but prefer SetupAttachment before registration. Returns bool (false = rejected, parent unchanged) SceneComponent.h:752
DetachFromComponent(const FDetachmentTransformRules& DetachmentRules) Runtime SceneComponent.h:786
AActor::AttachToComponent(...), AttachToActor(AActor* ParentActor, const FAttachmentTransformRules&, FName SocketName = NAME_None), DetachFromActor(const FDetachmentTransformRules&) Attach the whole actor via its root; both attach calls return bool Actor.h:2015, 2029, 2062
K2_AttachToComponent(...), K2_AttachToActor(...) Blueprint nodes only; C++ calls the non-K2_ forms Actor.h:2006, 2042

FAttachmentTransformRules presets (Engine/EngineTypes.h:78-81): KeepRelativeTransform, KeepWorldTransform, SnapToTargetNotIncludingScale, SnapToTargetIncludingScale; per-axis constructor FAttachmentTransformRules(EAttachmentRule InLocationRule, EAttachmentRule InRotationRule, EAttachmentRule InScaleRule, bool bInWeldSimulatedBodies). FDetachmentTransformRules presets (:125-126): KeepRelativeTransform, KeepWorldTransform.

void AMyCharacter::EquipWeapon(UStaticMeshComponent* WeaponMesh)
{
    WeaponMesh->AttachToComponent(GetMesh(), FAttachmentTransformRules::SnapToTargetNotIncludingScale, TEXT("WeaponSocket"));
}

Activation (ActorComponent.h)

uint8 bAutoActivate:1 is public (:317): set it in the constructor. Runtime: 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 is private). Gate activation by overriding virtual bool ShouldActivate() const (:807). Delegates OnComponentActivated / OnComponentDeactivated (:559, :563).

Component Lifecycle Hooks

Override these on UActorComponent subclasses; signatures are verbatim from Components/ActorComponent.h.

Hook Line Fires
virtual void OnComponentCreated() :1331 Native components when the actor is spawned; not for components loaded from a level
virtual void OnRegister() / virtual void OnUnregister() :830, :835 Around world registration; render/physics state is created after OnRegister
virtual void InitializeComponent() / virtual void UninitializeComponent() :919, :955 Only when bWantsInitializeComponent (:340) is true; once per session
virtual void BeginPlay() / virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) :936, :949 Play start/stop
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) :976 Requires PrimaryComponentTick.bCanEverTick and registration
virtual void OnComponentDestroyed(bool bDestroyingHierarchy) :1338 From DestroyComponent
HasBeenCreated(), HasBeenInitialized(), HasBegunPlay(), IsRegistered(), IsBeingDestroyed() :505-520, :1316 State queries; the bit fields are private

GetOwner() (:538) and GetOwner<T>() (:542) return the owning actor; GetWorld() is valid once registered.

Spawning

FActorSpawnParameters (Engine/World.h:420-519): Name, Template, Owner, Instigator, OverrideLevel, SpawnCollisionHandlingOverride, TransformScaleMethod, bNoFail, bDeferConstruction, bAllowDuringConstructionScript, NameMode, ObjectFlags, CustomPreSpawnInitialization. Collision handling values (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);
}

Deferred spawn: configure before construction and 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) sets bDeferConstruction = true. Finish with FinishSpawning(const FTransform& Transform, bool bIsDefaultTransform = false, const FComponentInstanceDataCache* InstanceDataCache = nullptr, ESpawnActorScaleMethod TransformScaleMethod = ESpawnActorScaleMethod::OverrideRootScale) (Actor.h:3117). Until then the actor "is in a malformed state" (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;
}

The two defaults differ: SpawnActorDeferred uses MultiplyWithRoot, FinishSpawning uses OverrideRootScale. Pass the scale method explicitly when the root component has a non-unit default scale.

Object pooling

SpawnActor/Destroy churn for projectiles or casings costs GC time. Park actors instead: hide, disable collision and tick; reuse by reversing. AActor has no IsActive(); use IsHidden() (Actor.h:4523) as the parked flag.

Full pooled-actor class (Acquire/Release with GC-safe storage): references/component-types.md.

Ticking

FTickFunction fields (Engine/EngineBaseTypes.h): bCanEverTick (:213), bStartWithTickEnabled (:217), bTickEvenWhenPaused (:209), bAllowTickOnDedicatedServer (:221), TickGroup (:196), EndTickGroup (:204), TickInterval (:258). Actors use PrimaryActorTick (Actor.h:318), components 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) Use
TG_PrePhysics Default. Input, movement requests, AI decisions
TG_DuringPhysics Work that does not read this frame's physics results
TG_PostPhysics Camera, IK, anything reading final physics transforms
TG_PostUpdateWork Last gameplay group
TG_StartPhysics, TG_EndPhysics, TG_LastDemotable, TG_NewlySpawned Engine-internal; never assign

Ordering between specific objects: AddTickPrerequisiteActor(AActor* PrerequisiteActor) and AddTickPrerequisiteComponent(UActorComponent* PrerequisiteComponent) exist on both AActor (Actor.h:2093, 2097) and UActorComponent (ActorComponent.h:1355, 1359). SetTickableWhenPaused(bool bTickableWhenPaused) (Actor.h:2113, ActorComponent.h:618). Change group at runtime with SetTickGroup(ETickingGroup NewTickGroup) (Actor.h:3566, ActorComponent.h:1351). Fixed-step physics callbacks: bAsyncPhysicsTickEnabled (Actor.h:699) plus virtual void AsyncPhysicsTickActor(float DeltaTime, float SimTime) (Actor.h:2930); see ue-physics-collision.

When not to tick

Need Use instead
Delayed or repeating work GetWorldTimerManager().SetTimer(FTimerHandle& InOutHandle, UserClass* InObj, TMethodPtr InTimerMethod, float InRate, bool InbLoop = false, float InFirstDelay = -1.f) (TimerManager.h:167)
React to state change Dynamic multicast delegate on the component, bound in PostInitializeComponents
Collision OnComponentBeginOverlap, OnComponentHit (PrimitiveComponent.h:1457-1475), OnActorBeginOverlap (Actor.h:1368); see ue-physics-collision
Cheap per-frame updates Keep tick but throttle with TickInterval and disable with SetActorTickEnabled(false) when idle

Interfaces

Use a UINTERFACE for a capability ("can be interacted with") that unrelated actors share; use a component when the behavior owns state or needs to tick. Blueprint-facing exposure rules (BlueprintImplementableEvent, meta= specifiers, latent actions) are owned by 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);
};

Implementers inherit both classes, class MYGAME_API AMyChest : public AActor, public IMyInteractable, and override virtual void OnInteract_Implementation(AActor* InstigatorActor) override;. Callers never invoke OnInteract directly:

// 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)
}

Composition Patterns

Prefer a flat actor plus components over deep hierarchies (AMyCharacter + UMyHealthComponent + UMyInventoryComponent), with one class and many data assets instead of one subclass per variant. Components talk through the owner (GetOwner()->FindComponentByClass<UMyHealthComponent>()) or through delegates, never through cached raw pointers to siblings. Data-driven loadouts add components at runtime from a TArray<TSubclassOf<UActorComponent>> on a data asset:

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
    }
}

For components injected into actors by plugins or Game Features, use UGameFrameworkComponentManager::AddReceiver(AActor* Receiver, bool bAddOnlyInGameWorlds = true) from ModularGameplay (Beta in 5.8); see ue-game-features.

Deprecated โ€” do not use

Do not emit Use in 5.8 Source
FindComponentByInterface<UMyInterface>() FindComponentByInterface<IMyInterface>() UE_DEPRECATED(5.5) in GameFramework/Actor.h:3844
PreDuplicate(FObjectDuplicationParameters&) PreDuplicateFromRoot(FObjectDuplicationParameters& DupParams) UE_DEPRECATED(5.6) in GameFramework/Actor.h:2413
Actor->LastRenderTime GetLastRenderTime() / SetLastRenderTime(float) UE_DEPRECATED(5.6) in GameFramework/Actor.h:138
NetUpdateFrequency = 30.f, MinNetUpdateFrequency = ..., NetCullDistanceSquared = ... SetNetUpdateFrequency(), SetMinNetUpdateFrequency(), SetNetCullDistanceSquared() UE_DEPRECATED(5.5) in GameFramework/Actor.h:898-909
BeginReplication() / EndReplication() overrides OnReplicationStartedForIris / OnStopReplicationForIris / FillReplicationParams; see ue-networking-replication UE_DEPRECATED(5.7) in GameFramework/Actor.h:3493-3506
APawn::GetMovementBase() GetMovementBaseObject() / GetMovementBaseInterfaceData(); see ue-character-movement UE_DEPRECATED(5.8) in GameFramework/Pawn.h:59
AttachTo(...), K2_AttachTo(...), AttachRootComponentTo(...) AttachToComponent(Parent, FAttachmentTransformRules, SocketName) UE_DEPRECATED(4.17) in GameFramework/Actor.h:1991, Components/SceneComponent.h:740
AttachRootComponentToActor(...) AttachToActor(ParentActor, FAttachmentTransformRules, SocketName) UE_DEPRECATED(4.17) in GameFramework/Actor.h:2018
DetachFromParent(bool), DetachRootComponentFromParent(bool) DetachFromComponent(FDetachmentTransformRules), DetachFromActor(FDetachmentTransformRules) UE_DEPRECATED(4.12) in Components/SceneComponent.h:768; UE_DEPRECATED(4.17) in GameFramework/Actor.h:2045
Comp->bReplicates = true SetIsReplicatedByDefault(true) (constructor) or SetIsReplicated(true) private member, Components/ActorComponent.h:264-267
Comp->bCreatedByConstructionScript Comp->CreationMethod == EComponentCreationMethod::UserConstructionScript or IsCreatedByConstructionScript() @deprecated Replaced by CreationMethod, Components/ActorComponent.h:306-310
SceneComp->RelativeLocation = ..., SceneComp->bVisible = ..., SceneComp->AttachParent SetRelativeLocation(), SetVisibility(), GetAttachParent() private members, Components/SceneComponent.h:109-183
Actor->bHidden IsHidden() / SetActorHiddenInGame(bool) private member, GameFramework/Actor.h:365
GetComponentsByClass(...) in C++ (the C++ name is K2_GetComponentsByClass) GetComponents<T>(OutArray) or TInlineComponentArray<T*> "intended to only be used by blueprints", GameFramework/Actor.h:3801-3807
LightmapType on primitives GetLightmapType() / SetLightmapType() UE_DEPRECATED(5.5) in Components/PrimitiveComponent.h:359

Common Mistakes

World access in the constructor: GetWorld() is nullptr on the CDO; SpawnActor, timers and lookups belong in BeginPlay, component binding in PostInitializeComponents.

Skipping Super::: every lifecycle override calls its Super:: (BeginPlay first thing; EndPlay(EndPlayReason) last). AActor::EndPlay is what forwards EndPlay to components; RouteEndPlay ensures against a missing Super::EndPlay (Actor.cpp:3230).

Pooled or cached actors outside a UPROPERTY: a plain TArray<AMyProjectile*> member is invisible to GC; declare UPROPERTY() TArray<TObjectPtr<AMyProjectile>>. For non-owning references in non-UObject code use TWeakObjectPtr<AActor> and check IsValid().

AttachToComponent in the constructor: the header allows it on unregistered components, but SetupAttachment is the intended call there (SceneComponent.h:745-746); use AttachToComponent from BeginPlay onward and check its bool result.

NewObject without RegisterComponent: the component never gets render or physics state and never ticks. Also call AddInstanceComponent if it should appear in the Details panel and survive serialization.

Deferred spawn without FinishSpawning: the actor stays in a malformed state (Actor.h:632); always pair SpawnActorDeferred with FinishSpawning.

Calling an interface method directly: Target->OnInteract(...) bypasses Blueprint implementers. Test with Implements<UMyInteractable>(), call through IMyInteractable::Execute_OnInteract(Target, ...).

Polling in Tick: if (HealthComp->IsDead()) every frame is replaced by binding OnDeath once; disable tick with SetActorTickEnabled(false) when nothing needs per-frame work.

Assuming child actors exist in PostInitializeComponents: UChildActorComponent children may begin play late (Actor.h:275); read GetChildActor() in or after BeginPlay.

Writing private component flags: bReplicates, bIsActive, bHasBegunPlay, RelativeLocation and bVisible are private; use the setters and queries listed in the tables above.

Related Skills

  • ue-cpp-foundations โ€” UCLASS/UPROPERTY/UFUNCTION specifiers, TObjectPtr vs TWeakObjectPtr, subsystems, GC rules
  • ue-gameplay-framework โ€” GameMode, GameState, PlayerController, Pawn, Character, damage without GAS
  • ue-physics-collision โ€” collision channels and profiles, overlap and hit events, sweeps, async physics tick
  • ue-networking-replication โ€” SetReplicates, property replication, OnRep, RPCs, subobject replication, Iris
  • ue-gameplay-cameras โ€” USpringArmComponent, UCameraComponent, PlayerCameraManager, Gameplay Cameras plugin
  • ue-blueprint-cpp-interop โ€” Blueprint-implementable interfaces, BlueprintNativeEvent rules, latent actions, meta specifiers
  • ue-character-movement โ€” CharacterMovementComponent, movement base API, CMC vs Mover
  • ue-animation-system โ€” USkeletalMeshComponent animation, AnimInstance, montages
  • ue-audio-system โ€” UAudioComponent playback, attenuation, MetaSounds
  • ue-niagara-effects โ€” UNiagaraComponent, system spawning, user parameters
  • ue-game-features โ€” ModularGameplay components, UGameFrameworkComponentManager, Game Feature actions
  • ue-gameplay-abilities โ€” UAbilitySystemComponent placement on actors
  • ue-state-trees โ€” UStateTreeComponent on actors and AI controllers
  • ue-ai-navigation โ€” perception and navigation components
  • ue-procedural-generation โ€” UProceduralMeshComponent, UDynamicMeshComponent, instancing at scale
  • ue-editor-tools โ€” detail customizations, editor utility widgets, UToolMenus and editor subsystems
  • ue-input-system โ€” Enhanced Input actions, mapping contexts, triggers, modifiers and user settings
  • ue-mass-entity โ€” Mass processors, fragments, queries and entity traits
  • ue-materials-rendering โ€” material instances, parameter collections, render targets and post process
  • ue-sequencer-cinematics โ€” Level Sequences, playback, cine cameras and Movie Render Graph
  • ue-world-level-streaming โ€” World Partition, level streaming, data layers and travel

Source: SKILL.md on GitHub

No alerts2d5 checks ยท Risk SAFE
  • Gen Agent Trust Hub2d

    This skill provides comprehensive technical documentation and C++ code patterns for Unreal Engine 5.8 Actor-Component architecture. It includes lifecycle references, component type descriptions, and best practices for gameplay development. No security issues were detected.

  • Socket2d

    No alerts

  • Snyk2d

    Risk: LOW ยท No issues

  • Runlayer6mo

    3 files scanned ยท No issues

  • ZeroLeaks5mo

    Score: 93/100 ยท 2 sections analyzed

Signed by skilld at f3742d7. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 days ago.

Activeupdated 3 days ago
metadata
{
  "version": "2.0.0",
  "engine": "5.8"
}

README badge

README badge for quodsoler/unreal-engine-skills/ue-actor-component-architecture