【Unreal Engine】EnumとSwitchで状態を管理する:Blueprintのステートマシン入門

作成: 2026-07-20最終更新: 2026-09-05

鍵が掛かっている、開けられる、開いている途中、開き終わった。宝箱の4状態をEnumで表し、Switchで操作を分けます。連打しても開き直さず、途中でリセットしたら動きも止まる仕組みを作り、状態の変更と後始末の関係を確かめます。

宝箱に鍵を付け、開く動きも加えた。すると、開いている途中でキーを連打したら動きが最初に戻ったり、リセットしたはずの箱が少し後にまた開いたりすることがあります。「今どんな状態か」と「その状態で何を受け付けるか」が、別々の場所に散らばると起きやすい問題です。

Enum を使うと、宝箱の状態を「施錠中」「解錠済み」「開いている途中」「開き終わった」のどれか1つで表せます。Switch は、その値に応じて処理の行き先を分けるノードです。この記事では小さな宝箱を作り、状態を切り替えるだけでなく、途中でやめるときの動作まで揃えます。

宝箱のLocked・Closed・Opening・Openの4状態から、CurrentStateがOpeningの1つを持つイメージ

この記事でわかること

  • BooleanとEnumを、何を表したいかで使い分ける考え方
  • Enumの作成と、Switchで状態ごとに処理を分ける手順
  • 状態変更の入口をまとめ、動きの停止と開始を揃える方法
  • 連打と途中リセットで、状態管理の効果を確かめる実践

Sponsored

Enumは「今どれか1つ」を表す

Boolean(bool) は、trueかfalseかの2択を表します。「効果音を鳴らすか」のようなオン・オフに使いやすい型です。

一方、今回の宝箱には4つの状態を用意します。

状態意味開く操作をしたら
Locked鍵が掛かっている開かない
Closed鍵は外れているが、ふたは閉じている開き始める
Openingふたが動いている途中今の動きを続ける
Open開き終わっているそのまま

ここでのClosedは「閉じている物すべて」ではなく、解錠済みで開けられる状態 です。Lockedと見た目が同じでも、受け付ける操作が違います。

これを IsLockedIsOpeningIsOpen という別々のBooleanで持つこともできます。ただし、1つをtrueへ変えるときに、ほかをfalseへ戻す必要が出てきます。戻し忘れると、この宝箱のルールでは使わない「施錠中なのに開いている途中」という組み合わせも保存できてしまいます。

Enum(列挙型) は、決めておいた選択肢の中から1つの値を持つ型です。CurrentState という変数をEnum型にすれば、4つの状態から1つを持ち、LockedとOpeningが同時に入ることはありません。複数の旗を揃えて書き換える手間を減らせます。

Booleanを3つ持つと施錠中なのに開いている途中という組み合わせも作れてしまうが、Enumなら必ずどれか1つになる

ただし、Enumは状態の名前を持つだけです。ふたを動かす処理や、鍵が掛かっている間は開けない判定まで自動で作られるわけではありません。そこをSwitchと、自分で作る処理でつないでいきます。

移動しながら攻撃できるゲームなら、「移動中」と「攻撃中」は同時に成立して構いません。何でも1つのEnumへ押し込むのではなく、同じ観点で、今どれか1つに決めたいものをまとめる と考えてください。

実践の準備:4つの状態を持つ宝箱

Third PersonのBlueprintプロジェクトを使います。新規作成時に「Variant」がある版では None を選びます。変数と関数を作り、ピンをつなぐ操作が分かれば進められます。

練習用の宝箱は、Cubeを本体とふたに見立てて作ります。蝶番で回す形ではなく、ふたが2秒かけて真上へ100cm持ち上がる形です。状態と動きの関係を見やすくするため、形はシンプルにしています。

  • F:鍵を外す
  • E:開ける。開いている途中なら、動きをやり直さない
  • R:途中でも動きを止め、施錠した閉じた箱へ戻す
Fで解錠し、Eでふたを2秒かけて100cm上げ、Rで途中でも施錠した閉じた状態へ戻す完成イメージ

本体とふたを置く

  1. Actorを親にBlueprint Class BP_StateChest を作ります。
  2. Static Meshコンポーネントを2つ加え、BodyLid と名付けます。どちらも DefaultSceneRoot の子にします。
  3. 両方へ標準のCube(Engine/BasicShapes)を割り当てます。見つからなければ、アセット選択欄でエンジンコンテンツの表示をオンにします。
  4. 次の表に合わせ、回転は両方とも0にします。「Mobility」はMovable、「Simulate Physics」はオフ、「Collision Presets」はNoCollisionです。

Movableは、ゲーム中に位置などを変えられる設定です。今回はふたをBlueprintから動かします。

コンポーネントRelative LocationScale
BodyX=0 / Y=0 / Z=50X=2 / Y=1.5 / Z=1
LidX=0 / Y=0 / Z=110X=2 / Y=1.5 / Z=0.2

Relative Location は、親を基準にした位置です。ここでは箱のRootから測った位置で、Bodyの底がRootの高さに、Lidの底がBodyの上面に揃います。

BP_StateChestをレベルへ1つ置き、Actor自体のScaleは 1, 1, 1、Rootの高さは床に合わせます。プレイヤーの開始位置から見える場所へ置いてください。今回はキーで動きを試すので、接触判定は使いません。

Enumを作り、変数の型にする

コンテンツブラウザで右クリックし、「Blueprints」→「Enumeration」を選びます。E_ChestState と名付けて開き、「Add Enumerator」で次の4項目を作ります。

Display NameDescriptionに書く説明の例
Locked施錠中。開く操作は受け付けない
Closed解錠済み。開く操作を受け付ける
Openingふたが開いている途中
Open開き終わった

Display Name は、変数の選択欄やSwitchのピンに出る名前です。Descriptionは、後から意味を思い出すための説明に使えます。今回の名前は表に揃え、保存します。

BP_StateChestへ CurrentState 変数を作ります。型の検索欄で E_ChestState を選び、コンパイル後、既定値を Locked にします。Enumアセットが「選択肢の一覧」、変数が「この箱が今選んでいる値」という関係です。

4項目を持つE_ChestStateアセットと、それを型に持つCurrentState変数の関係

Switchで状態に合った処理を呼ぶ

まずは、状態ごとに文字が出るところまで作ります。BP_StateChestに EnterChestState という関数を追加し、「Pure」はオフにします。入力 State を加え、型をE_ChestStateにします。戻り値は使いません。

Pureをオフにするのは、白い実行ピンで呼び、表示や位置の変更をする関数にするためです。

この関数は、指定した状態に入ったときの処理 をまとめる場所です。現段階では表示だけを置き、後でふたの動きを加えます。

  1. 関数の入口にあるStateの出力から線を引き、Switch を検索して Switch on E_ChestState を作ります。Stateをその Selection へつなぎます。
  2. 関数入口の白い実行出力もSwitchの白い入力へつなぎます。
  3. SwitchのLocked・Closed・Opening・Openから、それぞれ別の Print String を呼びます。
  4. 表示文字はピンと同じ名前にします。4つとも「Print to Screen」をオン、Durationを 5 にします。
EnterChestStateの入力StateをSelectionへ渡し、4つの出口から同じ名前のPrint Stringを呼ぶ接続

Switchは、白い実行線が来た時点のSelectionを読み、一致する出口へ進みます。Enumの値をどこかで変更しただけでは、このSwitchは実行されません。

イベントグラフへ戻り、Event BeginPlay → EnterChestState をつなぎます。呼び出しのStateへ Get CurrentState を渡します。コンパイルしてPlayすると Locked が表示されれば、最初の分岐はできています。

Playを止め、CurrentStateの既定値をClosedへ変えて再開すると、今度は Closed が出ます。試したらLockedへ戻します。この段階ではPrintだけなので、箱の見た目は変わりません。

状態を変える前に、今の動きを止める

これから「開く」「リセットする」といった操作を加えます。その前に、状態の変更をどこへ書くかを決めておきましょう。

たとえば、開いている途中でCurrentStateをLockedに変え、ふたを閉じた位置へ戻すだけでは不十分です。ふたを動かしている処理が残っていれば、次の更新でまた上へ動かされます。

そこで、状態変更は ChangeChestState という関数へまとめ、次の順を通します。

  1. 同じ状態が指定されたら、そのまま終える
  2. 今のふたの動きを止める
  3. CurrentStateを新しい値へ変える
  4. EnterChestStateで、新しい状態の表示と動作を始める
開いている動作を止め、CurrentStateをLockedへ更新してから、新しい状態の処理を呼ぶ順序の概念図

このように、現在の状態と、次の状態へ移るルールを組み合わせたもの が、ここで作るステートマシンです。「状態遷移」は、ClosedからOpeningへ移る、といった状態の切り替わりを指します。

同じ状態を指定したときに終えるのは、Opening中の「もう一度Openingにして」という要求で、動きを最初から始め直さないためです。これだけで、すべての遷移を許可・禁止できるわけではありません。施錠中に開けない条件は、後で操作側へ書きます。

Sponsored

実践:ふたの動きと操作をつなぐ

1. 2秒で0から1になるTimelineを作る

Timeline は、時間に合わせて値を変える仕組みです。今回は2秒間で0から1へ増える値を作り、ふたがどこまで開いたかに使います。

BP_StateChestのイベントグラフで右クリックし、Add Timeline を選んで TL_Open と名付けます。ダブルクリックして開き、Float Trackを追加して Alpha と名付けます。

Float Trackのグラフを右クリックしてキーを2つ追加し、それぞれ選んでTimeとValueを揃えます。キー は「この時刻には、この値にする」という目印です。

キーTimeValue
始まり00
終わり21

キーを選んで右クリックし、補間をLinearにします。これは、キーとキーの間で値を一定のペースで変える設定です。Lengthは 2、AutoPlayとLoopはオフにします。Alpha は今回「どこまで進んだか」を表す値で、0なら始まり、0.5なら半分、1なら終わりです。

イベントグラフへ戻ります。このTimelineノードは、後で使うためそのまま置いておきます。Timeline本体は関数の中へ移しません。 再生を始めた後も、時間をかけて更新する部分だからです。

2. 状態変更用の関数を組む

関数 ChangeChestState を作り、Pureをオフにします。入力は NewState、型はE_ChestStateです。

  1. Get CurrentStateから == を検索し、Enumの比較を作ります。もう片方の値へ、関数入力のNewStateを渡します。
  2. 関数入口の白い出力をBranchへ、比較結果をConditionへつなぎます。
  3. Trueは空けます。同じ状態なので、ここで終わります。
  4. Falseから StopSet CurrentStateEnterChestState の順につなぎます。
  5. Set CurrentStateの値と、EnterChestStateのStateには、どちらもNewStateを渡します。
CurrentStateとNewStateを比較し、同じならTrueで終わり、違うときだ��けFalse側へ進める関数の前半

ここで使うStopは Timeline ComponentのStop です。「マイブループリント」にあるTL_OpenをグラフへGetで取り出し、その青いピンからStopを検索してください。TargetがTL_Openになったノードを使います。

BranchのFalse側から、TL_OpenをTargetにしたStopを呼ぶ接続

Timeline本体と、その再生を操作するノードは別です。関数の中では、このようにTimelineを指定して「止める」「最初から再生する」という指示を出せます。

Stopの白い出力からは、次の順につなぎます。図のNewStateには、この関数の入力を使います。新しいメンバー変数を作る必要はありません。

Stopの後でCurrentStateへNewStateを保存し、Enter Chest StateのStateにも同じ入力値を渡す接続

今後、CurrentStateを書き換えるSetノードは、この関数の1つへまとめます。既定値のLockedは、開始前の設定として使います。

3. 開いている途中の位置を更新する

TL_Openのあるイベントグラフで、Floatの Lerp を追加します。Lerpは、2つの値の間をAlphaに応じて選ぶノード です。

Aを 110、Bを 210 にし、AlphaへTimelineのAlphaをつなぎます。今回は閉じたふたの高さ110から、開いた高さ210までを動きます。Alphaが0.5なら、途中の160になります。

Timelineの0秒・1秒・2秒でAlphaが0・0.5・1となり、ふたの中心のZが110・160・210へ変わる関係

次に、コンポーネント一覧のLidをグラフへドラッグし、その青い出力から Set Relative Location を作ります。

  • 白い入力:TL_Openの Update
  • Target:Lid
  • New Location:X=0、Y=0、ZにLerpの結果
  • Sweep:オフ

New LocationのVectorピンを右クリックし、「Split Struct Pin」でX・Y・Zへ分けると、Zへだけ数値をつなげられます。Update はTimelineが値を更新したときの出口です。ここから位置を変えるので、ふたが少しずつ上がります。

TimelineのUpdateでLidの位置を設定し、Alphaから計算したLerpの値をNew LocationのZへ渡す接続

TL_Openの Finished からは、作成したChangeChestStateを呼び、NewStateを Open にします。これは2秒の再生が終わったときの切り替えです。

4. EnterChestStateへ動作を足す

先ほど作ったEnterChestStateへ戻ります。4つのPrint Stringの後ろへ、次の処理を加えます。SelectionやPrintの接続は、そのまま使います。

Switchの出口Printの後にすること
LockedSet Relative Location:Lidを 0, 0, 110
ClosedSet Relative Location:Lidを 0, 0, 110
OpeningTL_OpenをTargetにして Play from Start
OpenSet Relative Location:Lidを 0, 0, 210
EnterChestStateでOpeningと表示した後にTL_Openを再生し、LockedではLidを閉じた高さ110へ戻す接続例

図のPrint Stringは、先ほどSwitchにつないだものです。その後ろへ動作を足します。ClosedとOpenのPrintの後にも、それぞれ表の位置を設定するノードを置いてください。

位置を変える3つのノードは、すべてTargetをLid、Sweepをオフにします。OpeningのPlay from Startは、TL_OpenのGetから青い線を引いて検索します。途中から続けるPlayではなく、時刻0から始めるPlay from Start を選びます。

BeginPlayから呼んでいるEnterChestStateも残します。CurrentStateの既定値はすでにLockedなので、BeginPlayでChangeChestState(Locked)を呼ぶと「同じ状態」の判定で終わってしまいます。最初の表示と位置合わせは、EnterChestStateを直接呼ぶ 形にします。

5. 開く操作と解錠を分ける

BP_StateChestに、Pureオフ・入力なしの関数を2つ作ります。

UseChest は、開く操作を受け取る関数です。入口の白い実行線をSwitch on E_ChestStateへ、Get CurrentStateをSelectionへつなぎます。

出口処理
LockedPrint Stringで Locked と表示
ClosedChangeChestStateを呼び、NewStateを Opening にする
OpeningPrint Stringで Opening と表示
OpenPrint Stringで Open と表示
UseChestが現在の状態で分岐し、ClosedだけOpeningへの変更を呼び、ほかの状態は文字の表示で終える接続

ここでもPrintのDurationは5、Print to Screenはオンにします。Opening側からChangeChestStateを呼ばないので、開いている途中の連打では表示だけが増え、ふたの動きは続きます。

UnlockChest は、鍵を外す関数です。Get CurrentStateとLockedを == で比べ、BranchのConditionへ渡します。関数入口の白い線をBranchへつなぎ、TrueからChangeChestStateを呼んでNewStateをClosedにします。Falseは空けます。

UnlockChestで現在の状態がLockedかを調べ、TrueのときだけClosedへの状態変更を呼ぶ接続

これで、すでに開いている箱にFを押してもClosedへ戻らなくなります。Enumで状態を表すことと、その操作を許す条件を書くことが、別の役割だと分かります。

6. 配置した箱をキーで操作する

BP_StateChestをコンパイルして保存します。レベルに置いた箱を選び、ツールバーからLevel Blueprintを開きます。グラフを右クリックして、選択中のBP_StateChestへの参照を作ります。

参照 は、このレベルに置いた「その箱」を指定するためのものです。その青いピンから、作成した関数を呼び出します。

キーボードイベントのPressed呼ぶ関数入力
FUnlockChestTargetは配置した箱
EUseChestTargetは配置した箱
RChangeChestStateTargetは配置した箱、NewStateはLocked
Level BlueprintのRのPressedから、配置した箱をTargetにしてChange Chest StateでLockedを指定する接続

図はRキーの接続です。FとEも同じ配置した箱をTargetにし、表の関数へつなぎます。

3つとも、キーイベントの白いPressedを関数の白い入力へつなぎます。箱の関数は箱の動きを持ち、Level Blueprintは試すための操作を持つ形です。参照の作成が初めてなら、Level BlueprintとBlueprint Classの記事も参考になります。

連打と途中リセットを試す

両方のBlueprintをコンパイルし、Playしたらゲーム画面をクリックします。箱が見える位置で、次の順に操作してください。

操作表示とふたの動き
Play開始Locked。ふたは閉じた高さ
Eを押すLocked。開かない
Fを押すClosed。解錠されるが、まだ開かない
Eを押すOpening。ふたが上がり始める
2秒待つOpen。ふたが100cm上がった位置で止まる
Rを押すLocked。ふたがすぐ閉じた高さへ戻る

次はF、Eと押し、開いている途中にEを何度か押します。Openingの文字は増えても、動きは最初に戻らず、そのままOpenになることを確認します。

最後に、もう一度Rで戻してからF、Eと押し、2秒が終わる前にR を押してください。ふたが閉じ、その後2秒より長く待っても、Lockedのまま閉じていれば成功です。

状態だけ戻した場合と比べる

Playを止め、ChangeChestStateのFalseからSet CurrentStateへ白い線を直接つなぎ、Stopを一時的に通らない形にします。ほかの接続は変えません。

コンパイルしてPlayし直し、F→E→すぐRを試します。リセット直後は閉じても、Timelineが動き続けるため、ふたがまた持ち上がり、FinishedからOpenへ切り替わります。

途中でRを押した後、Stopを省くと再び開き、Stopを通すと2秒以上待っても閉じたままになる比較

これはCurrentStateが2つの値を同時に持ったわけではありません。状態の値は戻したのに、前の状態で始めた動作を止めていなかった のが原因です。

確認後はPlayを止め、False→Stop→Set CurrentStateの接続へ戻します。コンパイルして同じ操作を再確認してください。Stopは再生を止める指示で、停止しただけではFinishedを呼びません。

うまくいかないとき

症状確認するところ
開始時にLockedが出ないBeginPlayからEnterChestStateを呼んだか。ChangeChestStateでは同値で終わる
FやEを押しても反応しないゲーム画面へフォーカスしたか。Level BlueprintのPressedと、配置した箱へのTargetがつながっているか
Openingと出るが動かないPlay from StartのTargetがTL_Openか。TimelineのUpdateから、LidのSet Relative Locationへ白い線があるか
ふたが変な位置へ飛ぶLidの親がDefaultSceneRootか。Relative LocationのX/Yが0、ZがLerp110〜210か
最後まで上がったのにOpeningのままTimelineのFinishedからChangeChestState(Open)を呼んだか
リセット後も勝手に開くChangeChestStateでStopを通るか。StopのTargetがTL_Openか
Sponsored

状態を増やすときに見直すこと

たとえば宝箱へ Broken、つまり壊れた状態を足したくなったとします。Enumへ名前を追加するだけでなく、その状態へ「いつ入るか」「入ったら何をするか」「操作されたらどうするか」も決めます。

今回ならEnterChestStateとUseChestのSwitchが見直し対象です。増えた出口へ壊れた見た目や操作への反応をつなぎ、UnlockChestでは解錠させないままでよいかも確認します。ピンが増えても、処理は自動では書かれません。

EnumにBrokenを足すとSwitchの出口が1本増えるが、その先の処理は空のまま

EnumアセットのReference Viewerを使うと、利用しているBlueprintをたどれます。項目を追加・改名・削除した後は、利用箇所を開いてコンパイルし、Switchの接続と変数の既定値を確認してください。保存済みデータに状態を記録している場合は、その読み込みも確認します。

状態が増えたら、個数だけで分けるのではなく、別の観点が混ざっていないかを見ます。「開閉の状態」と「レア度」は別の観点なので、それぞれの変数に分けられます。一方、変数を2つにすれば組み合わせの制約まで消える、というわけではありません。

AnimBPのState Machineとの違い

Animation Blueprintにも State Machine があります。こちらは「待機のアニメーションから走るアニメーションへ移る」といった、再生と切り替えを扱います。

今回のEnumは「鍵が掛かっているので開けない」のようなゲームのルール、AnimBPのState Machineは「どの動きをどう見せるか」という役割です。キャラクターなら、ゲーム側の速度や状態をAnimBPへ渡し、遷移条件に使うことができます。

開けてよいかを決めるEnumと、どの動きを再生するか決めるAnimBPのState Machine

ただし、値を渡すだけでアニメーションや遷移条件が用意されるわけではありません。また、アニメーション中の通知をゲーム側の処理に使う構成もあります。詳しい再生側の作り方は、AnimBPのState MachineとBlend Spaceの記事で扱います。

おまけ:自分のゲームへ広げるとき

  • 鍵の所持も条件にできる:今回はFを解錠用の試験操作にしました。ゲームへ組み込むなら、鍵を持っているときだけUnlockChestを呼ぶ、近くにいる箱へUseChestを送る、といった入口に置き換えます。
  • 後始末が増えたら関数へ分ける:今回は停止するTimelineが1つなのでChangeChestStateへStopを置きました。状態ごとのTimer停止やエフェクト削除が増えたら、古い状態を渡すExitChestStateなどの関数へまとめ、その後でCurrentStateを更新すると追いやすくなります。
  • 外への通知は状態が決まった後に:開いたことをUIやクエストへ知らせたいなら、Event Dispatcherを使えます。ふたの毎回の位置更新で通知せず、Openに入ったときの処理へ置くと意図が揃います。
  • 敵AIにも考え方を使える:巡回から追跡へ移るときに速度を変え、追跡をやめたら移動要求を止める、という形です。実際の移動・発見判定は別に必要です。行動の優先順位を組むならBehavior Tree、状態と遷移を専用のエディタで組むならStateTreeも選択肢になります。
  • 2択ならBooleanでも十分:「一度開いたか」だけで動く箱まで、この4状態へ増やす必要はありません。追加するルールに合わせて、必要な状態を決めましょう。

まとめ

Enumは「今どの状態か」を1つの値で表し、Switchはその値に応じて処理を分けます。そこへ「いつ次へ進めるか」と「切り替えるときに何を止め、何を始めるか」を加えると、連打や途中キャンセルにも対応しやすくなります。

宝箱が普通に開くだけでなく、途中でRを押しても閉じたままかを確かめてみてください。状態の名前を揃えることと、実際の動きを揃えること。その両方を扱うのが、この実践の要点です。

参考:EpicのSwitchと実行フローの解説Timelineの操作ノードTimeline ComponentのStop

Unreal Engine このセクションのノート98