MonoGame で制作したゲーム「リトルセイバー」を Web (Blazor + WebGL) で動かしてみた話 その2

image

前回の投稿

今回の記事は前の投稿の後日談になるので前回の記事を読んでいない場合は読むことをお勧めします。

nkast.Xna.Framework.Blazor がバージョンアップされました!

ゲームフレームワーク「MonoGame」で作ったゲームを Blazor で動かせるライブラリ「nkast.Xna.Framework.Blazor」が 3.8.9100 から 3.8.9101 にバージョンアップされました!

数字を見るとマイナーバージョンアップのように見えますが、内容的にはかなり大きな改善が入っています。改修内容を見てみると私が報告した不具合と、なんと私が書いたブログの内容がいくつか反映されているようでした。

主なバージョンアップ内容

バージョンアップ内容についてはコミュニティの以下の投稿に書いてあります。(一部私宛の返信の内容になっています)

バージョンアップ内容を簡単にまとめると以下のようになります。

  • SpriteBatch のパフォーマンスが大幅に向上 (←これがすごい)
  • SoundEffect.Volume の設定が反映されない不具合修正
  • DXT3 圧縮がサポート

まず SoundEffect.Volume の不具合が直ったのでわざわざ音量を調整した音声ファイルを用意する必要はなくなりました。さすがにそれは面倒なのでやっていませんが。こちらはコミュニティに報告した内容が反映されています。

DXT3 圧縮もサポートされたので、SpriteFont などのコンテンツを作成する際にわざわざ別なフォーマットを選択する必要がなくなりました。こちらはなぜかブログに書いていた内容が反映されています。

そして一番影響が大きいのが SpriteBatch のパフォーマンスが上がったことです。プログラムを変更することなくライブラリを更新するだけで 2D のゲームのパフォーマンスが大幅に上がります。どのぐらいパフォーマンスが上がったかは動画を上げましたので前回の動画と比較して見てみてください。

プレイ動画

以下は前回、バージョン 3.8.9100 で作成したゲームを動かしてみたときの動画です。動画の内容は前回と同じものです。

ニコニコ動画

Youtube

そして今回、バージョン 3.8.9101 に更新してゲームを動かしてみた動画が以下になります。

ニコニコ動画

Youtube

見てもらえれば一目瞭然ですが、ちょっとどころではなく数倍ぐらいパフォーマンスが上がっているように見えると思います。パフォーマンスが上がっていると行ってもさすがにネイティブに比べれば劣りますが、多少低スペック向けにゲームを調整すれば Blazor 版でも十分に実用に耐えられるゲームが動かせると思います。

バージョンアップの経緯

今回 Blazor 版で実装するにあたりライブラリの中の `SoundEffect.Volume` で不具合を見つけたのでコミュニティの Blazor のスレッドで報告しました。Blazor 版のライブラリはお試し版であることもあり、せっかくゲームを動作させてみたので Blazor で動かしてみたらこうなったよ、という動画も一緒に作って投稿しました。動画にはブログのリンクも付けてあります。

その後コミュニティで nkast さんから返信を頂いたのですが、回答を頂いた内容を見るとコミュニティに投稿した内容や動画の内容だけではなく、私がブログに書いた内容についても回答を頂いていました。本人に確認したわけではないので本当かどうかは分かりませんが、おそらく日本語で書いたブログをわざわざ読んでいただいたんだと思います。

前回の調査内容に対しての相違点

先述の通り、nkast さんに前回の記事を読んでいただいたらしく、いくつかの調査内容は正しくないものがあるようでした。以下相違点について記載します。書いてる内容はコミュニティで回答いただいたものと同じです。

Effect (.fx) コンテンツはシェーダモデル 2.0 まで対応可能

前回 Effect コンテンツはサポートされていないと書きましたがシェーダモデル 2.0 までなら対応されているようです。確かに私がゲームで使用していたのはシェーダモデル 4.0 なので対象外ですね。

ちなみにシェーダモデル 2.0 にしたら動きました。

Load 用コンテンツ (.xnb) の配置場所

こちらについてはコンテンツを実行ファイルに埋め込むか、静的ファイルとして `/wwwroot/Content/` に配置するかの2択であることは前回説明した通りです。

`/wwwroot/Content/` に配置した際にうまく読み込めない件については Web サーバーで .xnb ファイルの MIME タイプを 'application/octet-stream' にするとうまくいくという回答を頂きました。ただ、こちらは試していないので実際に使う方は正しく動くか確認してみてください。

SpriteFont.Characters は使えない

どうやら Blazor 版では `SpriteFont.Characters` の代わりに `SpriteFont.Glyphs` を使うようです。現在 MonoGame の正式版では `SpriteFont.Characters` が使われてるので今後 `SpriteFont.Glyphs` に置き換わる可能性はあるかもしれません。

まとめ

前のバージョンでは Blazor+WebGL で高負荷のゲームを動かすのはなかなか難しいという印象を受けましたが、今回のバージョンアップで2Dスプライトの描画性能が飛躍的に上がったので、Web 上でゲームを動かすのもかなり現実味を帯びてきたと思います。パフォーマンス的には Silverlight + XNA に近いレベルになったのではないかと思います。これなら体験版としてゲームを作って Web で公開するという方法も行けそうな気がしました。

ゲームデモ版 Ver 0.40 公開予定について

最近は制作動画のほうの更新もなかなかできずにいたので情報公開がしばらくできていなかったのですが、一応プログラムのほうはちまちまと作っていました。Ver 0.40 は「この機能を入れる!」っていうような新機能はなかったのでどのあたりまで作りこむか迷っていたのですが、とりあえず各機能が問題ないレベルまで動くようになったのでそろそろ Ver 0.40 を公開しようかと思います。

現在のゲームイメージは下のようになります。

2017-04-21 22_17_57-ゲームデモ Ver 0.40 - β版開発室 - ソーサリーフォース - Internet Explorer

ゲームの操作方法や各説明についてはゲーム公開ページに載せる予定なのでここでは記載しません。

Ver 0.30 では2ステージから選択できていましたが、今回は1ステージのみとなっています。その代わり、ゲーム開始時に難易度を3種類から選択できるようになっています。ちなみに Ver 0.40 の難易度は過去3バージョンに比べるとかなり難しくなっていると思います。

難易度で「普通」を選択した場合でも、立ち回りをうまくしないとクリアが困難になる可能性があります。「簡単」を選択すれば相変わらず仲間が勝手にどんどん敵を倒してくれます。「難しい」を選択するとジリ貧状態まで追い込まれるので、作者自身がプレイしてもなかなか難しかったです。

ちなみに私が各難易度をクリアした結果は下のようになりました。神プレイを狙ったわけではなくとりあえず1回クリアしてみたものです。

2017-04-22 19_09_10-OneNote

2017-04-22 19_02_53-OneNote

2017-04-22 18_50_07-OneNote

「易しい」「普通」はそれなりの結果でクリアできたと思いますが、「難しい」はクリアに27分もかかってしまいました。敵の数に対して仲間が圧倒的に少ないので余計に時間がかかります。

今回のデモ版のクリア条件はすべての敵を倒すことです。ボスはいません。しかも敵は赤色と黄色がいるので、片方だけ攻めているともう一方に攻撃される可能性もありますので、マップを見て現在の状況を把握する必要があります。

ゲームのパフォーマンスについてですが、60FPS を出すのが結構難しい状態になっています。私の環境でゲームの設定を変えずにプレイした場合、敵の数が画面内に多くなったりすると40FPS ぐらいまで落ちてしまいました。試しに GPD WIN でプレイした場合は 20FPS でした。

一応負荷軽減対策としてゲーム開始前のオプションでユニットの配置数を変えることができるようになっています。もしまともにプレイできないようであればユニットの配置数を減らしてプレイしてみてください。逆にもっとユニットを出したい場合は増やしてみるのもいいかもしれません。

2017-04-22 21_15_23-OneNote[3]

ちなみにパフォーマンスがでない理由についてはよくわかっておりません。おそらくですが、ゲームプログラムが Internet Explorer を介して動いているため、その分余計なオーバーヘッドがかかっているのではないかと思っています。ちなみに UWP でも同じプログラムを使って動かしていますが、こちらの方は2倍程度高速に動いている感じです。

一応パフォーマンスを改善できる点はまだあるのですが、今後もまだ機能を追加するものがあるので、そちらの負荷が上がったときに改善しようと思っております。今回も開発版なのでそこまで最適化を行っているわけではありません。

今後の予定について

プログラムのほうは動作確認を残しているだけなので、早いうちに公開できると思います。その前に今回のバージョンに向けての制作動画を2本撮ったので、先にそちらの方の編集を行って公開した後にゲームを公開しようと思っております。

ちなみに Ver 0.40 になってもいまだに Game Demo  というタイトルなのですが、今はシステム構築がメインなので、Ver 0.50 公開あたりまではたぶんこのままだと思います。コンテンツなどは後半に行う予定です。

]]>

ゲームデモ版 Ver 0.20 について

結構時間がかかってしまいましたが、ようやく公開できそうな段階まで出来上がってきました。都合がつけば今週中ぐらいにはアップできると思いますが、仕事がやたら忙しいため、下手すると次の週末になりそうな予感もしています(実際その確率のほうが高い)。

変更内容とかは公開したときに書きたいと思いますが、Ver 0.20 からは GPU 処理に代わりますので、ゲームを始める前に1回 Silverlight の設定を変更する必要があります。変更方法については公開後に、該当ページに説明を入れておきます。1回設定すれば、ほかのバージョンを公開した場合でも再設定の必要はありません(同一ドメインならそうだった気がします)。

パフォーマンスは想定していたよりはいい感じです。まあ結構アルゴリズムの最適化を行ってきたのでそうでないと割と困るのですが(^^;)。一応持っているデスクトップPCとノートで動かしてみましたがほぼ問題ありません。どちらも割と高スペックなのであまり参考にはならないのですが…。試しに DELL の Venue Pro 8 のタブレット PC でも動かしてみたのですが、たぶん 30FPS ぐらいでスムーズに動いている感じでした。ただ Ver 0.20 はまだキーボードしか対応していないので、ちーたんタッチボードを起動して無理やり操作したのですが。

続きは時間が取れた時に。下に載せたイメージは開発中の画面です。

2

]]>

ゲーム開発進捗 2016/02/12 またまたGCとパフォーマンス

どういった場合に GC の対象となるか調べてコードをいくつか改善してみました。おおざっぱなキャプチャしかとってなかったのであんまり参考にならないですが、改善前はこんな感じ。

2016-02-07 11_11_05-CpuGameDanke1UAP - Microsoft Visual Studio

10秒の間に2~4回ぐらい GC が発生していました。

改善した結果がこちら。

2016-02-11 20_12_39-CpuGameDanke1UAP - Microsoft Visual Studio - コピー

10秒に1~2回ぐらいまで抑えられました。まだ改善できそうな箇所があるのでもう少し頑張ってみます。

まあ GC の発生を改善すれば処理速度向上するかなーと思ってたんですが、気持ち程度でしたね。ただ、確実によくはなっていると思います。

とりあえず現状のパフォーマンスでユニットをたくさん出してみました。

2016-02-11 23_57_23-CpuGameDanke1UAP.Windows - コピー

ユニットがどれだけいるかわからないのですが、一応開発マシンでは FPS が 50~60 でている感じです。ただ、開発マシンはスペックが高く、ノートでやると明らかに落ちているのでまだまだ改善しないといけないですね。というかそもそもこんなにユニット出すのかっていう前提もあるんですが (^^;)

ロジックを最適化する場合、たいていは無駄な判定とか減らすのですが、それをやると正常に動かなくなることが割と多いです。これを直すのに意外と時間かかったりしますね。

]]>

ゲーム開発進捗 2016/02/07 GC とパフォーマンス

来週艦これのイベントが始まるということで、イベントが始まる前にマンスリー任務やEOステージのクリアをやってたのでゲーム開発のほうはあまりはかどりませんでした。それよりもどんどんたまっていくアニメの録画の消化をどうにかしたい…。

さてゲーム開発のほうですが、現在は Ver 0.20 の公開に向けて作っています。ですが、ちょっとパフォーマンスに難ありな状態なので、機能の作りはおいておいてメモリ管理のほうを少しやってました。

Visual Studio 2015 には診断ツールがあり、メモリの使用状況や CG の発生タイミング、メモリのスナップショットなどを見ることができます。

2016-02-07 11_11_05-CpuGameDanke1UAP - Microsoft Visual Studio

ゲームの場合ツール系とは違い、常に処理が回っているのでメモリ(インスタンス)の確保が常に発生します。C言語のような完全なネイティブプログラムの場合、自身でメモリの破棄タイミングを指定しなければならないので、メモリリークさえ気を付ければ GC なんて考えなくてもいいのですが、今回 C# でゲームを作っており、確保したメモリの破棄はほぼすべて GC に任せることになります。

ゲームループ中に GC の発生を抑えることはほぼ不可能です。事前に必要なメモリを確保しておき、その中でやりくりするという方法がゲームでは主流ですが、マネージドなプログラムだと、文字列処理を行うだけで GC 対象になるので相当気を使います。

とは言ってもあまり余計なインスタンスを作成さえしなければ、GC が発生してもゲームに影響することはそんなにありません。上の図で何回か GC が発生していますが、メモリが平行に進んでいる部分のGCは大体ジェネレーション1のものです。1回当たりにかかる時間はミリ秒単位。うまく作ってればコンマミリ秒まで落とせるので支障はあまりないと思います。

ただ、別のシーンに切り替えたときなどに例えば大きな規模の初期化処理などを行うとジェネレーション2が使用されます。これを放置しておくとゲームの最中で突然一気に解放されたりします。これにかかる時間が100ミリ秒単位だったりするので、その間完全にゲームが停止します。リアルタイム性が求められるゲームの場合致命的です。上の図でも途中で一気にメモリが解放されていることが分かります。

変なタイミングで発生されても困るので、初期化処理が終わったらとっとと GC.Collect を呼んで解放してしまうのがいいと思います。

2016-02-07 22_38_37-CpuGameDanke1UAP - Microsoft Visual Studio

プレイヤーが操作中に止まるよりは、次のシーンが始まる前の真っ暗な画面なんかで実行したほうがいいですね。操作中に0.5秒止まるよりは真っ暗な画面で0.5秒止まってたほうが、ユーザーは全然気にならないと思います。

]]>