1.

UE5でセーブボタンを作る方法|On ClickedでSave Game To Slotを呼ぶ

編集

Unreal Engine 5(UE5)でセーブするボタンを作成するには、画面に配置したUIのボタンにOn Clickedイベントを設定し、その中でセーブデータ用オブジェクトを用意してSave Game To Slotノードを呼び出します。これにより、プレイヤーが任意のタイミングでボタンを押すだけでゲームの進行状況を保存できる仕組みを実装できます。この記事では、Widgetブループリントを使ったセーブボタンの作り方を、つまずきやすいポイントまで含めて順を追って解説します。

この記事の要点
  • セーブボタンの基本は「Widgetのボタン → On Clicked イベント → セーブ処理」という流れで構成される。
  • 保存するデータはSaveGameクラスを継承したオブジェクトに格納し、Save Game To Slotでディスクへ書き込む。
  • 初回はCreate Save Game Objectで新規作成、2回目以降は既存スロットを読み込んでから更新するのが基本的な考え方。
  • 保存先は「スロット名」で識別するため、保存と読み込みで同じスロット名をそろえる必要がある。
  • セーブ&ロードの全体的な仕組みについては セーブ&ロード の記事もあわせて参照すると理解しやすい。

セーブボタンの全体像

UE5でセーブボタンを実現するときの構成要素は、大きく分けて3つです。まず、画面に表示するボタン(Button)を持つWidgetブループリント。次に、ボタンが押されたことを検知するOn Clickedイベント。そして、実際にデータを書き出すセーブ処理(SaveGameオブジェクト+Save Game To Slot)です。

処理の流れを図式化すると、次のようなイメージになります。ボタンを押した瞬間にすべてが連鎖して動くため、プレイヤーから見れば「ボタンを押す=セーブ完了」というシンプルな体験になります。

[セーブボタンを押す]
 ↓
On Clicked イベント発火
 ↓
SaveGame オブジェクトを用意(新規作成 または 既存を読み込み)
 ↓
保存したい値(スコア・位置など)をオブジェクトに設定
 ↓
Save Game To Slot(スロット名を指定してディスクへ書き込み)
 ↓
成否を判定してプレイヤーへフィードバック表示

以下では、この流れを4つの手順に分けて実装していきます。なお、セーブ機能そのものの考え方(どんなデータをどこに保存するか、ロード側の扱いなど)の基礎は セーブ&ロード で扱っているため、ここではボタンからセーブを呼び出す部分に焦点を当てます。

手順1:SaveGameクラス(保存データの入れ物)を準備する

セーブボタンを作る前に、まず「何を保存するのか」を定義したクラスが必要です。UE5ではSaveGameを親クラスとしたブループリント(または C++ クラス)を作成し、保存したい値を変数として持たせます。これがセーブデータの入れ物になります。

ブループリントでSaveGameクラスを作成する手順は次のとおりです。

  • コンテンツブラウザで右クリックし、「ブループリントクラス」を選択します。
  • 親クラスの選択画面で、検索欄に「SaveGame」と入力してSaveGameを選びます。「すべてのクラス」を展開する必要がある場合もあります。
  • 作成したクラスに分かりやすい名前を付けます(例:「BP_SaveSlot」)。
  • そのクラスを開き、保存したい値を変数として追加します。たとえばスコアなら整数(Integer)型の「PlayerScore」、プレイヤー位置なら「Vector」型の「PlayerLocation」などです。各変数は「インスタンス編集可能」にしておくと扱いやすくなります。

ここで定義した変数に、後ほどボタンを押したタイミングで現在のゲームの値を書き込み、それをまるごとディスクへ保存します。どんなデータを変数として持たせるべきかという設計の指針については セーブ&ロード を参照してください。

手順2:セーブ用WidgetにButtonを配置する

次に、画面に表示するセーブボタンを用意します。UE5のUIはUMG(Widgetブループリント)で作成します。

  • コンテンツブラウザで右クリックし、「ユーザーインターフェース」から「ウィジェットブループリント」を選択します。親クラスは標準の「User Widget」で問題ありません。
  • 名前を付けて(例:「WBP_SaveMenu」)保存し、ダブルクリックでUMGエディタを開きます。
  • 左側の「パレット」からButtonをデザイナー画面(キャンバス)へドラッグして配置します。
  • 配置したButtonを選択し、右側の「詳細」パネル上部の名前欄でボタンの名前を変更します(例:「SaveButton」)。この名前は後でイベントを作るときの識別に使います。
  • ボタンの上にTextをドラッグして重ね、「ゲームをセーブ」などの表示テキストを設定します。Buttonの中にTextを入れ子にすると、ボタンのラベルとして表示されます。

この時点ではボタンは見た目だけで、押しても何も起きません。次の手順でクリック時の処理を組み込みます。

手順3:On Clickedイベントでセーブ処理を組む

ここがセーブボタンの中心です。配置したButtonにOn Clickedイベントを追加し、その中でセーブ処理を構築します。

まず、On Clickedイベントノードを作成します。

  • UMGエディタでSaveButtonを選択した状態で、「詳細」パネルを下にスクロールし、「イベント」セクションにあるOn Clickedの右側の「+」ボタンをクリックします。
  • 自動的にグラフ(イベントグラフ)に切り替わり、「On Clicked (SaveButton)」というイベントノードが追加されます。このノードの実行ピンから処理をつないでいきます。

続いて、セーブ処理の本体を組みます。基本となる考え方は「SaveGameオブジェクトを用意して、値を入れて、スロットへ書き込む」です。初回セーブと2回目以降を分けて考えると分かりやすくなります。

初回(新規作成)の場合

  • On Clickedの実行ピンからCreate Save Game Objectノードをつなぎます。「Save Game Class」には、手順1で作成したSaveGameクラス(例:BP_SaveSlot)を指定します。これでメモリ上に空のセーブデータが作られます(※この時点ではまだディスクには保存されていません)。
  • 生成されたオブジェクト(Return Value)に対して、保存したい現在の値を設定します。たとえば「Set PlayerScore」で現在のスコアを書き込む、といった形です。
  • 最後にSave Game To Slotノードをつなぎます。「Save Game Object」には先ほどのオブジェクト、「Slot Name」には任意のスロット名(例:「SaveSlot1」)、「User Index」は通常「0」を指定します。これで指定したスロットにデータが書き込まれます。

2回目以降(既存データを更新する)の場合

毎回Create Save Game Objectで新規作成すると、それまでの内容が初期値で上書きされてしまいます。すでに保存があるなら、いったん読み込んでから更新するのが安全です。

  • Does Save Game Existノードで、同じスロット名のセーブが存在するかを判定します。出力をBranch(True/False)につなぎます。
  • 存在する(True)場合はLoad Game from Slotで既存データを読み込み、Cast To(SaveGameクラスへキャスト)で自作クラスとして扱える形にします。
  • 存在しない(False)場合のみ、Create Save Game Objectで新規作成します。
  • どちらの経路でも最終的に同じオブジェクトに対して値を設定し、Save Game To Slotで書き込みます。

なお、保存するデータ量が大きい場合や、ゲームプレイ中(一時停止していない状態)に保存する場合は、処理中の引っかかり(ヒッチ)を避けられるAsync Save Game To Slotの利用が推奨されています。メニューやポーズ画面からの保存、あるいはデータが小さい場合は同期版のSave Game To Slotでも問題ありません。

手順4:成否のフィードバックを表示する

セーブが完了したことをプレイヤーに伝えると、操作の安心感が大きく向上します。Save Game To Slotノードには成否を示す戻り値(ブール値)があり、これを利用します。

  • Save Game To Slotの戻り値をBranchにつなぎます。
  • True(成功)の場合は、「セーブしました」などのメッセージを画面に表示します。簡易的には開発用のPrint String、製品版では別のWidget(テキストやポップアップ)を一時表示するのが一般的です。
  • False(失敗)の場合は、「セーブに失敗しました」といったエラー表示を行い、必要に応じてログを残します。

Async Save Game To Slotを使う場合は、書き込み完了時に呼ばれる出力(コールバック相当の実行ピン)でフィードバックを表示すると、タイミングがずれずに済みます。

具体例:ボタンを押して現在のスコアを保存する

ここまでの流れを、シンプルなスコア保存の例でまとめます。GameInstanceやプレイヤーに「現在のスコア」を持たせている前提です。

On Clicked (SaveButton)
 ↓
Does Save Game Exist(Slot Name = "SaveSlot1")
 ↓ → Branch
  True : Load Game from Slot → Cast To BP_SaveSlot
  False: Create Save Game Object(Class = BP_SaveSlot)
 ↓(合流)
Set PlayerScore(= 現在のスコア値)
 ↓
Save Game To Slot(Slot Name = "SaveSlot1", User Index = 0)
 ↓ → Branch(戻り値で判定)
  True : Print String "セーブしました"
  False: Print String "セーブに失敗しました"

このグラフを組めば、ボタンを押すたびに最新のスコアが「SaveSlot1」に書き込まれ、成否がその場で表示されます。ロード側(ゲーム起動時に同じスロットを読み込んで値を反映する処理)の作り方は セーブ&ロード を参照してください。

落とし穴と注意点

つまずきやすいポイント
  • 毎回Create Save Game Objectで上書きしてしまう:ボタンを押すたびに新規オブジェクトを作ると、それまでの保存内容が初期値に戻ってしまいます。既存データを残したい場合は、Does Save Game ExistとLoad Game from Slotで読み込んでから更新しましょう。
  • スロット名のミスマッチ:保存(Save Game To Slot)と読み込み(Load Game from Slot)で、わずかでもスロット名が違うと別物として扱われ、データを見つけられません。スロット名は変数や定数で一元管理すると安全です。
  • ボタンの連打:短時間に何度も押されると、保存処理が重複して走り、特にAsync版では予期しない挙動につながることがあります。保存中はボタンを一時的に無効化(Is Enabledをfalse)し、完了後に戻すと安全です。
  • 「保存した=ディスクに書き込んだ」ではない点:Create Save Game Objectはメモリ上にオブジェクトを作るだけで、ディスクへの書き込みはSave Game To Slotが担います。ここを混同すると「セーブしたはずなのに残っていない」原因になります。

よくある質問(FAQ)

Q. ボタンを押してもセーブされません。何を確認すればよいですか。

まず、On Clickedイベントが正しく作成されているか(SaveButtonに対して追加されているか)を確認します。次に、Save Game To Slotまで処理がつながっているか、スロット名が空でないかをチェックします。Print Stringなどで各ノードの実行を確認し、どこで処理が止まっているかを切り分けると原因を特定しやすくなります。Save Game To Slotの戻り値がfalseなら、書き込み自体が失敗している可能性があります。

Q. 複数のセーブデータ(スロット)を扱いたいときはどうすればよいですか。

スロット名を変えるだけで、複数の独立したセーブデータを管理できます。たとえば「SaveSlot1」「SaveSlot2」のように名前を分け、ボタンごと、あるいはセーブ枠の選択に応じてスロット名を切り替えてSave Game To Slotに渡します。読み込み時も同じスロット名を指定すれば、対応するデータを取り出せます。

Q. Save Game To SlotとAsync Save Game To Slotはどちらを使うべきですか。

保存するデータが小さい場合や、メニュー・ポーズ画面など処理が一瞬止まっても気にならない場面では、同期版のSave Game To Slotで十分です。一方、データ量が大きい、またはゲームプレイ中に保存してフレームの引っかかりを避けたい場合は、Async Save Game To Slotの利用が推奨されています。仕様の細部はバージョンによって異なる場合があるため、最終的な確認はお使いのバージョンの公式ドキュメントをご参照ください。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. セーブするボタンを作成する方法
  2. セーブするとセーブファイルの実体がどこに保存されるか
  3. ロードするボタンを作成する方法

最近更新/作成されたページ