Unreal Engineでは、Level上に配置されているActorの変数の値を変更したり、Actorを移動したりすると、Construction Script(コンストラクションスクリプト)が自動的に実行されます。
複数の変数を連動して変更するなど、Levelエディタ上での編集作業を効率化するために非常に便利な機能です。
Construction Scriptが実行されるタイミングは決まっていますが、通常では実行されないタイミングで意図的に(強制的に)呼び出したいことはないでしょうか。
例えば、あるActorが実行されたら別のActorも実行する、複数のActorを一斉に実行する、ある処理で再実行するなどです。
本記事では、Construction Scriptを意図的に実行する方法を説明します。
なお、本手法を実現するためにはC++での実装が必要です。
汎用的に使えるよう、BP(ブループリント)で実行できるようにする方法も説明します。
※本手法はゲームプレイ中でも実行できますが、安全でない可能性があります。
目次
Construction Scriptが自動的に実行されるタイミング
通常Construction Scriptは、Actorに対する以下の操作で自動的に実行されます(代表的なもの)。
- メンバ変数の値を変更
- 移動・回転・拡大
- BPエディタ上でコンパイル実行
Construction Scriptで実行される処理は、ActorのBPエディタ画面のConstruction Script
に記載します。
Construction Scriptを意図的に実行する方法
それでは、サンプルを示しながら、Construction Scriptを好きなタイミングで意図的に実行する方法を説明します。
先に方法を一言でまとめると、Actorのメンバ関数RerunConstructionScriptsを呼び出すことで実現できます。
サンプルの仕様
以下のようなサンプルを作成します。
- C++で、
Actor
の派生クラスActorA
、
BPで、Actor
の派生クラスActorB
を作成し、Level上に配置する。 ActorA
クラスは、TObjectPtr
型(UE4ではAActor*
型)のメンバ変数TargetActor
を持つ。
TargetActor
変数には、Level上に配置したActorB
を設定する。ActorA
クラスは、Construction Script実行の際、画面上に"A called"を表示するとともに、
TargetActor
変数に設定されているActorのConstruction Scriptを実行する。ActorB
クラスは、Construction Script実行の際、画面上に"B called"を表示する。
Construction Scriptの実行方法
Actor
クラスにはConstruction Scriptを実行するメンバ関数が存在します。
それが、RerunConstructionScripts関数です。
RerunConstructionScripts()
この関数はBPでは呼び出すことができず、C++でのみ呼び出し可能です。
(後ほど、BPで呼び出す方法を説明します。)
この関数を呼び出すことで、Construction Scriptを意図したタイミングで実行可能です。
実行対象のActorを指定することで、自分自身以外のConstruction Scriptの実行も可能です。
サンプルのActorの実装
ActorAクラスのC++ソースコードを以下に示します。
プロジェクト名はMyProject
としています。
C++では、Construction Scriptの処理はOnConstruction関数
に記載します。
OnConstruction
関数で、先ほどのRerunConstructionScripts
関数を呼び出します。
ヘッダファイル(ActorA.h)
#pragma once
#include "GameFramework/Actor.h"
#include "ActorA.generated.h"
UCLASS()
class MYPROJECT_API AActorA : public AActor
{
GENERATED_BODY()
public:
virtual void OnConstruction(const FTransform& Transform) override;
UPROPERTY(EditAnywhere)
TObjectPtr< AActor > TargetActor; // TObjectPtr< AActor > is AActor* in UE4
};
ソースファイル(ActorA.cpp)
#include "ActorA.h"
void AActorA::OnConstruction(const FTransform& Transform)
{
Super::OnConstruction(Transform);
GEngine->AddOnScreenDebugMessage(-1, 3.0f, FColor::Red, "A called");
if (TargetActor) {
TargetActor->RerunConstructionScripts();
}
}
次に、ActorBクラスのBPを以下に示します。
Construction Script
に処理を記載します。
サンプルの実行
作成したActorA
とActorB
を、Level上に配置します。
(C++で作成したActorA
をそのまま配置すると移動できないので、BPでActorA
の派生クラスを作成した上で配置します。)
配置したActorA
のTargetActor
変数に、配置したActorB
を設定します。
ActorA
を移動したり、何らの変数を変更し、ActorA
のConstruction Scriptを実行させてみましょう。
画面上に"A called"と"B called"が表示され、ActorAと同時にActorBのConstruction Scriptが実行されていることが確認できます。
以上のように、RerunConstructionScripts
関数を呼び出すことで、意図的にConstruction Scriptを実行させることができます。
今回は、あるActorから別のActorのConstruction Scriptを実行する処理を例として挙げましたが、RerunConstructionScripts
関数は任意のタイミングで呼び出し可能です。
BPでも意図的に実行できるようにする方法
C++でしかConstruction Scriptを意図的に実行できないのは不便に感じると思います。
そこで、BP関数ライブラリでRerunConstructionScripts関数を呼び出すBP関数を作成すれば、BPでも呼び出し可能になります。
RerunConstructionScripts
関数はC++でしか呼び出せないため、C++でBP関数ライブラリを作成します。
C++のソースコードの一例を以下に示します。
ライブラリ関数名はMyFunctionLibrary
としています。
AActor*
型を入力として受け取り、そのActorのRerunConstructionScripts
関数を実行します。
ヘッダファイル(MyFunctionLibrary.h)
#pragma once
#include "Kismet/BlueprintFunctionLibrary.h"
#include "MyFunctionLibrary.generated.h"
UCLASS()
class MYPROJECT_API UMyFunctionLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable)
static void RerunConstructionScripts(AActor* Target);
};
ソースファイル(MyFunctionLibrary.cpp)
#include "MyFunctionLibrary.h"
void UMyFunctionLibrary::RerunConstructionScripts(AActor* Target)
{
if (Target) {
Target->RerunConstructionScripts();
}
}
このライブラリ関数を利用して、先述のサンプルのActorA
クラスをBPで作成することができます。
このように、BP関数ライブラリで作成しておけば、C++だけでなくBPでもConstruction Scriptを意図的に実行することが可能になります。
まとめ
本記事のポイントは以下のとおりです。
Actor
クラスのメンバ関数RerunConstructionScripts
により、Construction Scriptを意図的に実行することが可能- BP関数ライブラリで
RerunConstructionScripts
関数を呼び出すBP関数を作成すれば、BPでもConstruction Scriptを意図的に実行することが可能
以上が、Construction Scriptを意図的に実行する方法です。
【宣伝】
Colory Gamesでは、Unreal Engine C++の入門書をBoothで販売しています。
対話形式でわかりやすく説明しています。