UWPでMonoGame - Gameオブジェクトへの引数渡し2021年04月08日 13:58

以前作成したXAMLベースのゲームアプリ(UWP)の使い勝手を改善しようと、ゲームエンジンの導入を考える。一度アプリ構築に使用したUnityが第一候補になるが、もう少し手軽で、XAMLページとの連携ができそうなMonoGameを試してみる。

引数の設定

MonoGameのUWP対応のプロジェクトを作成すると、生成されるコード群に、GamePage.xaml.csがあり、MonoGameの環境を生成するコードがある(L.40)。XamlGame<T>.Create() の部分。

最初の引数に parameter がある。設定のしかたは、"key:value"の形。複数ある場合は、空白で区切る。このあたり、MonoGameの文書に説明がなく、試行錯誤。

引数の取込

parameterの受け取りは、ゲーム本体のClass(Gameを継承)のConstrucorで行う(L.85)。Game.LaunchParameter(L.91)というCollectionに入っているので、foreachで取り出す。こちらは、Gameクラスの説明にある。

Navigateでの引数設定

実際の活用は、App.xaml.csからGamePageを呼び出す処理を変更し、別に用意するMainPageを介してGamePageに遷移するようにする。この時、MainPage→GamePage→MonoGameに引数を渡す。こうすれば、MainPageにゲーム選択や各種設定などのUIを担わせることができる。

MonoGameで各種UIを作成することもできなくはないが、いろいろな部品は手作りになる。

UWPでMonoGame - GameからXAML Pageへの復帰2021年04月08日 18:42

UWPでXAMLのPage(GamePage)から、引数付きでMonoGameのGameを起動することができた。次は、Gameから元のXAMLのPageに復帰する。

例外発生

Gameの終了は、Dispose()を呼び出せばよいようだが、UnhandledExceptionが発生し、アプリが終了してしまう。OnNavigatedFrom()に記述したデバッグ文が呼び出されているところから、XAMLのPageに戻ってはいる様子。

ログを見ると、Gameオブジェクトがなくなったのに、Mouse周りのイベントが刈り取られず、イベントの宛先がNullであると言っている(Disposeしたから当然だが)。これが致命傷になり、アプリの継続が不可になっている。

ちなみに、Exit()を呼び出すと、GamePageに戻ることなく、アプリが終了する。

イベント受信

本来は、MonoGame側の対処を望みたいところだが、何とか先に進めてみる。まず、Gameの終了をGamePage側から行うため、イベントを自作し、ゲームの終了をGameからGamePageに伝える。

そこで、GamePageを起動したMainPageにGoBack()で遷移する(L.70)。UIとは別Threadに居るので、Dispatcher.RunAsync() 経由。念のため、例外発生前に遷移指示を済ませる。

その上で、GameをDispose()する(L.84)。一つ前のSuppressDraw()は例外抑止に効果なし。発生するUnhandledExceptionは、ここのtry/catchでは拾えない。

例外ハンドラ登録

UnhandledExceptionを拾うために、App.xaml.csにハンドラを登録(L.32,33)。2つ登録しているが、MonoGameの例外を拾うのは、CoreApplication.UnhandledErrorDetectedの方。

例外ハンドラ

ハンドラの実体。CoreApplication.UnhandledErrorDetectedを受けるのは、CatchCoreUnhandledException()の方(L.133)。引数のargsには、Messageがないので、Propagate()で改めてThrow(L.147)。このあたりは、atmarkitの記事を参考に。

記事にあるように、VisualStudioのプロジェクトのPropertyで、条件付きコンパイルシンボルを設定しないと、Debugモードの実行では、アプリのハンドラの代わりにVisualStudioのデバッガが例外を捕まえるので注意。

Null Reference例外

すると、例外の実体が、NullReferenceExceptionであることがわかる。

こうして、UnhandledExceptionを受けとめると、例外でアプリが落ちることなく、GamePageから遷移したMainPageが無事に表示される。とりあえずは、これで先に進める。