[UE4]独自プラグインを作成する

今回は自作プラグインの作成例を紹介したいと思います。
アンリアルエンジンにおけるプラグインは、ゲームプロジェクトそのもの、もしくはエディタに追加の機能を持たせることができます。
これを覚える事でより一層深くアンリアルエンジンを自由に使うことができるので、是非試してみてください。

##プロジェクトの準備
ではまず今回の演習用の新規プロジェクトを作成します。
アンリアルエディタから、NewProject -> C++ -> BasicCode を選択してください。
名前はなんでも構いません。ボクはプロジェクト名を"MyPluginTest"とします。
次に、 File -> NewLevel から "Default"を選択し、新規レベルを作成してください。
Content以下に"Maps"フォルダを作り、その中に"TestLevel"として今の新規作成したレベルを保存しましょう
![000.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163667/52b7f557-aba4-83d6-4333-4823ec0dcbff.jpeg)


次にプラグインの雛型を作ります。
エディタのEdit -> Plugins を押してPluginsのウィンドウを開きます。
![001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163667/9d407de8-3ed9-d185-30a9-2ac9587f0cec.jpeg)


すると、次のような画面が開くと思いますので、右下のNewPluginをクリックします。
![002.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163667/b94a43e5-3c39-abe5-3a3e-4d4810c56267.jpeg)


新規プラグイン作成ウィンドウになるので、Blankを選択し、名前を"TestPlugin"にします。
Descriptor Dataには、このプラグインの詳細情報を入力します。必須項目ではないので入力しなくても大丈夫です。
自分がプラグインをGithubかアンリアルのマーケットプレイスで公開する時に入力するものです。
![003.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163667/bf4f2730-4584-de38-b2ca-2d9955065922.jpeg)


コンパイルが済んだら、先ほどのPluginsウィンドウの左タブの一番下に、自分が作成した"TestProject"が追加されているのが確認できると思います。
この時点でなんかもぅやったった感があるんですが楽しくなるのはこれからです。
![004.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163667/99a23680-64e4-5f36-77ce-85cd1a6cfb8a.jpeg)


では、新規クラスを作成する為に、ContentBrowser -> AddNew -> C++ Classをクリックします。
そして以下のように Show All Classesを押してObjectを選択してNextを押してください。
![005.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163667/34c13903-81c5-7088-e16d-d671680e7a85.jpeg)


モジュール選択で先ほど作ったプラグインを指定して、名前を"TestFunctions"にして作成します。
Pluginでも普通にUE内だけでC++クラスを作るようにPublicかPrivateを選択します。
メソッドとして公開したいやつだけをPublicにして不要なファイルを公開しないようにしましょう。
今回はPublicで生成します。
![006.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163667/e50c8ce4-7ff7-4a5a-6db0-8f89eed5f6ff.jpeg)


では、.slnファイルを開いてみて、今まで作成したプラグインとスクリプトが反映されているか確認してみましょう。
以下の画像のようになっていたら無事生成できています。
Resourceフォルダにはこのプラグインのサムネイル画像が保存されています。
![007.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163667/0e3d3719-83c0-7298-1060-d4495839abb8.jpeg)


###プラグインの概要
Pluginファイル本体の拡張子は.upluginです。ちなみにもこの.upluginは必ずしもPluginsフォルダ直下にある必要はないです。
UEではモジュール単位でスクリプトの機能を管理しています。Build.csファイルがプロジェクト側にも、プラグイン側にもあるのが確認できますか？
このファイルにそれぞれのスクリプトで用いるモジュールを記述して読み込みます。
今回は特に使用しないので割愛しますが、次回以降の記事で掘り下げていこうと思います。


##プラグインにスクリプトを記述する
それでは先ほど作ったファイルにソースコードを記述していきます。
中身は以下のように書き換えてみましょう


```TestFunctions.h
#pragma once

#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "TestFunctions.generated.h"

UCLASS(Blueprintable)
class TESTPLUGIN_API UTestFunctions : public UObject
{
	GENERATED_BODY()

	UFUNCTION(BlueprintCallable, Category = "IwaxLab")
	static bool WriteLocation(AActor* Actor);

	UFUNCTION(BlueprintCallable, Category = "IwaxLab",
		meta = (WorldContect = "WorldContextObject"))
	static AActor* GenerateCameraActor(AActor* BaseActor, FVector Location);

};
```

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


#include "TestFunctions.h"
#include "Engine.h"
#include <string>
#include <fstream>

bool UTestFunctions::WriteLocation(AActor* Actor)
{
	if (!Actor) return false;

	//パスの設定
	FString filepath_str = FPaths::ProjectLogDir() / "ActorLocation.txt";
	//stringに変換
	const std::string filepath(TCHAR_TO_UTF8(*filepath_str));


	//Actorのラベルを取得
	FString label_str = Actor->GetActorLabel();
	//stringに変換
	const std::string label(TCHAR_TO_UTF8(*label_str));


	//Actorの座標を取得
	FVector location = Actor->GetActorLocation();


	//座標を書き込み std::ios::appにすると追記モードになる
	std::ofstream ostr(filepath, std::ios::out);
	ostr << label << ":"
		<< location.X << ","
		<< location.Y << ","
		<< location.Z << std::endl;

	return true;

}

//=======================================================

AActor* UTestFunctions::GenerateCameraActor(AActor* BaseActor, FVector Location)
{

	if (!BaseActor) return nullptr;


	//引数に入れたActorから、それが存在するUWorldを取得
	UWorld* World = BaseActor->GetWorld();


	//カメラアクタを生成
	AActor* Actor = World->SpawnActor<ACameraActor>();
	//アクタのラベル
	Actor->SetActorLabel("TestCamera");
	//アクタの位置
	Actor->SetActorLocation(Location);
	//Actor->SetActorLocation(Location);


	//ちなみにアクタの削除は以下のメソッド
	//AActor::Destroy()


	//生成したActorを戻り値として返す
	return Actor;

}
```

##エディタ側でPluginを再コンパイルする
記述出来たらエディタから WIndow->Developer Tools -> Modulesをクリックし、Modulesウィンドウを開きます。
![008.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163667/babeea25-8169-8f9c-901d-de1ca78b62c9.jpeg)


その中に"TestPlugin"が確認できると思うので"ReCompile"を押してコンパイルしてみましょう。
入力に間違いがなければコンパイルが通るはずです。
どうしてもうまくいかない場合は一度エディタを再起動してみてください
![009.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163667/a57b848d-9446-90c7-5a69-b336d51425cb.jpeg)


##Blueprintから扱ってみる
無事コンパイルできましたか？ではでは早速ブループリントから使ってみましょう。
ただそのまえに、カメラを生成するためのレベル情報を取得する為にCubeを一つ作っておきます。
以下の座標に配置してみてください。名前はBaseCubeとします。
![010.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163667/befd28e5-724f-e139-43f0-323cd8a3377d.jpeg)


では、いざレベルブループリントを開きましょう。
ツールバーのBlueprintsからOpenLevelBlueprintで開いてください
そして以下の画像のようにしてみましょう
![011.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163667/f571a04a-4aed-d257-ab50-c9d0240746eb.jpeg)


やっていることとしては、先ほど作成した"BaseCube"からレベル情報を取得して、その同一レベルにカメラアクタを新規作成し、Cubeに対して正面に来る座標でスポーンするようにしています。
そしてその生成したカメラの座標をログとして外部ファイルにテキストファイル形式で書き出しています。

##いざプレイ
worldOutlinerにTestCameraが追加されてCubeが画角に収まっているのがわかりますでしょうか？
また、./MyPluginTest/Saved/LogsフォルダにActorLocation.txtがあり、座標データが保存されているはずです。
こんな風に、プラグインを用いれば共同開発などで扱いやすい形で独自の機能をアンリアルに付与することができます。
![012.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163667/27bf1976-fb9f-a7c8-50f7-5bddebb78703.jpeg)
![013.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163667/c85fa6c9-52bc-c1c1-dc06-131a91fef1fa.jpeg)


<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">[UE4]独自プラグインを作成する<a href="https://t.co/1O8ctL9YA1">https://t.co/1O8ctL9YA1</a> <a href="https://t.co/TX62VnNbFO">pic.twitter.com/TX62VnNbFO</a></p>&mdash; iwax (@iwax51101141) <a href="https://twitter.com/iwax51101141/status/1173215336889372673?ref_src=twsrc%5Etfw">September 15, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


##お疲れさまでした
以上が基本のプラグイン制作例になります。これを元に是非色々な独自プラグインを是非作ってみてください。
それではまた！