背景アーティストが作るエディタースクリプティング紹介

#はじめに
自分は普段、コンシューマーゲームの開発会社にて、UE4を使用したプロジェクトに**背景アーティスト**として携わっています。
実際のゲーム内に組み込まれるようなプログラムを書くことはほとんど無いのですが、UE4には**エディタースクリプティング**なるものが用意されており、その**導入のし易さ**から**様々な業務を自動化**しています。
今回はその中から、お気に入りのスクリプトを幾つか抜粋し紹介させていただきます。

本記事では具体的なコードの書き方やテクニックの紹介をしません。
**実装方法よりも実装内容を重視**し記載していきます。
未経験者には「こんなことができるのか～:smile:」と、
経験者には「こんな需要があるのか～:smirk:」と、
そんな感じでアレしてもらえたら幸いです。

##BlueprintとPythonの使い分け
この記事を書いている現在(UE4.23)、UE4のエディタースクリプティングは、**Blueprint**と**Python**の2種類の方法が用意されています。
用意されている処理の内容にはほとんど違いを見つけられませんでしたが、
それぞれ、**得意なことが微妙に異なります**。
今回紹介するスクリプトがどのような判断基準で使い分けられているのか、以下にそれぞれの利点を紹介します。

<details><summary>**Blueprint**が得意なこと</summary><div>

 - **手早くそこそこのクオリティのGUIが作れる**
    - 変数を**編集可能**にするだけでそれなりに融通の利くGUIが作れてしまいます
        -  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524423/2c2b3162-a98d-c05d-818a-668f541b21dc.png)  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524423/01911de5-2f0c-ce5c-805b-e268b4ca02a1.png)

 - **アセットを変数にアサインする際に検索ボックスが用意されているなど、基本機能が充実している**
    - 特にテクスチャを細かく入れ替えて運用したい場合などは、基本機能に助けられることが多いです
        -  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524423/bde4e465-7580-db3f-04fa-7aff59406b81.png)

 - **機能の検索をし易い**
    - エディタースクリプティングに限らない話ですが、Blueprintの場合は**"Context Sensitive"**にチェックを入れることで、ノード検索時に**使用可能な変数や関数が全て表示**されます。Pythonの場合はリファレンスから探さなければならないこと考えると、**取っつきやすさが段違い**です
        - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524423/2d0e3d4a-0afd-5e06-25d4-1ecc5ac28391.png)


</div>
</details>
<details><summary>**Python**が得意なこと</summary>
<div>

- **処理が軽い**
    - プロジェクトの規模によっては、コンテントブラウザ走査などの大がかりな処理をBlueprinitで行うと落ちます。Pythonの場合は余裕で行えたため、明確に**実行速度の違いがある**ようです。(UE4.21調べ)
        - <img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524423/a120ff9d-bb5a-0134-9c36-3cb50a862b34.png" width = 75%>

- **外部モジュールを使える**
    - 外部ファイルとの連携などはPythonならではの利点です
        - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524423/e8817356-0047-8a41-1ca3-52aa79c0ea8b.png)

</div>
</details>

#実際に作成したスクリプトの紹介
##アセットを一定間隔で配置するやつ（Blueprint）
<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524423/cb2b9b30-aeb4-2f04-0c2d-d5495ee983b0.png" width = 75%>
**作ったアセットを一望できるレベルが欲しい**という要望があり作成しました。
アセットの大きさに応じて配置順や間隔を変える処理を入れました。

<details>
<summary>**機能紹介**</summary>
<div>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524423/915530a1-8b2f-846f-0f15-4f1cf134300b.png)

 + TargetClasses：このスクリプトで配置するクラスを指定します
 + StartLocation：この位置からY方向に、小さい順で配置していきます
 + ConstDistance：必ずConstDistance分は距離を離してくださいね。という値です
 + MaxExtentY：ここで指定した幅まで達したらX方向に改行します
</div>
</details>

##特定の値のパラメーターを持つマテリアルインスタンスをログに出すやつ（Blueprint）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524423/1d441204-c745-5f0e-43ea-84df77877d3e.png)

 + 意図しないテクスチャのアサインが無いか？
 + スペキュラの値が大きすぎるものが無いか？
 + 使用していないパラメータは無いか？

など、**マテリアルインスタンスの使用状況を調査するとき**に使用しました。

<details>
<summary>**機能紹介**（テクスチャを調べるとき用）</summary>
<div>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524423/79914876-e516-6078-8945-a61c5b43305d.png)

 + ParameterName：調べたいパラメーター名を入力します
 + InputTexutre：ここでアサインされたテクスチャと合致した場合にログに出力します
 + UseListMode：Trueの場合、合致の判定は行わず、対象の全マテリアルインスタンスのテクスチャをログに出力します
</div>
</details>

<details>
<summary>**機能紹介**（スカラー値を調べるとき用）</summary>
<div>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524423/01016c68-bd93-9be1-a7ae-5dc2c79a0bad.png)

 + ParameterName：調べたいパラメーター名を入力します
 + InputValue：ここで入力された値と"SearchType"の関係で合致した場合にログに出力します
 + SearchType：Valueと対照の値との関係を指定します
 + UseListMode：Trueの場合、合致の判定は行わず、対象の全マテリアルインスタンスの値をログに出力します

</div>
</details>
このように、**細かく値を設定しながら使用したいスクリプト**はGUIでの運用が求められます。
Blueprintであれば、**手間も少なく簡潔なGUIが作成できます**。
##レベルをたくさん生成するやつ(Blueprint)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524423/8eb84fd9-012a-99f4-d4bb-b2a68564441a.png)
「12個のサブレベルを6種類作る」みたいな業務があったとき作成しました。
<details>
<summary>**ノードはこれだけで済みます。**</summary>
<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524423/3a96ea75-dfbe-6d4c-ce04-be423cb9c957.png" width = 75%>
</details>
一度きりのスクリプトですが、Blueprintのメリットを活かし、素早く機能の検索、実装ができました。**手作業で複製するよりも大幅に時間を短縮できました。**

##パラメーターコレクションの値をプリセット管理するやつ(Python)
![MPCPresetEditorUtility.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524423/bb230924-c03b-fdb6-3870-5a71fb4637b1.gif)
マテリアルパラメーターコレクション内で値の調整をする業務の際、**プリセット保存できれば試行錯誤できて便利**だなあ、ということを思い、Pysideで作成しました。

<details>
<summary>**機能紹介**</summary>
<div>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524423/9fcbd7c0-fdfa-cb85-9e47-f3720818dc4e.png)


 + Select MPC：コンテントブラウザ上で選択したMPCを登録します。リストにはMPCに対応した登録済のプリセットが表示されます
 + Import Preset：リスト内で選択したプリセットの値を登録したMPCに入力します
 + Export Preset："New Preset Name"に入力した名前で新規プリセットを作成します
</div>
</details>

プリセットはCSVファイルで作成していますが、**外部ファイルを扱い易いのはPythonの強み**です。

##検証用にマテリアルを複製して全部差し替えてくれるやつ(Python)
<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524423/43f70560-33ad-3a30-de0d-725db9533177.png" width = 75%>

現行のレベルデータに影響を与えずに、マテリアルの機能を追加するような検証を行いたい場合

**1. レベルデータ複製**
**2. レベル内で使われているマテリアルと親マテリアルを複製**
**3. 複製マテリアルの親を検証用ベースマテリアルに差し替え**
**4. レベル内のメッシュコンポーネントに複製マテリアルをオーバーライド**
という手順が必要です。
手作業で行うのは厳しいので、これらを一括で行うスクリプトを作りました。
自分の業務の都合上、思ったよりも使用する機会が多く、**作った中では最も費用対効果の高いスクリプト**となりました。

このように大量のデータを扱う処理はPython向きです。
##その他

 + **テクスチャアセットに対し、テクスチャグループやCompressionSettingを一括設定するやつ（Blueprint）**
 + **ドキュメント記載用に、全アセットのリストを作成するやつ（Python）**
 + **マテリアルインスタンスの親を差し替える際、既にオーバーライドしていた値を別名のパラメーターに引き継がせるやつ（Python）**

など、細かいものを上げれば他にも様々なスクリプトを作成しています。

##まとめ
今回紹介したスクリプトは全てローカルで完結しており、且つROMには直接組み込まれないものばかりです。
**自己の作業で完結している**ため、エディタースクリプトは他のプログラム業務と比べ、実験をし易く、プログラムの精度も（比較的）求められません。
**プログラムに興味があるけれどハードルが高い、と感じられている非プログラマーの方がいらっしゃったら、是非エディタースクリプティングの導入をオススメします。**

##エディタースクリプティング入門にオススメの記事
下記の記事は初心者に易しく、段階的に、且つ凄く丁寧に記載されています。自分も学習の際には活用させていただきました！


 + [UE4]エディタ上で動作するツール・エディタ拡張をUMGで簡単に作れる Editor Utility Widget について
    + https://qiita.com/EGJ-Kaz_Okada/items/9f530db3b53d0fde3f20
 + 【UE4】Pythonつかって、MaterialInstanceアセットのパラメーターとかいじってみた
    + https://kinnaji.com/2019/05/16/python-mi-01/