前回、無料で軽快な 2D/3D ゲームエンジン GodotEngine4 で作成したタップゲームを Android スマートフォンに USB ケーブル経由でインストールしてデバッグ実行しました。
実機でデバッグ実行すると、PC では発生しなかった問題がいくつか発生しました。
今回は、無料で軽快なゲームエンジン GodotEngine4 で作成したアプリを Android スマートフォンの実機でデバッグ実行した際に、スコアなどのセーブデータがオートセーブされないバグとその対処法について紹介します。
※この記事の内容は、アプリ タップ The 宝箱 の開発でも使用しています。
※ GodotEngine のバージョンは 4.1.2 です。 .NET 版ではありません。
※「いらすとや」様の画像を使用しています。
※「ふい字」フォントを使用しています。
※「魔王魂」様のサウンドを動画内で使用しています。
※「無料効果音で遊ぼう!」様のサウンドを動画内で使用しています。
※記事で紹介するスクリプト / プログラム / コードは自己責任で使用してください。
セーブとロードの実装について
セーブとロードの処理の実装については後日、別記事で紹介します。
今回は Android スマートフォンでデバッグした結果、セーブの処理自体が呼び出されない問題について対処します。
セーブ・ロードができない問題の対処
宝箱をタップしてスコアを増やしてから、一度アプリを閉じます。
再びアプリを起動するとスコアが初期値の 0 に戻っています。
原因の切り分け
オートセーブが動作していない原因として以下の4つが考えられました。
- セーブ処理自体が動作していない
- ロード処理が動作していない
- アプリが閉じられる際にセーブ機能が呼び出されていない
- アプリ起動時にロード機能が呼び出されていない
試しに、確実にイベント処理が行われているコインや宝石が飛び出す処理で、セーブ機能を呼び出すようにした apk を作成して実機デバッグを行うと、2回目の起動時に以前のセーブデータが読み込まれました。
このことから、3番の「アプリが閉じられる際にセーブ機能が呼び出されていない」が原因であることがわかりました。
アプリ終了に関するプロジェクト設定
メニュー「プロジェクト」→「プロジェクト設定」を選択して「プロジェクト設定」ウィンドウを開きます。
「一般」タブの「アプリケーション」→「構成」を選択します。
「プログラム終了を自動的に受け入れる」は既定値ではチェックされていますが、これを解除しないと NOTIFICATION_WM_CLOSE_REQUEST イベント通知を受け取れないようなので、チェックを解除します。
しかし、それだけではバグは修正できませんでした。
他サイト様「How to handle Android game closing in Godot 4? : r/godot」によると、スマートフォンによっていろいろな終了方法があり、終了を通知するメッセージを受け取れないこともあるようです。
そのため、アプリ終了のメッセージ以外、例えばバックグラウンドにアプリが隠れた場合などアプリ終了の少し前に置きそうなメッセージを受け取ったらセーブを行うようにしました。
修正前は、以下の3つのメッセージ ID が送られてきたらセーブ機能を呼び出していました。
# アプリ終了の条件とみなすメッセージ ID
var list_quit_message_id = [
# 閉じる
NOTIFICATION_WM_CLOSE_REQUEST,
# バックキー (android)
NOTIFICATION_WM_GO_BACK_REQUEST,
# バックグラウンド
#NOTIFICATION_APPLICATION_FOCUS_OUT,
]
修正後は、アプリがバックグラウンドに隠れた場合など、アプリ終了と直接関係しないイベント通知でもセーブ機能を呼び出すようにしました。
# セーブの条件とみなすメッセージ ID
# 終了処理のメッセージだけでは、 Android 実機では呼び出されないで終了することがあるため、別のメッセージでもセーブします。
var list_save_message_id = [
# 閉じる
NOTIFICATION_WM_CLOSE_REQUEST,
# バックキー (android)
NOTIFICATION_WM_GO_BACK_REQUEST,
NOTIFICATION_APPLICATION_PAUSED,
NOTIFICATION_APPLICATION_RESUMED,
NOTIFICATION_APPLICATION_FOCUS_OUT,
NOTIFICATION_APPLICATION_FOCUS_IN,
NOTIFICATION_WM_WINDOW_FOCUS_IN,
NOTIFICATION_WM_WINDOW_FOCUS_OUT,
# バックグラウンド
NOTIFICATION_APPLICATION_FOCUS_OUT,
]
以下は、前述したセーブする対象のイベント通知があればセーブして、アプリ終了のイベント通知があればセーブの後に終了処理を呼び出しています。
# セーブデータの保存先。 Windows の場合 user:// は %APPDATA%\Godot\app_userdata\プロジェクト名\ に保存されます。
var save_path = "user://TapTheTakarabako.save"
# セーブの条件とみなすメッセージ ID
# 終了処理のメッセージだけでは、 Android 実機では呼び出されないで終了することがあるため、別のメッセージでもセーブします。
var list_save_message_id = [
# 閉じる
NOTIFICATION_WM_CLOSE_REQUEST,
# バックキー (android)
NOTIFICATION_WM_GO_BACK_REQUEST,
NOTIFICATION_APPLICATION_PAUSED,
NOTIFICATION_APPLICATION_RESUMED,
NOTIFICATION_APPLICATION_FOCUS_OUT,
NOTIFICATION_APPLICATION_FOCUS_IN,
NOTIFICATION_WM_WINDOW_FOCUS_IN,
NOTIFICATION_WM_WINDOW_FOCUS_OUT,
# バックグラウンド
NOTIFICATION_APPLICATION_FOCUS_OUT,
]
# アプリ終了の条件とみなすメッセージ ID
var list_quit_message_id = [
# 閉じる
NOTIFICATION_WM_CLOSE_REQUEST,
# バックキー (android)
NOTIFICATION_WM_GO_BACK_REQUEST,
# バックグラウンド
#NOTIFICATION_APPLICATION_FOCUS_OUT,
]
# 通知イベントで呼び出されます。
func _notification(what):
if list_save_message_id.has(what):
# セーブデータを書き込みます。
print("セーブします")
save_app_data()
if list_quit_message_id.has(what):
# list_quit_message_id の要素のいずれかにあてはまる通知の場合は終了処理をします。
# 既定ではプロジェクト設定>アプリケーション>構成のアプリケーションの終了を自動で受け入れる(auto_quit_accept)が有効なので
# この処理は必要ありませんが、それを無効にしないと終了のメッセージが受け取れないため、無効にして終了処理を実装します。
get_tree().quit() # default behavior
return
User:// は Android で唯一の保存先で権限の追加も不要
今回のセーブ機能の修正の際に調べた有用な情報として
- Android では User:// から始まるパスだけが保存先として利用できる
- User:// から始まるパスへのファイルの保存には、 Android の権限を追加する必要がない
- ファイルへのアクセス権限として Android では以下のものがありますが、どれも必要がない
Read User Directory
Write User Directory
Read External Storage
Write External Storage
ことがわかりました。
参照:「Godot・Tips」「How to save game progress on android? – Archive – Godot Forum」
テスト
前回行ったように PC と Android スマートフォンを USB ケーブルで接続して、ファイル転送モードを選択した後、スマートフォンの内蔵ディスクのトップに、修正版の apk ファイルを上書きします。
以前インストールしたアプリをアンインストールしてから、インストールします。
新しくアプリをインストールして起動します。
初回起動時に宝箱をタップしてスコアを増やし、音量も変更しました。
その後、一度アプリを閉じてから開くと、スコアと音量の設定がロードされました。
まとめ
今回は、無料で軽快なゲームエンジン GodotEngine4 で作成したアプリを Android スマートフォンの実機でデバッグ実行した際に、スコアなどのセーブデータがオートセーブされないバグとその対処法について紹介しました。
Android では User:// 以降のパスにのみファイルを保存できることや、特に権限を追加する必要がないこともわかりました。
参照サイト Thank You!
- Godot Android library — Godot Engine (4.x)の日本語のドキュメント
- Godot: 終了処理の検知 – kidooom’s Scrapbox
- Godot・Tips
- How to save game progress on android? – Archive – Godot Forum
- OS — Godot Engine (4.x)の日本語のドキュメント#request-permissions
- EditorExportPlatformAndroid — Godot Engine (4.x)の日本語のドキュメント(Android Exportのオプションなど)
- あらためてRuntime Permissionと実装方法をおさらいする #Android – Qiita
- Save file in Android system storage · Issue #23004 · godotengine/godot · GitHub
- android – Activities still in back stack when launching activities with FLAG_ACTIVITY_CLEAR_TOP|FLAG_ACTIVITY_SINGLE_TOP – Stack Overflow
- Make save in godot for android – Godot Forums
- How do i save an image to android? So here is what ive got: a button that takes the viewport, slices is and saves it as a png. In permissions i have write external storage enabled. I also made sure to turn access to files on on my device, still didnt work. : r/godot
- Sending NOTIFICATION_WM_CLOSE_REQUEST does not actually trigger a quit when “Auto Accept Quit” is enabled · Issue #67379 · godotengine/godot · GitHub
- Best ways to save on quit – Help / Programming – Godot Forum
- Handling Quit Requests badly worded about mobile platforms · Issue #8474 · godotengine/godot-docs · GitHub
- Handling quit requests — Godot Engine (stable) documentation in English
- How to handle Android game closing in Godot 4? : r/godot
記事一覧 → Compota-Soft-Press
コメント