ue-actor-component-architecture について
UE 5.8 の C++ でコンポーネントから Actor を構成し、そのライフサイクルを扱うためのコーディングスキルです。コンポーネントの作成とアタッチ、Actor のスポーン、Tick、インターフェースを解説します。
主な機能
- 01Actor とコンポーネントのライフサイクル
- 02コンポーネントの作成、登録、アタッチ
- 03即時および遅延 Actor スポーン
- 04Tick の設定とスケジューリング
- 05C++ インターフェースとコンポジションパターン
活用シーン
- 01Actor のロジックを置く場所の判断
- 02実行時のコンポーネント追加とアタッチ
- 03構築前の設定を伴う Actor のスポーン
- 04Actor の機能をコンポーネントに分割
インストール
コマンドをコピーしてターミナルで実行します。
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 のヘッダーに照らして検証済みです。古い形式は「非推奨 — 使用しないでください」に記載しています。
コンポーネントを組み合わせてアクターを構築します。ライフサイクルフックの正しい順序、スポーン(即時、遅延、プール)、コンポーネントの作成とアタッチ、ティック、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/ネットワーク設定)。ファイルがなくても作業を中断しないでください。
リクエストとコードベースから対象領域を特定してください。妥当な解釈が 2 通りあり、それぞれで異なるコードになる場合に限り、質問してください。
| リクエストの内容… | 参照先 |
|---|---|
| コードを記述する場所:コンストラクター、PostInitializeComponents、BeginPlay、EndPlay | アクターのライフサイクル |
| コンポーネントの作成、アタッチ、有効化 | コンポーネントシステム |
| コンポーネントフックのオーバーライド(OnRegister、InitializeComponent、TickComponent) | コンポーネントのライフサイクルフック |
| SpawnActor、遅延スポーン、プーリング | スポーン |
| ティックグループ、ティック間隔、前提条件、ティックとタイマーの使い分け | ティック |
| キャストを使わずにアクター間で機能を提供する方法 | インターフェース |
| 肥大化したアクターのコンポーネントへの分割、データ駆動型ロードアウト | コンポジションパターン |
| イベントの全順序、EEndPlayReason、ネットワークと子アクターのタイミング | 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
アクターやコンポーネントに対して、new/delete を決して使わないでください。アクターには UWorld::SpawnActor と AActor::Destroy(bool bNetForce = false, bool bShouldModifyLevel = true)(Actor.h:2327)を使用します。コンポーネントには CreateDefaultSubobject/NewObject と UActorComponent::DestroyComponent(bool bPromoteChildren = false)(ActorComponent.h:1328)を使用します。
アクターのライフサイクル
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 の使い分け
コンストラクターは、GetWorld() が nullptr となる Class Default Object 上で実行されます。ワールドや他のアクターを必要とする処理は、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.h:275)。プロパティ到着時のフックは PreNetReceive()/PostNetReceive()(Actor.h:2943-2946)と PostNetInit() です。PostNetInit() は「スポーンおよびレプリケートされたプロパティの読み込み直後に必ず呼び出されます」(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(); }
}
コンポーネントのレプリケーション:UActorComponent では bReplicates は private です(ActorComponent.h:267)。コンストラクターで SetIsReplicatedByDefault(true) を呼び出すか、後から SetIsReplicated(true) を呼び出してください。また、所有するアクターもレプリケーションする必要があります。詳細は 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() は登録を解除し、GC の対象にします。Outer がアクターであるコンポーネントは、そのアクターの OwnedComponents に追加されます(PostInitProperties 内の ActorComponent.cpp:600、登録時の :951)。この OwnedComponents は AActor::AddReferencedObjects によって GC に通知されます(Actor.cpp:574)。そのため、DestroyComponent() が呼ばれるかアクターが破棄されるまで、UPROPERTY の有無にかかわらずコンポーネントは存続します。それでも、追跡されて安全に null 化されるよう、自身のポインターを 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&) | ルートを介してアクター全体をアタッチします。アタッチ呼び出しはいずれも bool を返します | Actor.h:2015, 2029, 2062 |
K2_AttachToComponent(...)、K2_AttachToActor(...) | Blueprint ノード専用です。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 は public です(: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 は private です)。virtual bool ShouldActivate() const(:807)をオーバーライドすると、アクティベーションを制御できます。デリゲートは OnComponentActivated / OnComponentDeactivated です(:559, :563)。
コンポーネントのライフサイクルフック
UActorComponent のサブクラスで以下をオーバーライドします。シグネチャは Components/ActorComponent.h の記述そのままです。
| フック | 行 | 呼び出されるタイミング |
|---|---|---|
virtual void OnComponentCreated() | :1331 | アクターのスポーン時にネイティブコンポーネントで呼び出されます。レベルからロードされたコンポーネントでは呼び出されません |
virtual void OnRegister() / virtual void OnUnregister() | :830, :835 | ワールドへの登録時と登録解除時に呼び出されます。描画/物理状態は OnRegister の後に作成されます |
virtual void InitializeComponent() / virtual void UninitializeComponent() | :919, :955 | bWantsInitializeComponent(:340)が true の場合のみ、セッションごとに 1 回呼び出されます |
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 が有効で、コンポーネントが登録されている必要があります |
virtual void OnComponentDestroyed(bool bDestroyingHierarchy) | :1338 | DestroyComponent から呼び出されます |
HasBeenCreated(), HasBeenInitialized(), HasBegunPlay(), IsRegistered(), IsBeingDestroyed() | :505-520, :1316 | 状態を確認します。ビットフィールドは private です |
GetOwner()(:538)と GetOwner<T>()(:542)は、所有元のアクターを返します。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.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;
}
2 つのデフォルト値は異なります。SpawnActorDeferred は MultiplyWithRoot を使用し、FinishSpawning は OverrideRootScale を使用します。ルートコンポーネントのデフォルトスケールが 1 以外の場合は、スケールメソッドを明示的に渡してください。
オブジェクトプーリング
プロジェクタイルや薬莢に対する SpawnActor/Destroy の繰り返しは、GC の処理時間を消費します。アクターを破棄せずに待機させます。非表示にし、衝突判定とティックを無効にして、再利用時に元に戻します。AActor に IsActive() はありません。待機中かどうかのフラグには IsHidden()(Actor.h:4523)を使用します。
プールされたアクターのクラス全体(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)。アクターでは 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 | エンジン内部用。割り当てないでください |
特定のオブジェクト間の順序制御には、AActor(Actor.h:2093, 2097)と UActorComponent(ActorComponent.h:1355, 1359)の両方にある AddTickPrerequisiteActor(AActor* PrerequisiteActor) と AddTickPrerequisiteComponent(UActorComponent* PrerequisiteComponent) を使用します。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 を使います。動作が状態を持つ場合や 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)
}
コンポジションパターン
深い継承階層ではなく、フラットなアクターとコンポーネントの組み合わせ(AMyCharacter + UMyHealthComponent + UMyInventoryComponent)を優先します。また、バリエーションごとにサブクラスを作るのではなく、1 つのクラスと複数のデータアセットを使います。コンポーネント間の通信にはオーナー経由(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 によってアクターへ注入されるコンポーネントには、ModularGameplay の UGameFrameworkComponentManager::AddReceiver(AActor* Receiver, bool bAddOnlyInGameWorlds = true) を使用します(5.8 ではベータ)。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 の @deprecated Replaced by 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) |
よくある間違い
コンストラクターでのワールドへのアクセス: CDO では GetWorld() は nullptr です。SpawnActor、タイマー、検索処理は BeginPlay で、コンポーネントのバインドは PostInitializeComponents で行います。
Super:: の呼び出しを省略する: ライフサイクルのオーバーライドでは、すべて Super:: を呼び出します(BeginPlay では最初に、EndPlay(EndPlayReason) では最後に呼び出します)。AActor::EndPlay は、コンポーネントに EndPlay を転送します。RouteEndPlay は Super::EndPlay の呼び出し漏れに対する安全策です(Actor.cpp:3230)。
UPROPERTY の外にあるプール済みまたはキャッシュ済みのアクター: 通常の TArray<AMyProjectile*> メンバーは GC から認識されません。UPROPERTY() TArray<TObjectPtr<AMyProjectile>> として宣言してください。UObject 以外のコードで非所有参照を使う場合は、TWeakObjectPtr<AActor> を使い、IsValid() を確認してください。
コンストラクターでの AttachToComponent: ヘッダー上は未登録コンポーネントにも使えますが、ここで使うことを想定した呼び出しは SetupAttachment です(SceneComponent.h:745-746)。BeginPlay 以降で AttachToComponent を使い、その bool の戻り値を確認してください。
RegisterComponent を呼び出さずに NewObject を使う: コンポーネントに描画状態や物理状態が設定されず、ティックも実行されません。また、Details パネルに表示し、シリアライズ後も保持する必要がある場合は、AddInstanceComponent も呼び出してください。
Deferred Spawn 後に FinishSpawning を呼び出さない: アクターが不正な状態のままになります(Actor.h:632)。必ず SpawnActorDeferred と FinishSpawning を組み合わせてください。
インターフェースメソッドを直接呼び出す: Target->OnInteract(...) では Blueprint の実装が呼び出されません。Implements<UMyInteractable>() で確認し、IMyInteractable::Execute_OnInteract(Target, ...) を通じて呼び出してください。
Tick でポーリングする: 毎フレーム if (HealthComp->IsDead()) を実行する代わりに、OnDeath を一度バインドしてください。毎フレームの処理が不要になったら、SetActorTickEnabled(false) でティックを無効にしてください。
PostInitializeComponents で子アクターが存在すると想定する: UChildActorComponent の子アクターは、プレイ開始が遅れることがあります(Actor.h:275)。BeginPlay 中またはその後に GetChildActor() を読み取ってください。
コンポーネントのプライベートフラグを書き換える: bReplicates、bIsActive、bHasBegunPlay、RelativeLocation、bVisible はプライベートです。上記の表に記載されているセッターとクエリーを使ってください。
関連スキル
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 のルール、潜在アクション、メタ指定子ue-character-movement— CharacterMovementComponent、移動ベース API、CMC と Mover の比較ue-animation-system— USkeletalMeshComponent のアニメーション、AnimInstance、モンタージュue-audio-system— UAudioComponent の再生、減衰、MetaSoundsue-niagara-effects— UNiagaraComponent、システムのスポーン、ユーザーパラメーターue-game-features— ModularGameplay コンポーネント、UGameFrameworkComponentManager、Game Feature アクションue-gameplay-abilities— アクター上の UAbilitySystemComponent の配置ue-state-trees— アクターと 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、レベルストリーミング、データレイヤー、トラベル