ue-actor-component-architecture

Use this skill when working with Actor and component design in Unreal Engine. Triggers on: Actor, component, BeginPlay, Tick, SpawnActor, lifecycle, CreateDefaultSubobject, composition, EndPlay, PostInitializeComponents, UActorComponent, USceneComponent, UINTERFACE, attachment, spawn, interface. See

By quodsoler · 870 installs

npx skills add quodsoler/unreal-engine-skills --skill ue-actor-component-architecture

Source repository · Upstream listing

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]( actor lifecycle) Creating, attaching, activating components [Component System]( component system) Overriding component hooks (OnRegister, InitializeComponent, TickComponent) [Component Lifecycle Hooks]( component lifecycle hooks) SpawnActor, deferred spawn, pooling [Spawning]( spawning) Tick groups, tick interval, prerequisites, tick vs timer [Ticking]( ticking) Cross actor capability without casting [Interfaces]( interfaces) Splitting a fat actor into components, data driven loadouts [Composition Patterns]( composition patterns) Full event order, EEndPlayReason, network and child actor timing [references/actor lifecycle.md](references/actor lifecycle.md) Which built in component to use, header paths, member APIs [references/component types.md](references/component types.md) Mental Model 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](references/actor lifecycle.md). 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). 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](references/component types.md). Writing a component 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 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 . 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 . 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 ). 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](references/component types.md actor pooling). 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 ). 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