Blog

[UE4] プラグインとアクタの連携について(1)

執筆者 / K.T

はじめに

UE4で、レベルに依存しない汎用的な処理を、プラグインとして切り離しておくと便利です。

プラグインに、アクタとの連携機能やティック機能を持たせれば、より使い勝手が良くなります。

そのようなプラグインのサンプルを作成してみます。

この記事の内容

長いので、2回に分けてお送りします。

今回(1/2)は、サンプルのプロジェクトを作成した上で、以下のような機能を持つプラグインを追加します。

 1.デリゲートを持ち、アクタのイベント関数を結合できる

 2.ティック機能を持ち、ティック関数が呼び出される

 3.ティック関数でデリゲートを実行し、パラメータ(角度)をアクタのイベント関数へ送る

 4.パラメータ(角度)は等速で増え続ける

次回(2/2)は、アクタがイベント関数でパラメータ(角度)を受け取り、自身のZ軸回転に反映させるようにします。

つまりアクタがコマのようにくるくる回るようにします。

また、カメラをアクタの背後に置いて、アクタと一緒に回転するようにします。

これによって生じる問題点についても解説し、修正を行います。

用意するもの

・Unreal Engine 4.23.1

・Visual Studio 2017

プロジェクトの作成

プロジェクトブラウザを起動し、新規プロジェクトを作成します。

C++タブの基本コードを選択し、スターターコンテンツは有りにしましょう。

プロジェクトを作成したら、いったん閉じます。

そして、できあがったプロジェクトのContentフォルダ内に、Flyingというフォルダを作成してください。

作成したFlyingフォルダの中に、以下のフォルダから4つのアセットファイルをコピーします。

UE_4.23\Templates\TemplateResources\Standard\Flying\Content\Meshes

ここまでできたら、プロジェクトを起動してください。

メッシュの設定

コンテンツ/Flyingフォルダ内のUFOMaterialを開きます。

詳細の[一般]-[Parent]にBaseMaterialを設定すると、パラメータグループが現れるので、保存後に閉じてください。

続いて、同じくFlyingフォルダ内のUFOを開きます。

詳細の[Material Slots]-[エレメント0]にUFOMaterialを設定すると、メッシュが水色に変わるので、保存後に閉じてください。

アクタの設定

コンテンツフォルダ内にブループリントクラスを新規追加します。

親クラスはActorにしてください。

作成したActorFlyingを開きます。

DefaultSceneRootの下に、StaticMeshComponentを追加してください。

詳細の[Static Mesh]-[Static Mesh]にUFOを設定します。

また、[Materials]-[エレメント0]にUFOMaterialを設定します。

コンパイルして保存後に閉じてください。

ActorFlyingをビューポートにドラッグ&ドロップして、マップへ配置します。

詳細の[トランスフォーム]で、アクタの位置や回転を図のように設定してください。

プラグインの作成

メニューの[編集]-[プラグイン]を選択します。

[New Plugin]ボタンを押してください。

Blueprint Libraryを選択し、[Name]にControlActorと入力してください。

[Create Plugin]ボタンを押すと、プラグインのひな形が作成されます。

プラグインの編集

Visual Studioでソリューションが開かれるので、プラグインのソースコードを編集していきましょう。

図でフォーカスされている4つのファイルが対象です。

編集が終わったら、ソリューションをビルドして、保存後に閉じてください。

ControlActorBPLibrary.h
#pragma once

#include “Kismet/BlueprintFunctionLibrary.h”
#include “ControlActorBPLibrary.generated.h”

// 動的デリゲートの宣言(引数としてfloatを1つ渡します)
DECLARE_DYNAMIC_DELEGATE_OneParam(FControlActorEvent, float, RotYaw);

UCLASS()
class UControlActorBPLibrary : public UBlueprintFunctionLibrary
{
GENERATED_UCLASS_BODY()

// イベント関数を結合(ブループリントから呼び出せる関数です)
UFUNCTION(BlueprintCallable, Category=”ControlActor”)
static void BindEvent(UObject* object, FName func_name);
};
ControlActorBPLibrary.cpp
#include “ControlActor.h”

// コンストラクタ
UControlActorBPLibrary::UControlActorBPLibrary(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
}

// イベント関数を結合
void UControlActorBPLibrary::BindEvent(UObject* object, FName func_name)
{
FControlActorModule::BindEvent(object, func_name);
}
ControlActor.h
#pragma once

#include “Modules/ModuleManager.h”
#include “Tickable.h”
#include “ControlActorBPLibrary.h”

class FControlActorModule : public IModuleInterface, public FTickableGameObject
{
private:
FControlActorEvent m_Event; // イベント用のデリゲート

public:
// モジュール関連の関数
virtual void StartupModule() override {}
virtual void ShutdownModule() override {}

static inline FControlActorModule& Get(void){ return FModuleManager::LoadModuleChecked< FControlActorModule >( “ControlActor” ); }
static inline bool IsAvailable(void){ return FModuleManager::Get().IsModuleLoaded( “ControlActor” ); }
static FControlActorModule* GetInstance(void){ return ( FControlActorModule::IsAvailable() ? &Get() : nullptr ); }

// ティック関連の関数
virtual TStatId GetStatId(void) const { RETURN_QUICK_DECLARE_CYCLE_STAT(FControlActorModule, STATGROUP_Tickables); }
virtual bool IsTickable(void) const { return true; }
virtual void Tick(float delta_time);

// イベント関数を結合
static void BindEvent(UObject* object, const FName& func_name);
};
ControlActor.cpp
#include “ControlActor.h”

#define LOCTEXT_NAMESPACE “FControlActorModule”

// ティック
void FControlActorModule::Tick(float delta_time)
{
static float rot_yaw = 0.0f;

rot_yaw += 5.0f; // 角度を更新
if(rot_yaw > 360){ rot_yaw -= 360; }

m_Event.ExecuteIfBound(rot_yaw); // デリゲートを実行
}

// イベント関数を結合
void FControlActorModule::BindEvent(UObject* object, const FName& func_name)
{
FControlActorModule* module = GetInstance();

if(module == nullptr){ return; } // インスタンスの取得失敗

if((object == nullptr) || func_name.IsNone()){
module->m_Event.Clear(); // 引数が不正
}else{
// デリゲートにイベント関数を結合
module->m_Event.BindUFunction(object, func_name);
}
}

#undef LOCTEXT_NAMESPACE

IMPLEMENT_MODULE(FControlActorModule, ControlActor)

プラグインの解説

コメントでだいたい理解できると思いますが、ポイントとなる部分について簡単に解説します。

・ControlActorBPLibrary.h(7行目)

FControlActorEventという動的デリゲートを宣言しています。

プラグインからアクタへ、イベントという形で情報を送るためのものです。

・ControlActorBPLibrary.h(16行目)

BindEventという関数を宣言しています。

この関数は、ブループリントから呼び出すことが可能です。

第1引数のobjectには、イベント関数を保有するアクタオブジェクトを渡します。

第2引数のfunc_nameには、イベント関数名を渡します。

・ControlActor.h(7行目)

FTickableGameObjectというクラスを継承しています。

モジュールクラスにティック機能を付加するためのものです。

まとめ

今回(1/2)は、プロジェクトを作成し、アクタやプラグインなど必要なものを追加しました。

また、プラグインのソースコードを編集し、ティック機能やデリゲートを実装しました。

次回(2/2)はこのプラグインとアクタを連携させて、アクタが動くようにします。

参考リンク

デリゲート

FTickableGameObject