johnnyGameStudio’s blog

無能なゲームプログラマのぼやき ぎーくになりたい Twitter: https://twitter.com/JGS_Developer

【UE4】LevelSequenceでActorComponentを継承したComponentのプロパティを扱いたい

はじめに

C++で作成したActorに自分で追加してあるActorComponentのメンバ変数をLevelSequenceで扱いたい場合の手順がまとまっている情報がなかったので備忘録を兼ねてまとめておきます

環境

UE4.24.2
VisualStudioCommunity2017
Windows10

HowTo

ActorのコンストラクタでActorComponentを追加する

たとえ、メンバ変数にActorComponentを持っていたとしてもコンストラクタでCreateDefaultSubobjectで追加しておかないとLevelSequenceで認識してくれません
検証用に以下のサンプルでは二つのActorComponentを

という二つの方法でやってみます

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "TestActor.generated.h"

UCLASS()
class TESTPRJ_API ATestActor : public AActor
{
    GENERATED_BODY()
    
public: 
    // Sets default values for this actor's properties
    ATestActor();

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

private:
    class UTestComponent* testComp;//コンストラクタで生成

    class UTestComponent* testComp2;//BeginPlayで生成
};

// Fill out your copyright notice in the Description page of Project Settings.


#include "TestActor.h"
#include "TestComponent.h"

// Sets default values
ATestActor::ATestActor()
{
    // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;
    testComp = CreateDefaultSubobject<UTestComponent>(TEXT("testComp"));
}

// Called when the game starts or when spawned
void ATestActor::BeginPlay()
{
    Super::BeginPlay();
    testComp2 = NewObject<UTestComponent>(this);
    testComp2->RegisterComponent();
}

LevelSequenceで扱いたいメンバ変数にUPROPERTY(Interp)を付与する

LevelSequenceでメンバ変数を直接変更させる場合、UPROPERTY(Interp)をつけてあげる必要があります
なので今回はてきとーにBoolの変数をActorComponentに追加しました

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "TestComponent.generated.h"


UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class TESTPRJ_API UTestComponent : public UActorComponent
{
    GENERATED_BODY()

public: 
    // Sets default values for this component's properties
    UTestComponent();

protected:
    // Called when the game starts
    virtual void BeginPlay() override;

public: 
    // Called every frame
    virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

private:
    UPROPERTY(Interp)//追加
    bool bFlag;
        
};

確認

てきとーなLevelSequenceを作成し、TestActorのトラックを追加してみるとコンストラクタで追加した「testComp」だけが表示されて「testComp2」は表示されないことがわかります

image.png

また、TestComponentのメンバ変数がLevelSequenceのトラックとして追加できるようになっていることが確認できます

image.png

なぜコンストラクタで追加しないとLevelSequenceで扱えないのか

コンストラクタ内にブレイクポイントを仕込むとわかるのですが、UObjectを継承しているクラスのコンストラクタは以下の二つのタイミングで実行されます

  • ゲームが実行されたとき
  • エディタを起動するとき

つまり、エディタを起動する際にUObjectのリフレクション情報を生成しておいて、その情報を以ってLevelSequenceで扱えるようにしているわけです
C++そのものにリフレクションはないので考えてみれば当たり前ですね