【Unreal Engine】GameInstance入門:3ステージのスコアを持ち越す

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

UE5のGameInstanceで、レベルを切り替えてもスコアとクリア記録を持ち越します。クラスの作成・登録、Get Game InstanceとCast、記録の重複防止、新しい周回のリセットまで、3ステージを巡るBlueprintの実践で解説します。

ステージ1でコインを30枚集めて、次のステージへ。ところが、画面のカウントが0に戻ってしまった。プレイヤーの変数に入れたはずなのに、なぜ残らないのでしょうか。

Open Level で別のレベルを開くと、元のキャラクターや配置したActorは作り直されます。変数の値を残したいなら、そのActorより長く存在する置き場所が必要です。

そこで使うのが GameInstance です。今回のゲーム起動中、レベルが切り替わっても同じものが残ります。この記事では、3つのステージの得点を足し、最後の画面へ合計とクリア数を持ち越します。

他のエンジンでいうと: Unity で DontDestroyOnLoad を付けた管理用オブジェクト、Godot の Autoload(シングルトン) に当たります。ただし「プロジェクトに1つだけ」ではなく、 ゲームの実行1つにつき1つ です。

ステージが切り替わってもGameInstanceのスコアが次へ続く

この記事でわかること

  • 自作のGameInstanceを作り、プロジェクトで使うよう登録する
  • 別のActorから記録を更新し、次のレベルで読み出す
  • 同じステージの二重加算を防ぐ
  • 記録を残して再訪する場合と、新しい周回を始める場合を分ける

Blueprintで変数・関数を作れる人向けです。Third Personテンプレートの1人プレイを使い、Open Level でレベルを丸ごと切り替える例として進めます。

Sponsored

GameInstanceは、今回のプレイ中の記憶

GameInstanceは、ゲームの開始時にUEが作り、ゲームを終了するまで使うオブジェクトです。Actorのようにレベルへ配置するものではなく、位置や見た目も持ちません。

今回のレベル切り替えでは、次の違いがあります。

置き場所次のレベルを開いたとき
キャラクターや配置したActorの変数元のActorが破棄され、新しいActorは初期値から始まる
GameModeやLevel Blueprintの変数新しく開いたレベルのものに切り替わる
GameInstanceの変数同じGameInstanceが残り、値もそのまま使える
GameInstanceは3レベルを通して残り、各レベルのActorは入れ替わる

「キャラクターが残る」のではなく、「キャラクターの外へ預けた記録が残る」 と考えると、使いどころが分かりやすくなります。新しいレベルの表示側は、その記録を読み出します。

ただし、Playを停止してもう一度始めると、GameInstanceも新しくなります。製品版では、アプリを閉じるまでが一区切りです。タイトルへ戻るだけでは値は消えません。

GameInstanceだけが持ち越しの唯一の方法というわけではありませんが、Blueprintでレベルをまたぐ数値を扱う入口として使いやすい方法です。レベル遷移の記事も、この使い方につながります。

作って、プロジェクトへ登録する

1. GameInstanceを親にBlueprintを作る

コンテンツブラウザで右クリックし、「Blueprint Class」を選びます。親クラス選択の「All Classes」で GameInstance を検索し、BP_GameInstance を作ります。

開いて、次の2変数を追加します。コンパイルしてから初期値を確認してください。

変数名初期値・用途
TotalScoreInteger0。今回の合計点
ClearedStagesNameのArray空。今回クリアしたステージのID一覧

Name は、Stage01 のような識別名を扱う型です。Array(配列) にすると、同じ型の値を一覧として持てます。ClearedStagesには、通過した順にStage01、Stage02、Stage03を記録します。

2. このクラスを使うように設定する

「Edit → Project Settings → Maps & Modes」を開き、「Game Instance Class」へ BP_GameInstance を指定します。

GameInstanceを親に作成し、変数を追加して、Game Instance Classへ登録する

クラスを作るだけでは、まだ使われません。 ここで登録して初めて、UEが自作のBP_GameInstanceを作ってくれます。設定を変えたらPlayを停止し、もう一度開始してください。

スコアとクリア記録を更新する

GameInstanceを取得する入口は Get Game Instance です。これは、現在使われているGameInstanceへの 参照 を返します。参照とは「どのオブジェクトを使うか」を示すものです。呼ぶたびに新しく作る処理ではありません。

その出力を Cast To BP_GameInstance のObjectへ渡すと、自作の変数や関数を使えます。Castは、取り出した相手をBP_GameInstanceとして扱えるか確認する処理です。実際の接続は、後ほどゴールと表示用Actorで作ります。

先にBP_GameInstanceの中へ、「表示する」「クリアを記録する」の2つの関数を用意しましょう。

1. 現在の記録を表示するShowSummary

BP_GameInstanceの「Functions」に ShowSummary を作ります。入力・出力は追加せず、Pureは無効のままにします。今回は画面へ文字を出す処理なので、白い実行線で呼び出す関数にします。

Format Text を置き、Formatへ次を入力します。

合計: {Total} / クリア: {Cleared}

TotalへTotalScoreのGetをつなぎます。ClearedStagesのGetから Length を作り、その出力をClearedへつなぎます。Lengthは配列の項目数なので、3ステージを記録していれば3です。数値をTextへ変えるノードが自動で入る場合は、そのままで構いません。

TotalScoreとClearedStagesのLengthをFormat Textへ入れる

関数の入口から Print Text へ白い実行線をつなぎ、In TextへFormat TextのResultを渡します。Print to ScreenとPrint to Logを有効、Duration=10、Key=RunSummaryにします。

ShowSummaryの実行線と、Format Textからの文字をPrint Textへ渡す

これで、呼び出した時点の記録を画面とOutput Logへ出せます。同じKeyを使うので、画面上の表示は更新されます。

2. 初めてのクリアだけ加算するClearStage

同じBP_GameInstanceに関数 ClearStage を作り、入力を2つ追加します。

入力名渡される値の例
StageIDNameStage01
ScoreInteger120

今回は 「各ステージの得点は、1周につき1回だけ」 というルールにします。やり直して同じゴールを通っても、合計点は増やしません。

ClearedStagesのGetから Contains Item を作り、Item to Findへ入力のStageIDを渡します。Contains Itemは、「このIDが一覧にあるか」をtrue/falseで返します。

関数の入口からBranchへ白い線をつなぎ、ConditionへContains ItemのReturn Valueを渡します。True側はPrint Textで このステージは記録済みです と表示して終了。False側だけ、次の記録処理へ進めます。

クリア一覧にStageIDが含まれるか調べ、初めての場合だけ記録へ進む

Falseから、次の順で白い線をつなぎます。

  1. Add Unique:Target ArrayへClearedStagesのGet、New Itemへ入力のStageID
  2. Set TotalScore:値へ「TotalScoreのGet+入力のScore」を渡す。Integer同士の + を使う
  3. ShowSummary:TargetはSelf
未クリアのIDを追加し、現在の合計点へ今回のScoreを足す

Add Uniqueは、同じIDを配列に重ねて入れない追加方法です。これだけでは、その後のスコア加算は止まりません。 先にContains Itemで分岐することで、一覧と得点の両方を二重更新から守ります。Add UniqueのReturn Valueは今回は使いません。

記録済みメッセージなど、この記事のほかのPrint TextはDuration=5、Key=None、画面とログを両方有効にします。ここまでできたらBP_GameInstanceをコンパイルして保存し、ほかのBlueprintから関数を呼べる状態にします。

Sponsored

実践:3つのゴールから、記録して次へ進む

1. 4つのレベルを用意する

Third PersonのBlueprintプロジェクトで、「File → New Level → Basic」からレベルを作り、Content/Maps へ次の名前で保存します。

  • L_Stage01
  • L_Stage02
  • L_Stage03
  • L_Result

各レベルに歩ける床とPlayer Startを用意し、「World Settings」の「GameMode Override」を BP_ThirdPersonGameMode にします。Playでキャラクターが出現し、歩けることを確かめてください。テンプレートにVariant選択がある版では、Noneを使います。

2. ゴールActorを作る

Actorを親に BP_StageGoal を作ります。DefaultSceneRootの子へBox Collisionを追加し、Trigger と名付けます。Relative Locationは (0,0,100)、Box Extentは (100,100,100) にします。

TriggerのCollision PresetsをCustom、Collision EnabledをQuery Only、Object TypeをWorldDynamicにします。PawnだけOverlap、ほかはIgnoreにし、Generate Overlap Eventsを有効にします。

Overlap は、相手を壁のように押し返さず、領域へ入ったことを検知する設定です。BP_ThirdPersonCharacter側でもCapsule ComponentのGenerate Overlap Eventsを有効、Mesh側は無効にして、カプセルで検知します。

見える目印としてStatic Meshを追加し、Cubeを指定します。名前はMarker、Relative Location=(0,-120,60)、Scale=(0.15,0.15,1.2)、CollisionはNoCollisionにします。

柱の横のTriggerをキャラクターが通過するゴールの配置

BP_StageGoalに次の変数を作ります。

変数名初期値Instance Editable
StageIDNameNone有効
StageScoreInteger0有効
NextLevelNameNone有効
IsTransitioningBooleanfalse無効

Instance Editable を有効にすると、レベルへ置いた個体ごとに値を変えられます。同じBP_StageGoalを各ステージへ1つずつ置き、次を設定します。L_Resultにはゴールを置きません。

配置先StageIDStageScoreNextLevel
L_Stage01Stage01120/Game/Maps/L_Stage02
L_Stage02Stage0280/Game/Maps/L_Stage03
L_Stage03Stage03150/Game/Maps/L_Result

NextLevelは、次に開くレベルを示すNameです。ここでは名前の重複を避けるため、Content/Game に置き換えたパスを使います。末尾の .umap は付けません。

ゴールはPlayer Startと重ならない場所に置きます。たとえば床の高さをZ=0としたとき、ゴールActorを (500,0,0)、Player Startを (0,0,100) にすれば、歩いて近づいて試せます。

3. プレイヤーが触れたときだけ反応する

BP_StageGoalでTriggerを選び、On Component Begin Overlapを追加します。白い出力をCast To BP_ThirdPersonCharacterへ、Other ActorをObjectへつなぎます。Other Actorは、いま領域へ入った相手です。

Cast成功からBranchへ進め、ConditionへIsTransitioningのGetを渡します。Trueはつながず終了、FalseからSet IsTransitioning=trueへつなぎます。

Overlapの相手を確認し、遷移中でなければ処理を始める

IsTransitioningは「このゴールは、すでに次へ進む処理を始めた」という札です。複数の接触が起きても、同じゴールから処理を重ねて始めないようにします。

4. GameInstanceへ記録してから、次を開く

Set IsTransitioning=trueの後を、Cast To BP_GameInstance の白い実行入力へつなぎます。Get Game Instance の青いReturn Valueは、CastのObjectへ渡します。

白い実行線とGet Game Instanceの参照を、Castへ別々に渡す

Get Game Instanceには白い実行ピンがありません。白い線は「いつ実行するか」、青い線は「どの相手を使うか」 を渡します。

Cast成功からClearStageの呼び出しへ進みます。Targetへ「As BP Game Instance」、StageIDへ自分のStageIDのGet、Scoreへ自分のStageScoreのGetを渡します。

GameInstanceをTargetに、ゴール自身のStageIDと得点をClearStageへ渡す

ClearStageの白い出力から Open Level (by Name) へつなぎます。Level NameへNextLevelのGetを渡し、Absoluteはtrue、Optionsは空のままにします。

ClearStageの完了後に、NextLevelを指定したOpen Levelを呼ぶ

記録は、今のレベルを離れる前 に済ませます。次のレベルでは、すでに更新されたGameInstanceを読み出せます。

Cast To BP_GameInstanceの失敗側は、Set IsTransitioning=false→Print Textの順につなぎ、Game Instance Classを確認してください と表示します。失敗時にはOpen Levelへ進めません。キャラクターのCast失敗側は、対象外なので何もしません。

5. 新しいレベルで、今の記録を表示する

Actorを親に BP_RunStatus を作り、4つのレベルすべてに1つずつ置きます。見た目の部品は不要です。

BP_RunStatusではBeginPlay→Cast To BP_GameInstanceへ白い線をつなぎ、ObjectへGet Game Instanceの出力を渡します。成功からShowSummaryを呼び、Targetへ「As BP Game Instance」を渡します。失敗側は同じ設定確認メッセージを出します。

各レベルのBP_RunStatusが、BeginPlayでGameInstanceのShowSummaryを呼ぶ

表示するたびにTotalScoreを0へ戻さない ことが大切です。BP_RunStatusは読み出す係で、記録を初期化する係ではありません。

Sponsored

確認:持ち越し・再訪・新しい周回

まず、3ステージを通す

すべて保存・コンパイルし、L_Stage01からPlayします。画面をクリックして操作し、ゴールの柱へ順に近づきます。

場面表示される記録
L_Stage01の開始合計: 0 / クリア: 0
Stage01をクリアしてL_Stage02へ合計: 120 / クリア: 1
Stage02をクリアしてL_Stage03へ合計: 200 / クリア: 2
Stage03をクリアしてL_Resultへ合計: 350 / クリア: 3
3つのクリアで120、200、350と増え、リザルトでも350と3が残る

遷移直前の文字を見逃しても、次のレベルのBeginPlayで再表示します。Output Logにも同じ記録が残ります。

記録を残して、もう一度訪れる

確認用にBP_RunStatusの「Class Defaults → Input → Auto Receive Input」をPlayer 0にします。イベントグラフへキーボードの R を追加し、PressedからOpen Level (by Name)へつなぎます。Level Nameには /Game/Maps/L_Stage01 を直接入れます。

もう一度L_Stage01から3ステージを通し、リザルトで R を押してください。最初のステージを開き直しても、記録は350/3のままです。再びゴールを通ると「記録済み」と表示され、次へ進んでも得点は増えません。

これで、GameInstanceが残ることと、同じStageIDの二重加算を防げることを一緒に確かめられます。

新しい周回は、記録を消してから始める

BP_GameInstanceへ関数 ResetRun を作ります。入口からSet TotalScore=0→Clear→ShowSummaryの順につなぎます。ClearはClearedStagesのGetから作った配列用ノードで、一覧を空にする処理です。

BP_RunStatusへキーボードの N を追加します。Pressed→Cast To BP_GameInstance、ObjectはGet Game Instance。成功からResetRunを呼び、Targetへ「As BP Game Instance」を渡します。その後でOpen Level (by Name)を呼び、/Game/Maps/L_Stage01 を開きます。Cast失敗側には設定確認メッセージをつなぎます。

Rは記録を残して最初へ、NはResetRunで0と空の一覧にしてから最初へ

Play中に N を押すと0/0で始まり、もう一度3ステージを通せば350/3になります。レベルを開くことと、新しい周回にすることは別の処理 だと分かります。

最後にPlayを止めて再開すると、今度はGameInstance自体が新しくなり、初期値の0/0から始まります。RとNは確認用の操作なので、本番ではタイトル画面の「続ける」「はじめから」などへ置き換えられます。

うまく動かないとき

症状まず見るところ
設定確認メッセージが出るGame Instance ClassがBP_GameInstanceか。設定後にPlayを再開したか
ゴールに近づいても反応しないTriggerとCapsuleのOverlap設定、Other Actor→Object、Cast後の白い線
次のレベルへ進まない配置したゴールのNextLevel、レベルの保存先、Open Levelの入力
次のレベルで0になるBeginPlayで初期化していないか。レベル側の別変数を読んでいないか
2つ目のゴールも記録済みになる個体ごとのStageIDがStage01/02/03になっているか
再訪で得点だけ増えるContains ItemのTrue側から加算へ進んでいないか
RやNが反応しないBP_RunStatusを配置したか、Auto Receive InputがPlayer 0か、画面へ入力フォーカスがあるか

登録の意味も試すなら、Playを止めてGame Instance Classを既定のGameInstanceへ戻し、再生します。今度は設定確認メッセージが出るはずです。確認後はBP_GameInstanceへ戻してから、Playをやり直してください。

おまけ:初期化と、置くデータの選び方

InitとShutdownは、レベルの開始・終了とは違う

GameInstanceのイベントグラフではEvent InitとEvent Shutdownを使えます。それぞれ、GameInstanceが初期化されるときと、終了するときの入口です。

Init→Print Textで GameInstance: Init、Shutdown→Print Textで GameInstance: Shutdown をログへ出してみると、Play開始・停止と、レベル移動の違いを追えます。3ステージを通っても、Initはレベルごとに呼び直されません。

Initは、起動時に必要な値を準備する場所です。プレイヤーやUIがそろっている前提で触らず、画面やActorへの反映は、それぞれの準備ができた後に行います。また、強制終了などではShutdownが呼ばれる保証はないので、大切な保存を終了時だけに任せないようにします。

残すのは、次のレベルでも意味がある情報

今回残したのは、合計点とステージIDです。「L_Stage01にいたゴールActorそのもの」への参照は保存していません。

消えるゴールActorへの参照と、残して使えるStageID・得点を対比する

Actor参照は「いま存在するこの個体」を指します。GameInstanceから参照していても、レベルを離れて破棄されるActorが残るわけではありません。次のレベルで使う相手は、そのレベルで取得し直します。

持ち越したいこと記録の例
何点稼いだかTotalScore=350
どこをクリアしたかStage01、Stage02、Stage03
何を持っているかアイテムIDと個数
どこへ戻るかレベル名とチェックポイントID

参照をすべて禁止する必要はありません。制作時に用意したData Assetへの参照など、レベル上の一時的なActorとは性質が違うものもあります。参照先がいつまで存在するか を考えて選びます。IDも保存するだけでActorが自動復元されるわけではなく、IDに対応するものを探したり作ったりする処理が必要です。

次回の起動にも残すならSave Game

GameInstanceは「今回のプレイ中の記憶」、Save Gameへの保存は「次回へ渡す記録」 です。ゲーム中はGameInstanceで更新し、区切りで必要な値をSaveGameオブジェクトへコピーして、ファイルへ書き出します。次回はファイルから読んだ値をGameInstanceへ戻します。

SaveGameオブジェクトを作っただけではファイルに保存されません。Save Gameの記事で、書き込みと読み戻しを試せます。

機能が増えたら、役割ごとに分ける

スコア、音量、実績、保存の処理が一つのクラスへ集まり、どこを直すのか分かりにくくなったら、機能ごとの分割を考えます。GameInstanceとともに管理される GameInstance Subsystem が、その選択肢です。

最初から導入する必要はありません。まず今回のようにClearStageやResetRunへ変更の入口をまとめておくと、更新ルールを探しやすくなります。C++を使う分割の入口はSubsystemの記事で扱います。

パッケージ化して試す場合は、4つのレベルをビルド対象に含めます。名前で開けても、製品版にマップが入っていなければ移動できません。パッケージングの記事で確認してください。

まとめ

  • GameInstanceは、今回のプレイ中ずっと残る記憶
  • 作るだけでなく、Project Settingsへ登録して初めて使える
  • 残すのは「次のレベルでも意味がある情報」。Actorへの参照は残さない
  • いつ0へ戻すかは、周回の区切りに合わせて自分で決める

置き場所に迷ったときの問いかけは、「これは次のレベルでも意味があるか」 です。意味がないなら、そのレベルの中で持てば足ります。

次回の起動にも残すなら Save Game、機能ごとに分けたくなったら Subsystem へ進んでください。

参考:GameInstanceの公式APIGet Game InstanceOpen Level (by Name)

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