ブループリントで配列、繰り返し処理、実行順序の制御（ゲート、シーケンス）（Unreal Engine 4.25）

# 前提

身内用に書いたものを、暫定的に公開しているものです。何かおこったら閉じるかもしれません。

[前の記事](https://qiita.com/mml/items/5273a7699cdeb9ca21da)に書いた知識（ブループリントの最低限の知識）は持っている、という前提で書いてます。特に説明のない限り、Unreal Engine 4.25 で FirstPerson テンプレートで作成したプロジェクトのレベルブループリントのイベントグラフ上で操作をする前提です。

参考までに javascript や C# で同じ処理を書いたらどうなるかを併記しておきます（厳密にいうと同じではないこともあります。あくまでイメージです…）。

# 参考

下記の公式記事をある程度まとめたのです。わかる人は、下記の記事群を直接見たほうが速いです。

- [フロー制御](https://docs.unrealengine.com/ja/Engine/Blueprints/UserGuide/FlowControl/index.html): 公式記事
- [配列](https://docs.unrealengine.com/ja/Engine/Blueprints/BP_HowTo/WorkingWithArrays/index.html): 公式記事
- [配列の概要](https://docs.unrealengine.com/ja/Engine/Blueprints/UserGuide/Arrays/ArrayNodes/index.html): 公式記事
- [マップ](https://docs.unrealengine.com/ja/Engine/Blueprints/BP_HowTo/WorkingWithMaps/index.html): 公式記事
- [マップの概要](https://docs.unrealengine.com/ja/Engine/Blueprints/UserGuide/Maps/MapNodes/index.html): 公式記事

# 準備

以下、Unreal Engine 4.25.3 を使う前提で記事を書いています。4.24 でも多分動きます。

文中のブループリントのサンプルは、FirstPersonExample をベースにスターターコンテンツ有りで作成したプロジェクトをベースにしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/a493397a-e071-44f0-cbb5-bcb866a0a985.png)

# 配列

ブループリントの配列は、可変長配列です。

## 配列の作成

```sample.js
var Value = [];
```

```sample.cs
int[] Value = new int[4]; // C#の配列は可変長ではないので厳密には同じではない
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/0a963c79-9af7-a7d5-c9b5-917c762ead5f.png)

通常の変数を作るように、マイブループリントの「変数」の右側の＋を押して変数を作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/b981a084-078e-cdcc-6a37-31db877e3d9b.png)

次に、右側の「詳細」の変数の型のすぐ右側にあるアイコンを押して、メニューから「配列」を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/afa7eb68-f3f5-640c-c858-2c86a03fc9e7.png)

左側の「マイブループリント」の変数名の左側のアイコンも配列のものに変更されます。これで、Value 変数は配列として使用できます。

## 配列の初期化

```sample.js
var Value = [0,2,3,4];
```

```sample.cs
int[] value = new int[]{0,2,3,4};
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/4ba7dc37-53b3-7948-9a11-740019be1171.png)

配列の変数を作成したあとに、一度「コンパイル」を押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/aaf2b86e-db78-e75e-661e-4c74a58e2ab7.png)

「詳細」の中の「デフォルト値」のところがこのようになるはずです。

![ue01.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/293186fd-39df-9b71-ab42-dab7bceea00a.gif)

＋のアイコンを押すと、配列の要素数を増やせます。初期化したい値を直接入力することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/7de01a86-e9fa-4a76-0da2-6663db388c77.png)

要素を削除したいときは、要素の右側にある三角形アイコンを押してメニューを出し、削除を選びます。同様にして、要素の挿入やコピーもできます。

## 配列の要素を取り出す

Get ノードを使うことで、配列の要素を取り出せます。取り出すときに、要素のコピーを作成するか、要素をそのまま（参照として）取り出すか選べます。

```sample.js
console.log(Value[0])
```

```sample.cs
System.Console.WriteLine( Value[0].ToString() );
```

![ue2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/e603ce54-09b7-447f-2f63-c323cfca92ff.gif)

Get と書かれたノードの左下の数値（インデックス（を変更することで、取り出す要素を変えられます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/5689b337-a287-7a30-00fc-d8d2b965b4f8.png)

要素のインデックスを変数で与えることもできます。

## 配列の要素を設定する

```sample.js
Value[2] = 5;
```

```sample.cs
Value[2] = 5;
```

![ue3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/5d6e42ff-5e18-7fea-868a-549921ad03da.gif)

SetArrayElem ノードを使います。配列の変数自体には Get を使います（Set ではなく）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/d01073aa-ef1e-f360-c304-9afbd3e15287.png)

SizeToFit にチェックを入れると、配列のサイズを超える Index を指定したときに、自動的に配列のサイズを増加させます。チェックを入れないと、配列のサイズを超えている場合には何も実行されません。

## 配列に対するいろいろな操作

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/541f4f2b-a7c9-ae19-c477-07ecab02bd01.png)

他の言語でできるような配列操作はだいたいできます。ここでは説明を省略しますが、知りたい人は下記を見てください。

- [配列の概要](https://docs.unrealengine.com/ja/Engine/Blueprints/UserGuide/Arrays/ArrayNodes/index.html): 公式記事

# マップ（連想配列）

ブループリントでは、連想配列に相当するものはマップと呼ばれます。ブループリントのマップは、値の型が明示されます。

## マップの作成

```sample.js
var Value = {}; // 厳密には同じではない
```

```sample.cs
Hashtable Value = new Hashtable();
// Hashtable は値の型が String なので厳密には同じではない
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/0a963c79-9af7-a7d5-c9b5-917c762ead5f.png)

通常の変数を作るように、マイブループリントの「変数」の右側の＋を押して変数を作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/d1150c4d-0548-1fd0-9066-d4c1b5cefef3.png)

次に、右側の「詳細」の変数の型のすぐ右側にあるアイコンを押して、メニューから「マップ（辞書）」を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/74228e7e-b610-a06e-b84d-96141b25635a.png)

マップのキーの型を「変数のタイプ」として選び、値の型を「値タイプ」で選びます。上の例では、キーを String 型にして、値を Integer 型にしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/0acdda9b-05c1-55cd-d334-1f7db1eefd13.png)

型を設定すると、マップの変数の色がキーの型の色と値の型の色が混じったような色になります。

## マップの初期化

配列の初期化と同じようにできます。

```sample.js
var Value = {
    "first": 0,
    "second": 10,
    "third": 100
}; // 厳密には同じではない
```

```sample.cs
Hashtable Value = new Hashtable {
    ["first"] = "0",
    ["second"] = "10",
    ["third"] = "100"
}; // 値の型が違うので厳密には同じではない
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/4ba7dc37-53b3-7948-9a11-740019be1171.png)

マップの変数を作成したあとに、一度「コンパイル」を押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/3d2f5c64-5021-3f6b-6cb8-0766605487ed.png)

デフォルト値を追加できるようになります。＋を押すと要素を追加できます。Value 側にキーを入れ、エレメント側に値を入力します。

## マップの要素の値を取り出す

キーに対応する値を取り出すには、Find というノードを使います。

```sample.js
console.log( Value["First"] );
```

```sample.cs
System.Console.Write(Value["First"].ToString());
```

![ue4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/b6b53d53-8152-7952-7a4f-75b23075e445.gif)

## マップの要素の値を設定・追加する

```sample.js
Value["Fourth"] = 1000;
```

```sample.cs
Value["Fourth"] = "1000";
Value.Add("Fourth","1000");
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/4758fe10-a1c3-110a-04a4-d0efcb9265b3.png)

要素のの追加は Add ノードを使います。キーに対する値がすでに存在するときは、値が上書きされます。

## マップの要素のいろいろな操作

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/9a40cb25-47ce-81a9-9eb9-d184690ffd0c.png)

詳しくは下記を参照してください。

- [マップの概要](https://docs.unrealengine.com/ja/Engine/Blueprints/UserGuide/Maps/MapNodes/index.html): 公式記事

# 繰り返し処理

多言語の for, foreach, while ループに相当するノードがあります。

## ForLoop

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/076c7e39-5c1d-d6b7-88f7-c98283d3f90d.png)

Break 無しのものと付きのものがあります。ループカウンタがノードに内蔵されているため、カウンタ変数を用意する必要はありません。

```sample.js
var Sum = 0;
for (var i = 0; i < 100; i++ ){
    Sum += i;
}
console.log( Sum );
```

```sample.cs
int Sum = 0;
for (int i = 0; i < 100; i++ ){
    Sum += i;
}
System.Console.Write( Sum.ToString() );
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/2060308b-d512-8f0c-689d-261c0b7350a7.png)


## ForEachLoop

ForEachLoop は配列（Array）を引数に取ります。

```sample.js
var Sum = 0;
var array = [1,2,3,4,5];
array.forEach( function( value ){
    Sum += value;
});
console.log( Sum );
```

```sample.cs
int Sum = 0;
int [] array = new int[]{ 1,2,3,4,5 };
foreach( int e in array ){
    Sum += e;
}
System.Console.WriteLine( Sum.ToString() );
```

配列の要素の和を計算しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/84713db9-d965-a31c-8d6d-acd450871647.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/d1af9ce0-c020-0bae-b18d-a890e99816e1.png)

Break 付きのもの、配列を逆順で順番に処理する ForEachLoop もあります。

## WhileLoop

入力される Boolean の値が true の間、ループを繰り返します。

```sample.js
var Sum = 0;
var Value = 0;
while ( Value <= 10 ){
    Sum += Value;
}
console.log( Sum );
```

```sample.cs
int Sum = 0;
int Value = 0;
while ( Value <= 10 ){
    Sum += Value;
}
System.Console.Write( Sum.ToString() );
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/bd694601-2bb4-ab87-c926-c80f06f8e85c.png)

# ブループリント独自の制御ノード

## シーケンス (Sequence)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/9c5e4edd-8542-2895-f3b7-2047a21df48a.png)

右側の白い出力ピンの上から順番に実行します。並列に実行されるわけではなく、一番上のピンの先がすべて実行されたら、２番目のピンが実行されます。ピンは＋を押して増やすことができます。

ブループリントは横方向に長くなりがちですが、このノードを使うと縦方向に処理を書いていくことができます。

## ゲート (Gate)

何かのイベントをトリガーにして、Exit の先のノードを実行するようにしたり、実行しないようにしたり、切り替えることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/22a89906-2b22-e31b-5e29-30b291c83a13.png)

何かのボタンを押している間だけ動くオブジェクト、上に乗ると移動する床、部屋に入ると作動する床みたいな、特定のイベントをトリガーとして動いたり止まったりするオブジェクトの動作の記述に使えます。

変数とブランチを使って同じようなこともできますが、ゲートで書いたほうがノード数がすくすみます。

## マルチゲート (MultiGate)

実行されるたびに、違う出力ピンの先を実行します。名前が Gate に似てますが、動作はかなり違います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/60e4f5d3-2212-31d6-2575-9c0142b39bb2.png)

上のグラフでは、１回目にEnterを押すと 1 が表示荒れ、2回目は2、3回目は3と表示され、それ以降は Enter を押しても何も実行されません。

Loop にチェックを入れると、4回目からは1回目に戻ります。Random にチェックを入れると、実行される順番がランダムになります。

## DoOnce / DoN

DoOnce は、ループで最初の1回目だけ実行したいとか、イベントに1回だけ反応するみたいなときに使います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/3d881a5c-b32e-89c0-c274-28201e8af8fc.png)

DoN は DoOnce の回数を指定できる版です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/ee85fc6c-eea9-951d-49a2-c432dbf6cddf.png)

## フリップフロップ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/6ed53459-6393-ad33-b97b-2b5ff3349c72.png)

実行されるたびに、実行するピンを A と B とで交互に切り替えます。

# 続く？

次回は、関数やマクロの書き方の予定です。