【Unreal Engine】Blueprint変数入門:Class VariablesとLocal Variablesの正しい使い分け

作成: 2025-12-12最終更新: 2026-07-19

Blueprintの変数をClass VariableとLocal Variableのどちらで作るべきか、スコープと寿命の違いから図解。ループの累積バグを実際に起こして直す実践つき。

Blueprintを作り込んでいくと、Variablesパネルが変数でぎっしり埋まり、どれが大事な変数なのか分からなくなります。原因はたいてい、 一時的な計算結果まで全部Class Variableで作ってしまう ことです。

UEのBlueprintには、寿命と届く範囲が違う2種類の変数、Class VariableとLocal Variableがあります。使い分けの軸はたった1つ、 「状態か、途中計算か」 です。この記事では、2つの変数の違いと、「関数を2回呼んだら値が2倍になる」バグをわざと起こして直す手順を解説します。

大きなバックパックと小さな付箋を持つ人形。2種類の変数のイメージ

この記事でわかること

  • 2種類の変数の違いは 「スコープ(届く範囲)」と「寿命」
  • 使い分けの軸は 「状態はClass、途中計算はLocal」
  • Local Variableは Function内でのみ 作れる(イベントグラフでは不可)
  • 実践:ループの累積で 「2回呼ぶと2倍」バグ をわざと起こして直す

Sponsored

2種類の変数:スコープと寿命の違い

Blueprintの変数は、作る場所によって性質がまったく変わります。

  1. Class Variables(クラス変数/メンバ変数): My Blueprintパネルの「Variables」セクションで作る、いつもの変数
  2. Local Variables(ローカル変数): Function(関数)の中でだけ 作れる変数。関数を開いているときだけ、My Blueprintパネルに「Local Variables」セクションが現れます

違いは2つの軸で整理できます。1つ目は スコープ(どこから届くか)

Class Variableはどの処理からも届き、Local Variableは関数の中だけ。届く範囲は、狭いほど安全
Class VariableLocal Variable
スコープBlueprint内のすべての関数・イベントから読み書き可(Public設定なら外部からも)定義した関数の中だけ。外からは一切見えない
寿命インスタンスの生成から破棄まで関数の開始から終了まで
主な用途オブジェクトの 状態 ・設定値・参照一時的な 計算結果 ・中間データ

2つ目は 寿命(いつまで生きるか) です。

Class Variableはスポーンから破棄まで生き続け、Local Variableは関数の実行中だけ現れて消える

Class Variableはアクターが生きている限り値を持ち続けます。一方のLocal Variableは関数が呼ばれた瞬間に生まれ、関数が終わると跡形もなく消えます。この「すぐ消える」性質が、後述するバグ予防の要になります。

重要な補足: Local VariableはFunction内でのみ定義できます。 イベントグラフでは作れません 。イベントグラフで一時的な値を持ちたくなったら、それは処理をFunctionに切り出すサインです(→ FunctionとMacroの違い)。

Sponsored

使い分けの原則:状態はClass、途中計算はLocal

判断の原則は 「スコープの最小化」 です。変数が届く範囲は、狭ければ狭いほど安全になります。

状態・設定(体力・フラグ・設定値)はClass Variable、途中の計算はLocal Variable

Class Variableにすべきもの:オブジェクトの「状態」

プレイヤーの CurrentHPMaxHPIsDead を考えてみてください。ダメージイベントで減り、回復関数で増え、UI更新から読まれる——つまり 複数の処理から参照・更新される「いまの状態」 です。これはClass Variableの出番です。

Event ReceiveDamage
  → CurrentHP(Class Variable)から Damage を引いて Set
  → CurrentHP <= 0 なら → IsDead(Class Variable)を True に Set

Local Variableにすべきもの:関数内で完結する「途中計算」

一方、ダメージ計算関数の中で使う「基礎ダメージ×バフ倍率の中間結果」はどうでしょう。この値が必要なのは、計算している 数ミリ秒の間だけ です。関数の外の誰も、この値を知る必要がありません。これがLocal Variableの出番です。

Function: CalculateFinalDamage(Return Value: Float)
  → BaseDamage × BuffMultiplier の結果を Local Variable: IntermediateDamage に Set
  → IntermediateDamage × CriticalMultiplier を Return Value として返す

関数が終われば IntermediateDamage は消え去り、Variablesパネルを汚すことも、他の処理に影響することもありません。

Sponsored

全部Class Variableにすると何が起きるか

初心者が最も踏みやすい地雷が、「一時的な計算結果まで全部Class Variableにする」ことです。起きる問題は、大きく3つあります。

  • 変数リストの肥大化: 本当に大事な状態変数が、使い捨ての変数の山に埋もれます
  • デバッグの迷宮化: どこからでも書き換えられる変数は、「なぜこの値が変わったんだ?」の容疑者が全処理になります。Local Variableなら容疑者はその関数の中だけなので、捜査範囲が一気に絞れます(→ Print Stringデバッグ手法
  • 値の残留バグ: 最大の罠がこれです。Class Variableは 前回の値を覚えています 。次の実践で、実際に踏んでみましょう
Sponsored

実践:「2回呼ぶと2倍」バグをわざと起こして直す

RPGの合計スコア、シューティングのコンボ集計、インベントリの合計重量——「配列をループで回して合計する」処理はどのジャンルにも登場します。そしてこの処理は、変数の選び方を間違えたときの症状がいちばん分かりやすい教材でもあります。今回は わざと間違えて、バグを目撃してから直します

1回目の呼び出しは300で正しいが、2回目は600に。Class変数には前回の値が残っている

再現用の準備。適当なActor Blueprint(BP_ScoreTester など)に、次の変数を用意します。

変数名初期値置き場所
ScoreArrayInteger配列100, 100, 100Variablesパネル(Class Variable)
TotalScoreInteger0Variablesパネル(=これがわざと間違えた置き場所)
  1. わざと間違えた関数を作る: Function CalculateTotalScore(戻り値: Total / Integer)を作り、中身をこう組みます

    Function: CalculateTotalScore(戻り値: Total / Integer)
      → For Each Loop(Array: ScoreArray)
          Loop Body → Set TotalScore(= Add(A: TotalScore, B: Array Element))
          Completed → Return Node(Total ← TotalScore)
    
  2. 2回呼んで観察する: イベントグラフで、続けて2回呼びます

    Event BeginPlay
      → CalculateTotalScore → Print String(Append("1回目: ", ToString(Total)))
      → CalculateTotalScore → Print String(Append("2回目: ", ToString(Total)))
    

    Playすると、1回目: 300 と表示されます。正解です。ところが 2回目: 600 。配列は1つも変わっていないのに、合計が2倍になりました

  3. 犯人を言葉にする: TotalScore はClass Variableなので、1回目の300が 関数が終わっても生き残り 、2回目の加算がその上に積まれました

  4. 直す: TotalScore をVariablesパネルから 削除 し、CalculateTotalScore を開いた状態でMy Blueprintパネルの Local VariablesRunningTotal(Integer)を作り直します。中身は置き換えるだけです

    Function: CalculateTotalScore(戻り値: Total / Integer)
      → For Each Loop(Array: ScoreArray)
          Loop Body → Set RunningTotal(= Add(A: RunningTotal, B: Array Element))  ← Localに変更
          Completed → Return Node(Total ← RunningTotal)
    

    Playすると、1回目: 300 / 2回目: 300 。何回呼んでも300です。Local Variableは呼び出しのたびに まっさらな0から 始まるからです

    グラフとして変わったのは、変数の置き場所だけです。それだけで結果が変わります。

    不具合版(Class変数で2回目600)と修正版(Local変数で2回目300)を左右に並べたノードグラフ比較
Localは毎回まっさらなメモ、Classは前回の数字が残るメモ。ループの合計は、まっさらなメモで

「初期化ノードを足せばClass Variableでも直るのでは?」と思った方もいるはずです。そのとおりで、関数の先頭で0をSetすれば動きます。ただしそれは、「毎回リセットが必要な変数」を自分で管理し続けるということでもあります。 Local Variableなら、リセットは仕組みの側が保証してくれます 。人間の注意力より仕組みに頼るのが、バグの少ないBlueprintへの近道です。

ポイントは2つです。

  • 「関数が終わった後もこの値は必要か?」と自問する: Noなら迷わずLocal。この一問だけで変数の9割は正しく仕分けられます
  • 症状から犯人を推理できるようになる: 「2回目から値がおかしい」「リトライしたら前回の状態が残っていた」——この症状を見たら、Class Variableの残留をまず疑う。この嗅覚は今後ずっと役立ちます

おまけ:先に知っておくと良いこと

  • 関数のInput/Outputピンも仲間: 関数に値を渡すならInputピン、返すならReturnノードを使います。「引数と戻り値で受け渡す」形は、Local Variableすら不要になる最もクリーンな書き方です。Local Variableは「関数の中で何度も使い回す中間値」に絞ると美しく収まります
  • Class Variableには整理機能がある: 変数が増えてきたら、詳細パネルの Category でグループ分けできます。StatsConfig のように分類しておくと、Variablesパネルが読みやすくなります
  • インスタンスごとに値を変えたいなら: Class Variableの Instance Editable をONにすると、レベルに置いた個体ごとに詳細パネルで値を変えられます。「同じ敵Blueprintで、この個体だけHPを高く」が実現できます

まとめ:変数選択のチェックリスト

質問YESなら
オブジェクトの状態・設定を保持する?(HP、フラグ、参照)Class Variable
複数の関数・イベントから参照される?Class Variable
処理が終わった後も値が必要?Class Variable
1つの関数の中だけで使う一時データ?Local Variable
処理が終わったら捨てて良い?Local Variable

合言葉は 「状態(ステート)はClass Variable、過程(プロセス)はLocal Variable」 。変数を1つ作るたびにこの仕分けを意識するだけで、Blueprintの読みやすさとバグ耐性は目に見えて変わります。

変数の次は、処理のまとめ方です。FunctionとMacroの違いで「処理を関数に切り出す」技術を、Blueprintグラフを整理する10のテクニックでグラフ全体の整頓術を身につけましょう。

あなたのBlueprintのVariablesパネルを、今スクロールしてみてください。「関数が終わったら要らない値」が、何個まぎれていますか?