ガルパン最終章 第3話2021年04月02日 18:21

第2話から1年半ほど。ARIAを観たばかりだけど、今度は幕張に出かける。

第3話

第2話で知波単とやり合っていたところから、再開。トーナメントの他の試合の様子を交えながら、次の戦いへ。ベスト4を決める戦い。この調子なら、第5話で準決勝、第6話で決勝、というところか。卒業する面子も紹介され、今のチームは残りわずか。将来を見据え、みほに頼りすぎない、チーム力を鍛える展開になると予想するが、如何。途中、沙織の携帯がInfobar(少し前の型か)だ、とちょっとうれしくなる。

花島公園

帰りは、花見川団地行きの無料送迎バスを降り、花島公園に寄り道。川沿いの桜が見事。

花見川サイクリングロード

舗装工事中だった、花見川サイクリングロードも竣工。走りやすい道に。

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が無事に表示される。とりあえずは、これで先に進める。

佐倉チューリップフェスタ、新川、やちよ2021年04月09日 19:08

コーディングをキリのいいところまで進めたので、天気が悪くなる前に出かける。

佐倉ふるさと広場

いつもの印旛沼のサイクリングコース。ほぼ中間地点の佐倉ふるさと広場。

チューリップフェスタ


チューリップフェスタ

平日とは思えない大勢の人出。

出店

出店もいっぱい。学校帰りの学生が遊びに来ている。

みんなのレストラン

足をのばして、道の駅やちよ。今日は、川向こうの農業交流センターのレストラン。残念ながら、お弁当屋さんは店をたたんだ様子。

外でペペロンチーノ

地場野菜のペペロンチーノとスープのセット。天気がよいので、レストラン前の広場で。スープは、名物のクラムチャウダーを期待していたが違った。改めて次回にでも。

鯉のぼり

広場には、鯉のぼり。もうそんな時期。

まだいるオオバン

帰りの新川沿いの道。オオバンたちが餌をついばむ。まだ、帰る気はなさそう。

沿道の桜もあと少し

沿道の桜は、ほとんどが葉桜。遅咲きの木が少しだけ。

UWPでMonoGame - 日本語表示でSurrogate Pairに苦戦2021年04月13日 16:14

MonoGameで日本語を表示する方法は、あちこちに記事がある。

FontProcessor

MGCB EditorでSpriteFont定義に設定するProcessorをDLLとして作成。漢字やかなの入ったテキストファイルから一文字ずつ取り出し、FontDescriptionに登録。,NET Core 3.1のDLLのプロジェクトで作成したもので登録成功。

SpriteFont生成

常用漢字について実施したもの。左の"Processor"欄で、作成したProcessorを登録する。規格が合っていないと候補に出てこない。実行には、そこそこ時間を要す。

Surrogate Pair生成失敗

それではと、難読漢字の入ったテキストファイルを取り込んでみると、エラー。
Surrogate Pair (2バイトのコード2つで一文字を表現)
をバラバラに登録しないでね、Char配列で渡してね、と。

ところが、FontDescriptionに登録できるのは、Char型のみ。MonoGameのForumなどを覗いても、影響が大きいので対応は難しそう、とのこと。

LoadContent

それではと、先のForumでも触れられていた、FontStashSharp(SpriteFontPlus)を試してみる。コメントアウト済みだが、L.190あたり。LoadContent()では、フォントファイルを登録。

DynamicSpriteFont

Draw()では、DynamicSpriteFontを定義して、描画(L.566-567)。Surrogate Pairは試さなかったが、日本語表示は問題なくできる。

問題は、配布Packageにフォントファイルを同梱しなければいけないこと。IPAフォントのライセンスを読むと可能ではあるが、サイズも大きくなるし、どうしよう。UWPでなく、WPFにすれば、システムフォントを読み込めるかも。そもそも、今まで使ってきたUDデジタル教科書体を使いたい。

Win2DでTexture2D生成

結局、実行時に、Win2DでCanvasDeviceに日本語文字を書き込み(L.164)、Stream経由でTexture2Dを生成(L.182)することで対処。PutText()は縦書き表示のためのもの。

MGCB Editorで事前生成するわけではないので、実行時、それなりに時間を要する。ゲーム実行時のスコア表示などには向かないが、ゲーム開始前に作っておけば済むものなら使える。

464経由で手賀沼、吉高の大桜2021年04月16日 20:10

前回、桜を見に行ったとき、464(北千葉道路)のアップダウンはなんとかなりそうだったので、こちら経由で手賀沼に向かってみる。小林、木下ルートは、木下駅付近が難所だったので。

田植え

近所では早、田植えが始まる。

亀成川

464を印西牧の原の手前で右に降りて、亀成川。

川沿いの道

川沿いに平坦路を進み、手賀川に向かう。残念ながら、未舗装道が多い。比較的土の道なのが救い。

下手賀沼

下手賀沼。付け根を渡る。

用水路の白鳥

手賀川の用水路に白鳥。すっかり住み着いている。

草むらの黒猫

手賀川の河川敷の草むらに黒猫。猫は野鳥を襲うので、可愛いとばかりは。

手賀沼緑道下側の始点

手賀沼の下側の緑道の始点。

手賀沼

あいにくの曇り空だが、雲の形が面白い。

手賀沼

手賀大橋を渡って、水の館へ。

お昼

あいにく、レストランは満席。年配の方中心に、人出が増えてきた。直売所でサンドイッチ。

吉高の大桜

復路はせっかくなので、吉高の大桜へ。すっかり葉桜だが、葉が茂り、大木の貫禄が増す。

結果、距離はあまり変わらず。未舗装道があるが、のんびりいける。

HubSectionのDataTemplate定義内のRadioButtonやComboBoxの初期設定2021年04月19日 16:27


Hubで構築した設定画面

Hubで構築した設定パネル。設定のHubSectionにおいて、RadioButtonで設定を指定する。HubSectionは、DataTemplateで定義するので、x:Nameで指定した名前を使っては、RadioButtonなどの初期設定を行えない。

そのため、Bindを用いて、コードの値を反映させるのだが、XAMLの初期化時に、初期値(デフォルトの値)でもってCheckedのイベントが発生し、Bindすべき変数の値を、別の値で上書きしてしまう。RadioButtonのほか、ComboBoxなども同様。

ここは、Checkedのイベントの発生を、本来設定したい値をBindしてからにしたいところ。

XAML定義

巷の記事では、XAMLのTreeをたどって初期設定する力業なども紹介されているが、個々のコントロールのLoadedイベントを受けての処理で対処できそう(L.111)。

イベントハンドラ

RadioButtonのLoadedイベントを受けるコードで、IsCheckedを設定して、roamingSettingsなどから読み取った値を初期値として設定(L.200)。その後、Checkedのイベントが発生するが、先ほど設定した初期値でのイベントなので、別の値で上書きされない。