BlueprintのVariablesパネルに、HP、移動速度、計算途中の合計値が並んでいる。変数が増えると、「このActorが覚えておく値」と「一度の計算にしか使わない値」を見分けにくくなります。
この2つを分けるのが、Class VariableとLocal Variable です。HPのように次の処理へ残したい値はClass、関数の中だけで使う途中計算はLocal。どちらも値を入れる変数ですが、使える範囲と、値を持ち越す期間が違います。
今回はその違いを確かめるために、同じ合計計算を2回呼びます。配列を変えていないのに300→600になる不具合を起こし、300→300へ直してみましょう。
この記事でわかること
- Class VariableとLocal Variableを作る場所
- 「どこから使えるか」と「いつまで値が残るか」の違い
- 状態と途中計算を分ける考え方
- 同じ集計を2回呼び、前回の値が残る不具合を直す方法
2種類の変数:スコープと寿命の違い
Class Variables は、My Blueprintパネルの「Variables」で作る変数です。普段使っているHPや移動速度の変数が、これに当たります。Local Variables は、関数を開いたときに現れる「Local Variables」で作ります。その関数の中だけで使う変数です。
まず押さえたいのは、Class Variableも、Actorごとに別々の値を持つ という点です。同じ敵Blueprintから敵Aと敵Bを作っても、敵Aが攻撃されたからといって敵BのHPまで減るわけではありません。
このように、Blueprintから実際に作った1個のActorなどを インスタンス と呼びます。ここでのClass Variableは「メンバ変数」という意味で、クラスの全個体が共有するstatic変数の意味ではありません。
どこから使えるか:スコープ
スコープ は、その変数を直接読み書きできる範囲です。敵AのHPなら、敵Aのダメージ処理も回復処理も同じ値を使います。一方、ダメージ計算関数に作ったLocal Variableは、その関数だけが使いま す。

| 比べること | Class Variable | Local Variable |
|---|---|---|
| 同じBlueprint内で使える場所 | 複数の関数・イベント | 作成した関数の中 |
| 関数の呼び出しが終わった後 | そのインスタンスに値が残る | 次回へ途中の値を持ち越さない |
| 向いている値 | HP、移動速度、現在の装備など | 合計途中の値、計算中の一時データなど |
別のActorからClass Variableを扱う場合は、相手を指定する参照や、外からアクセスできる設定も関係します。「どのActorからでも無条件に使える」という意味ではありません。今回は1個のActorの中で比べます。
いつまで値が残るか:寿命

Class Variableは、Actorが存在する間、前の処理で入れた値を覚えています。ダメージを受けてHPが80にな ったら、次の回復処理も80から始められます。
Local Variableは、関数を呼ぶたびに既定値から始まります。 既定値は、その変数に設定しておく開始時の値です。合計用のInteger変数を既定値0にすれば、毎回0から計算できます。前の呼び出しで300になっていても、その300は次回へ持ち越しません。
なお、Class Variableの値が残るのは、そのインスタンスがある間です。ゲームを終了した後も残す保存データとは別です。
使い分けの基本:状態はClass、途中計算はLocal
「この処理が終わった後も、次の処理でこの値を使いたいか」を考えると、置き場所を決めやすくなります。

HPのように覚えておく値はClass
プレイヤーの CurrentHP は、攻撃で減り、回復で増え、画面のHPバーにも使われます。処理のたびに最初の値へ戻ってしまうと困るので、Class Variableへ置きます。
現在のHPだけでなく、最大HPや移動速度などの設定、装備中の武器を指定する参照も、Actorが覚えておく値です。
合計途中の値はLocal
例えば、リザルト画面に出す合計点を計算する関数では、100点、100点、100点を順に足します。途中の100や200は、計算中にだけ必要です。次に同じ集計を始めるときは、また0から足したいところです。
この合計途中の値をLocal Variableにします。最後の300は、関数の 戻り値 として呼び出した側へ渡せます。戻り値は「この処理の結果です」と返す値で、関数の中にある変数を外から直接読む必要はありません。
全部Class Variableにすると困ること
Class Variableで途中計算を持つこと自体が、必ず不具合になるわけではありません。ただ、次のような管理が必要になります。
- 毎回の開始値を揃える。 前の合計が残っているなら、計算前に0へ戻す。
- どの処理が書き換えたかを追う。 同じ変数を別の関数でも使うと、値が変わった原因を調べる範囲が広がる。
- 状態と途中計算を見分ける。 Variablesが増えても、HPなどの主要な値を探せるように整理する。
関数の中に閉じた計算なら、Local Variableにすることで、調べる場所もその関数に絞れます。次の実践では、最初の「前の合計が残る」を実際に確認します。

実践:2回目の合計が600になる不具合を直す
同じ敵を3体倒し、それぞれ100点を得たとして、合計を求めます。1回計算しても、もう一度計算しても、正解は300点です。

① 集計用のActorと変数を用意する
Blueprint Classの親にActorを選び、BP_ScoreTester を作ります。レベルへ 1個だけ配置 してください。今回は見た目がないActorなので、Outlinerで配置したことを確認します。
My BlueprintのVariablesに、次の2つを作ります。Integerは整数を扱う型です。
| 変数名 | 型 | 既定値 | 置き場所 |
|---|---|---|---|
ScoreArray | IntegerのArray | 100、100、100 | Variables |
TotalScore | Integer | 0 | Variables |
Array(配列) は、同じ型の値を順番に並べたものです。ScoreArrayの型をIntegerにし、型の隣にあるコンテナ選択でArrayを選びます。Compile後、既定値欄の「+」で要素を3つ追加し、すべて100にします(→ Array・Set・Map入門)。
② 前回の値が残る関数を作る
Functionsの「+」で CalculateTotalScore を作ります。DetailsのOutputsに、名前が Total、型がIntegerの出力を追加します。今回は白い実行線で2回の順番を指定するため、関数の「Pure」はオフにします。
関数の中へ For Each Loop を置きます。これは配列の要素を1つずつ取り出すノードです。Loop Bodyは要素ごとの処理、Completedはすべて終えた後の処理 に使います。
次の順で組みます。変数をグラフへドラッグするとき、Getは値を読むノード、Setは値を書き換えるノードです。
- 関数の入口の白い実行出力を、For Each Loopの実行入力へつなぐ。ArrayにはGet ScoreArrayをつなぐ。
- Integerの
+ノードを置き、AへFor Each LoopのArray Element、BへGet TotalScoreをつなぐ。 +の結果をSet TotalScoreの値入力へつなぐ。Loop Bodyの白い線もSet TotalScoreへつなぐ。- Completedの白い線をReturn Nodeへつなぐ。Return NodeのTotalには、別に置いたGet TotalScoreをつなぐ。
Set TotalScoreの白い出力はつながず、ループへ処理を返します。SetからReturn Nodeへつなぐと、1個目を足したところで関数が終わります。 合計を返すのはCompleted側です。

実行順と加算を2枚に分けています。上の図で省略したFor Each LoopのArray Elementは、下の図の加算へつなぎます。「Array Element」という別ノ ードを作るのではなく、ループが出す値のピンを使います。

③ 同じ関数を続けて2回呼ぶ
Event GraphのEvent BeginPlayから、CalculateTotalScoreとPrint Stringを交互に2つずつ置き、白い線を次の順につなぎます。
Event BeginPlay
→ CalculateTotalScore(1回目)→ Print String(1回目の結果)
→ CalculateTotalScore(2回目)→ Print String(2回目の結果)
1つ目の関数のTotal出力は、1つ目のPrint String用に渡します。Append のAに 1回目: 、BにTotalをStringへ変換した値を入れ、Appendの結果をIn Stringへつなぎます。IntegerからStringへの変換は、ピンをつないだときに変換ノードが入ります。2つ目も同様に、2回目: と2つ目のTotalを使います。
Print StringのDurationを10秒にし、Compile・保存してPlayします。1回目: 300 と 2回目: 600 が出れば、不具合を再現できました。画面では新しいメッセージが上へ出ることがあるので、上下ではなく「1回目」「2回目」のラベルで読みます(→ Print Stringの使い方)。
TotalScoreはClass Variableなので、1回目に入れた300が残っています。2回目は、その300へさらに100を3回足すため、600になります。配列が増えたわけではありません。
④ 合計途中の値をLocalへ移す
Playを止め、CalculateTotalScoreを開きます。My Blueprintの Local Variables に RunningTotal をIntegerで作り、Compile後に既定値を0にします。
関数内のSet TotalScoreをSet RunningTotalへ、2つのGet TotalScoreをGet RunningTotalへ置き換えます。ScoreArray、加算、ループ、Return Nodeの接続先は同じです。使わなくなったTotalScoreは、ノードの置き換えを終えてからVariablesから削除します。
Compile・保存してもう一度Playすると、1回目: 300、2回目: 300 になります。RunningTotalは呼び出しごとに既定値0から始まるため、前回の合計を引き継ぎません。

最後にScoreArrayを100、200、300へ変えてみます。両方の呼び出しが600になれば、決め打ちの300を表示しているのではなく、その都度配列から集計できています。
Class Variableを0へ戻しても直る?
はい。元の関数の先頭にSet TotalScore=0を置いても、毎回300を返せます。今回は合計途中の値をほかの処理が使わないため、この関数の計算用だと分かるLocal Variable を選びました。
大切なのはClassを避けることではなく、値を残す必要に合わせて置き場所を決めることです。集計した最終結果を後で使いたければ、呼び出し側で戻り値をClass Variableへ保存することもできます。
おまけ:先に知っておくと良いこと
Event Graphで途中計算をしたいときは
今回使った名前付きのLocal Variablesは、関数を開いて作ります。Event Graphには同じ欄がありません。処理がまとまってきたら、関数に切り出す方法を検討します。
ただし、値を足してすぐ次のピンへ渡すだけなら、変数を作らなくても計算できます。「途中計算だから必ずLocalを追加する」と考える必要はありません(→ FunctionとMacroの違い)。
同じ敵でも、1体だけHPを高くする
Class Variableの「Instance Editable」をオンにすると、レベルに配置した個体のDetailsで値を変えられます。敵AだけMaxHPを200、敵Bは100という設定ができます。これは、レベル上で個体ごとに値を編集できる設定です。
変数が増えたら用途ごとにまとめる
変数のDetailsにあるCategoryへ Stats や Config を指定すると、My Blueprint内で分類できます。ClassとLocalを分けたうえで、状態や設定の変数にもまとまりを付けると探しやすくなります。
まとめ:変数を作る前に考えること
| 今回の値は何に使う? | 選び方 |
|---|---|
| HPや装備など、次の処理にも覚えておきたい | Class Variable |
| 1つの関数を実行してい る間だけ使う合計途中の値 | Local Variable |
| 計算した結果を呼び出し側へ渡したい | 関数のOutputとReturn Node |
| 計算してすぐ次へ渡すだけ | ピンを直接つなげば変数が不要な場合もある |
Class Variableは状態を覚え、Local Variableはその関数の計算を支えます。今回の300→600のように、2回目から結果が変わるときは、計算の開始時にどの値が残っているかを確認してみてください。
処理のまとめ方はFunctionとMacroの違い、グラフ全体の整理はBlueprintを整理する10のテクニックで扱います。