ブループリントで変数、数値演算、論理演算、条件分岐、型変換（Unreal Engine 4.25）

# 前提

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

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/7689a532-411d-5340-427e-4fc497f9fa06.png)

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

# 変数

ブループリントの変数には型があります。イベントグラフの中に書いた変数は、すべてインスタンス変数（的な扱い）になります。関数では、関数の中限定のローカル変数も宣言できます。

## 変数の宣言

```sample.js
var Counter; // javascript は型がないので厳密には同じではない
```

```sample.cs
int Counter;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/4b26f521-3bfc-125a-c32e-c9a06ea21f8b.png)

変数の宣言は、ブループリントのノードではなく、エディタの左にある「マイブループリント」の「変数」という項目の右にある＋を押すことで追加できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/cee07d6a-295f-770b-66c7-13e897a91997.png)

＋を押すと、デフォルトの変数名と型が自動的に設定されます。名前や型を変更するには、変更したい項目（変数）を選んで、右側に出る「詳細」のタブの中で編集します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/34545bea-31e1-a3d1-29c3-03a1b6fc3235.png)

ここで「変数名」「変数の型」など、さまざまな項目を変更できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/75a293ef-b9e9-f6ed-3e1c-7add59d32a50.png)

変数のデフォルト値（初期化時の値）を入れるためには、一度「コンパイル」アイコンを押します。

```sample.js
var Counter = 100;
```

```sample.cs
int Counter = 100;
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/b2cf9f06-c16f-a1ed-749c-b5fe07e88086.png)


コンパイルを一度押すと、デフォルト値が設定できるようになります。変数の名前や型などを変更した後にデフォルト値を設定しなおす時は、再度コンパイルを押す必要があります。

## 変数への代入

```sample.js
Counter = 100;
```

```sample.cs
Counter = 100;
```

![ue02.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/cd664fb1-9485-0d9a-9e9f-1845777fc7a3.gif)


代入したい変数名を左から選んでエディタ内にドラッグドロップします。Set か Get を選ぶメニューが出るので、Set を選びます。そして、設定したい値を直接入力して、実行の白い線をつなぎます。

上の例では Counter 変数に 100 という数値を設定しています。

## 変数の値の読み出し

```sample.js
Counter = Val;
```

```sample.cs
Counter = Val;
```

![ue03.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/8b7fbb7a-187f-dd27-bb5b-6f21c544dab9.gif)

値を読み出したい変数を左から選んでエディタ内にドラッグドロップし、Set か Get を選ぶメニューで Get を選びます。これで値を読み出すノードは作られますが、値を読むノードには実行の白いピンがありません。読み出した値を使う、別の白いピンがあるノードにつなぐことで、実際に値を読み出す処理がなされます。

## 変数の値の読み出しタイミング

読み出すノードから、白いピンのある複数のノードに接続した場合、変数からの値の読み出しは「白いピンのあるノードが実行されるタイミングで」評価されるため、同じ値にならないことがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/c837fa3b-3f38-9165-d34a-5f5495faba56.png)

上のようなグラフの処理の結果、Counter の値は 10 になります。最初の Set Counter ノードが実行されるときは、その直前に Val  に 0 が入っているので、Counter には 0 が代入されます。しかし、次の Set Counter ノードでは、直前に Val に 10 が代入されているので、Counter の値は 10 になります。

同じ Val のノードからそれぞれの Set Counter ノードに線が出ているので、一見して同じ値が入りそうですが、線のつなぎ方とは関係なく「白い線がつながっているノードが実行されるタイミングで」白い線がつながっていないノードの値が評価されるため、このような結果になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/00c5ed2e-b4ce-f042-29ea-b848782039df.png)

ちなみに、このように Get Val ノードを分けて書いても、実行結果は全く同じになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/cb21458a-a571-dfaa-65cb-1e81d5fdc30a.png)

## 変数の型（主なもの）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/fb082db0-dd98-863d-deaf-c725fb04220c.png)

- Boolean: false か true の二値をとる型
- Byte: 符号付8ビット整数型
- Integer: 符号付32ビット整数型。よく使います。
- Integer64: 符号付64ビット整数型
- Float: 浮動小数点型。よく使います。
- String: 文字列型
- Text: 使用言語の設定によって表示内容を変更できる文字列型
- Vector: 浮動小数点の三次元ベクトル型（位置座標などに使う） (float x, float y, float z) 。よく使います。
- Rotator: 浮動小数点の回転角を示す型（float x, float y, float z)
- Transform: アクターの位置、回転角、拡大率を保持する型（Vector Location, Rotator Rotation, Vector Scale)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/87f278ab-829a-7ffc-fe9b-f946a89aca45.png)

配列は、変数の型の右にある、型を示す色の横棒みたいなアイコンを押すことで作れます。配列以外にマップ、集合などにもできます。配列については、後述の配列の項目で詳しく説明します。

## 変数の自動追加

他のノードから引き出した線の先で右クリックして「変数へ昇格」とすると、その型に対応するインスタンス変数を作成することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/3edd8721-eaa5-e5c9-fa5d-0dea78d21e8e.png)

上の例では、変数に昇格すると Integer 型の変数が追加されます。変数名は NewValue_0 のような適当な名前がつきます。名前を自分で変更すれば、その変数に関連するノードの名前も自動的に変更されます。

# 数値演算

## 加算

```sample.js
Counter = Counter + 1; // Counter ++; と同じ
```

```sample.cs
Counter = Counter + 1; // Counter ++; と同じ
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/21b958c4-c2b2-b7dd-60eb-fe3aba0e56b4.png)

変数間の加算もできます。

```sample.js
Counter += Val;
```

```sample.cs
Counter += Val;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/e1c1cc24-fc7a-bb87-f852-fce944b55fa8.png)

加算のノードを出すには、右クリックしてから＋または add と入力して検索します。加算のノードは、加算する変数の組み合わせによっていくつか種類が存在してます。Get Counter のノードから線を引き出してから検索すると、Get Counter の型 （Integer) を引数にもつ加算ノードだけが検索結果に出てくるので便利です。

```sample.js
Counter += Val + 2;
```

```sample.cs
Counter += Val + 2;
```

![ue05.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/058b1ab5-3a97-da1c-353a-26734c5a3447.gif)

「ピンを追加」を押すことで、加算する変数や数値の個数を増やすこともできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/d5139736-6b15-45cc-9dae-e309d5ebd3da.png)

追加したピンを削除したい場合は、ピンの上で右クリックして「ピンを削除」を選びます。

## 減算

```sample.js
Counter -= Val;
```

```sample.cs
Counter -= Val;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/fa4ff7c8-4dde-c559-37c5-34471dc9c325.png)

減算は「－」（ハイフン）または sub で検索できます。上側のピンの数値から、下側のピンの数値を引きます。徐算はピンの追加はできません。

## 積算

```sample.js
Counter *= Val;
```

```sample.cs
Counter *= Val;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/d76af4dd-158a-bf9f-86cd-8ca471dd6410.png)

積算は「＊」（アスタリスク）または mul で検索できます。積算もピンの追加ができます。

## 除算

```sample.js
Counter /= Val;
```

```sample.cs
Counter /= Val;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/fe56c5fd-d1c6-97b0-2e70-579bef5f4559.png)

徐算は「／」（スラッシュ）または div で検索できます。上のピンの値を下のピンで割ります。整数型の場合は、商の小数点以下は切り捨てられます。

0 で割ってもエラーにはならず、0 を結果として返すようです。 0/0 でも  0 を返してきます。

なお、徐算はピンの追加はできません。

## 剰余算

```sample.js
Counter %= Val; // Counter = Counter % Val;
```

```sample.cs
Counter %= Val;// Counter = Counter % Val;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/509e8ed8-f8be-de66-ade3-05ff17bef249.png)

剰余は「％」（パーセント）または mod で検索できます。上のピンの値を下のピンで割ったあまりを計算します。整数型でのみ使えます。剰余算もピンの追加はできません。

## 円周率

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/e01f883c-0516-6364-9464-fb6707c36651.png)

円周率は GetPi です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/6b59a830-975c-0596-b3ee-0056bc66b42b.png)

ノードの見掛けは上のような感じです。

## べき乗、四捨五入

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/976b1084-dc70-ee9b-6b7a-124d925414f8.png)

べき乗は Power、四捨五入は Round、小数点以下切り捨ては Floor です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/142571fa-613a-ceb6-0129-4c01c30a8cab.png)

平方根を得る sqrt というノードもあります。

## 三角関数

引数を Degree か Radian かで異なるノードになります。Sin, Cos, Tan, Asin, ACos, Atan があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/d08b23a7-589d-f9bc-c897-7fc1c2bdffc6.png)

ATAN だけは X,Y を別々に指定できる ATAN2 というノードがあります。また、なぜか ATAN は他の桟価格関数ノードと形状が違っています。（実用上の問題はありません、多分）

## 乱数

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/e9c3e756-cf10-17a1-a922-164d3409f814.png)

乱数は Random で検索できます。型や条件によってさまざまな種類があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/d8323663-5b85-0eb9-2f06-2058b7d7c4a0.png)

上の左は、0 以上 100 以下の実数の乱数を発生させます。右は 0 以上 100 以下の整数の乱数を発生させます。

乱数のノードから右にピンを複数引き出した場合、出力ピンごとに異なる数値が出力されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/bc98b1f6-f864-f7f5-ddc1-de51f6ba41f9.png)

乱数ノードから直接複数の線を出すのでない場合でも、たとえば上のよう感じで乱数の出力先のノードで複数に分岐している場合でも異なる値になります。上のプログラムを実行すると、二つの PrintText で異なる数字が表示されることがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/14e5dba9-161c-36fc-8bef-83808d0636a8.png)

乱数はわかっていても非常にバグりやすいので、多少冗長に見えても複数の線が出ないように、ノードを個々に分けたほうが安全だと思ってます。

## 対数、指数関数

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/59a2fa7e-d053-4d1c-ff57-061c29716f8a.png)

一般の対数は Log、自然対数は Loge、指数関数は Exp で検索できます。自然対数の底の値を得たいときは、Exp ノードの引数を 1 にして得ます。

ちなみに Log 0 を計算させてもエラーにならず、Float の負の最小値を返すようです。

## 算術演算の組み合わせ

計算順序を示すカッコに相当するノードはありません。

```sample.js
Counter = (1 + 2) * (3 + 4);
```

```sample.cs
Counter = (1 + 2) * (3 + 4);
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/453ca42d-cea6-307c-e08a-d81ae40c0f2c.png)

ノードを接続する順序で、演算する順序が決まります。

```sample.js
Counter = 1 + 2 * 3 + 4;
```

```sample.cs
Counter = 1 + 2 * 3 + 4;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/cd8e4277-2771-42bb-220c-4381ef4fa138.png)

他のプログラミング言語では書きにくい（変な？）計算式も書けます。

```sample.js
var tmp0 = Counter + Val;
var tmp1 = tmp0 + 1;
var tmp2 = tmp1 + tmp0;
Counter = tmp2 + tmp1;
```

```sample.cs
int tmp0 = Counter + Val;
int tmp1 = tmp0 + 1;
int tmp2 = tmp1 + tmp0;
Counter = tmp2 + tmp1;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/890d057f-aaff-00cd-34a3-a8dec39ee598.png)

このプログラムで、Val のデフォルト値を 0 にして Counter のデフォルト値を 1 にすると、5 が Counter に代入されます。javascript や C# で手続き的にこの計算式を計算しようとすると、上記のような一時変数が必要になりますが、ブループリントは演算の結果を変数にいれずとも再利用できるので、上記のような計算式の書き方も可能です。（嬉しいかは別として）

あくまで、このような書き方も可能だということであって、このように描くのを推奨するわけではありません。前述したように、値の評価は「白いノードが実行されるタイミングで決まる」ため、複雑な線の出し方をすると、予期しないバグが発生することがあります。上のほうに書いた乱数の例がいい例です。

# ベクトル関係の演算

Vector 型の変数に使える、さまざまな演算ノードがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/c95f61e0-6066-c4b6-69ec-c54beba2ebed.png)

上のほうに書いた算術演算を使わなくても、一発で計算できるノードがいろいろあります。ベクトル関係の計算をしたい場合は、ベクトル回りのノードを先に調べてみるといいかもしれません（丸投げ）。

# 条件分岐

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/a40b79d9-c47a-6c4e-e518-7909451fe5f0.png)

条件分岐には Branch （ブランチ）というノードを使います。他言語の IF 文に相当します。

```sample.js
if ( Val == 0 ){
   Counter = 0;
}else{
   Counter = 1;
}
```

```sample.cs
if ( Val == 0 ){
   Counter = 0;
}else{
   Counter = 1;
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/f36e522e-7ab5-8e09-8297-0172df2fa378.png)

ブランチの左側の赤いピンに、論理演算ノードの計算結果の Boolean の値を入れます。Boolean の値が true なら上のピンの先が実行され、false なら下のピンの先が実行されます。

# 論理演算

だいたい他の言語と同じような論理演算が使えます。

## 等しい

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/728793c8-ed39-2bd5-cd97-b07d2ed5f91b.png)

＝＝またはequalで検索できます。

```sample.js
if ( Val == 0 ){ ... }
```

```sample.cs
if ( Val == 0 ){ ... }
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/314214b2-3a47-6138-d157-2e064901bbc0.png)


## 不等号

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/c8c935f0-2393-a8df-5d79-6279a5583fc1.png)

＜やlessで検索できます。＞の場合は、＞またはgreaterで検索できます。

```sample.js
if ( Val < 0 ){ ... }
```

```sample.cs
if ( Val < 0 ){ ... }
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/23feca28-a592-530d-ddeb-b2382464a14a.png)

## 、不等号その２

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/f0bffde5-67af-aa9b-2b89-41ad9aa98176.png)

＝＜やlessで検索できます。＞＝の場合は、＞＝またはgreaterで検索できます。

```sample.js
if ( Val <= 0 ){ ... }
```

```sample.cs
if ( Val <= 0 ){ ... }
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/e8e7edc4-3576-4568-6595-50d75f2ed045.png)

## 不一致

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/80cc7835-eb70-6308-872a-ea6c46b060dd.png)

！＝または NotEqual で検索できます。

```sample.js
if ( Val != 0 ){ ... }
```

```sample.cs
if ( Val != 0 ){ ... }
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/cc54d63e-fec8-d518-7ae3-4e4e94f9efb1.png)

## 論理積（AND）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/c14d9813-529d-13bc-3af4-4f6b997d539d.png)

AND はピンが増やせます。

```sample.js
if ( Val >= 90 && Val <= 100 ){ ... }
```

```sample.cs
if ( Val >= 90 && Val <= 100 ){ ... }
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/b43436a2-3d39-0d40-6b21-888217754538.png)


## 論理和（OR）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/a7bc33b9-a9a0-455d-86f8-74303d3c7bdf.png)

OR もピンが増やせます。

```sample.js
if ( Val == 0 || Val == 10 ){ ... }
```

```sample.cs
if ( Val == 0 || Val == 10 ){ ... }
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/b696b7c2-c1c8-a87b-1a39-9c5b5dcc7d02.png)

## その他の論理演算ノード

NOT,NAND,NOR,XOR もあります。説明は省略します。

# switch-case 的な条件分岐

変数の値によって、処理内容を変更するような、いわゆる switch-case 文的な条件分岐も書けます。

![ue7.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/30a844e5-48aa-762c-ba88-71d8a901aff1.gif)

switch で検索することでノードを設置できます。ピンを増やすことで、入力が 0 の場合、1 の場合・・・というように条件を増やしていけます。ピンを増やした時の数字は 0, 1, 2, というように順番にしか増えないので、たとえば 0 と 100 の時だけ条件分岐したい、みたいなことは、このノードではやりにくいです（ピンを101個作ればできますが・・・）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/6e4d3e7f-d865-6627-c336-1ea10f3ec0ac.png)

このように、文字列の内容で分岐できる条件分岐ノードもあります。文字列を使った条件分岐ノードは、右側の「詳細」のところでマッチさせる文字列を指定できます。

# 型変換（キャスト）

型が異なる変数に値を代入するには、型変換をする必要があります。型の変換が自明なときは、型が違うピンにつないだときに、自動的に型変換のノードをエディタが挟んでくれます。

![ue06.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/69109ac2-65df-a17a-e7f6-e68402305119.gif)

上の例では、Text 型を引数にとる PrintText ノードの Text 型のピンに、Integer 型のピンを接続しています。接続した瞬間、Integer 型から Text 型に変換するノードが作られています。

というか、自明でない（自動で型変換してくれない）場合は自分で型を変換する関数を書いたりする必要がある場合がほとんどです。

なお、型変換のことを他言語では「（型）キャスト」と呼ぶことがありますが、ブループリントでキャストというと、オブジェクトの型をチェックする（C# や javascript の instanceof の強化版のような）機能のことを言うことが多いです。

# 続く

次回は繰り返し（ループ）、ブループリント特有の制御構文（ぽいもの）、配列あたりについて書く予定です。