ゲームのセーブ失敗をプレイヤーに伝えるUI
遊びをつくる執筆にClaudeを使用しています。

セーブが失敗したとき、プレイヤーに何も伝えなければ「保存できた」と思いこんだままゲームを終了し、次回起動時にデータが消えていることに気づきます。この体験はゲーム自体への不信感に直結するため、セーブ失敗の通知は「あれば親切」ではなく「なければ有害」な機能です。 では何を、いつ、どのように伝えればよいのか。「エラーが出ました」と表示するだけでは不十分で、プレイヤーが次にとれる行動まで案内できて初めて通知の役割を果たします。この記事では、ブラウザゲームを前提にセーブ失敗UIの設計を「伝える内容」「表示タイミング」「見た目と文言」「実装上の注意」の順に整理します。
この記事の目次
セーブ失敗UIが伝えるべき三つの情報
エラー通知に必要な情報は三層あります。この三層がそろっていないと、プレイヤーは「何かまずいことが起きたらしい」とは感じても、行動に移れません。
第一層:何が起きたか「セーブに失敗しました」という事実そのものです。曖昧な表現(「エラーが発生しました」など)では、セーブ以外のどこかが壊れたと誤解される可能性があります。「進行データの保存に失敗しました」のように対象を明示します。
第二層:なぜ起きたか(分かる範囲で)原因が分かる場合は短く添えます。ブラウザゲームで頻度が高い原因は、ストレージ容量の超過、ネットワーク切断、ブラウザのプライベートモードによるlocalStorage無効、セッション切れの四つです。すべての原因を網羅しようとすると文章が長くなりすぎるため、エラーコードや例外オブジェクトから判定できる場合だけ補足し、判定できない場合は「詳しい原因は不明です」と正直に書くほうが信頼感を損ないません。
第三層:プレイヤーが今できること「もう一度保存を試す」「ページを再読み込みして再試行する」「データをテキストとしてコピーして手元に保管する」など、具体的な次の行動を一つか二つ示します。特に「何もできない」場合でも「このセッション中のプレイは保存されません。ブラウザを閉じると進行が失われます」と伝えることで、プレイヤーは自分でリスクを判断できます。
表示タイミングの設計:いつ・何回・どのくらい見せるか
セーブは非同期処理になることが多く、タイミングの設計を誤ると通知が役に立たなくなります。
失敗を検知した直後に表示するlocalStorage.setItem() がエラーをスローした、あるいはAPIレスポンスがエラーを返した瞬間にUIを出します。処理の完了を待ちながら「保存中…」インジケーターを出している場合は、そのインジケーターを失敗状態に切り替えます。成功通知と失敗通知が同じ場所に出るようにしておくと、プレイヤーは「ここを見ればセーブの状態が分かる」と学習します。
自動消滅させるかどうかの判断基準成功トーストは3〜5秒で自動消滅させてもかまいません。しかし失敗通知は、プレイヤーが読んで行動を選ぶまで残しておく必要があります。自動消滅させると「何かエラーが出たが消えた、大丈夫だろう」と誤解される典型的なパターンに陥ります。閉じるボタンを設け、プレイヤーが明示的に「確認した」という操作をしてから消える設計にします。
再試行後の扱い「再試行」ボタンを押した後、再び失敗した場合は同じメッセージをそのまま出し直すより、「再試行しましたが、再び失敗しました」と状態が変わったことを示します。同じ文言が繰り返し表示されると、プレイヤーはUIが壊れていると感じます。
文言と見た目:読まれるエラー通知の条件
文言の書き方
技術的な表現はプレイヤー向けには避けます。以下に悪い例と改善例を示します。
- QuotaExceededError、改善例:保存領域がいっぱいです。不要なデータを削除するか、別のブラウザをお試しください。
- Network Error: 503、改善例:サーバーに接続できませんでした。インターネット接続を確認してから、もう一度お試しください。
- undefined is not a function、改善例:セーブ処理中に予期しないエラーが起きました。ページを再読み込みすると解決する場合があります。
文言の長さは2〜3文が目安です。それ以上になる場合は「詳細を見る」で折り畳みます。
視覚的なデザインの要点
失敗通知には警告色(赤やオレンジ系)を使うのが一般的ですが、色だけに頼るとカラーユニバーサルデザインの観点で問題が起きます。アイコン(×や⚠)と文字を組み合わせ、色が見えなくても情報が伝わるようにします。
位置はゲーム画面の邪魔にならない場所、かつ目に入る場所を選びます。画面中央のモーダル(ポップアップ)は確実に目に入りますが操作を強制中断させます。画面の端に出るトースト型は邪魔になりにくい反面、見落とされるリスクがあります。セーブ失敗は重大度が高いため、ゲームを一時停止してモーダルで伝える判断が妥当な場面も多くあります。重大度に応じてモーダル・バナー・トーストを使い分ける設計を最初に決めておくと、後からUIが散らかりません。
実装で失敗しやすい三つのポイント
エラーを握りつぶさない
try { save() } catch (e) {} のようにcatchブロックを空にすると、失敗が静かに無視されます。開発中に「エラーが出なければOK」と確認していると、このパターンに気づきにくいです。catchブロックの中で必ずUIへの通知処理を呼ぶか、呼び忘れを防ぐためにセーブ処理を関数化してUI通知を必ずセットにする設計にします。
成功と失敗を同じ変数で管理しない
saveStatus = 'success' | 'error' | 'idle' のように状態を一つの変数で管理し、それに応じてUIを切り替えるアーキテクチャが整理しやすいです。「成功フラグ」と「失敗フラグ」を別々のbooleanで持つと、両方trueになるなど矛盾した状態が発生しやすくなります。
localStorageが使えない環境のフォールバック
ブラウザのプライベートモードやiOSのWebViewなど、localStorageへの書き込みが最初から禁止されている環境があります。セーブ処理の前に一度テスト書き込みを行い、失敗した場合はゲーム起動時点で「このブラウザ環境では保存機能が利用できません」と伝えておくと、ゲーム中のエラーを未然に防げます。起動時に気づいてもらう方が、ゲームを進めた後に失敗を知らせるよりプレイヤーの心理的ダメージが少ないです。
アソバースのSDKを使う場合の考え方
アソバースのSDKに対応したゲームではクラウドセーブの仕組みを利用できますが、SDKが提供する保存APIも内部的には非同期処理であり、失敗することがあります。SDKから返るエラーオブジェクトをそのままプレイヤーに見せるのではなく、上で説明した三層の情報に変換してUIに渡す処理は作者側で実装する必要があります。SDKの挙動や返り値の仕様は公式ドキュメントで確認したうえで、エラーハンドリングの設計を行ってください。
次の行動
自分のゲームのセーブ処理をcatchブロックの中から見直し、UIへの通知が確実に呼ばれているか確認してみてください。次に、意図的にストレージをいっぱいにした状態や、オフラインで実際にエラー通知が表示されるかをテストします。アソバースへの投稿前にこのテストを一度通しておくと、公開後に「データが消えた」という報告を受けるリスクを減らせます。

