play the jitoh-san

play the jitoh-san(プレイザジトーさん)とは

Godot 4ゲームエンジンを使ってジトーさんのことをちょっとブンドドして遊べるものにしてみようという自己満足的企画。ゲームボーイライクの2Dアクションで、スプライトからできるだけ自分で用意してやってみようというおべんきょう企画でもあります。

プレイザジトーさん4月号(5/5)
※STAGE 3(山)

※ブラウザでいますぐ遊べます。
 30MB強あるのと、キーボードがないと操作ができないので注意。
 タイトル画面進行:Enter
 移動:左右/AD
 ジャンプ:X/スペース
 攻撃(10ダメージ):Z
 追撃(5,5,10ダメージ):攻撃モーション中にZで攻撃終了時
 調べる:上/W
 溶ける:下/Sを押しっぱなし(空中・上に障害物がある場合は離していても持続)
 ステージクリア後・終了後:キャラモーション後にZ/X/Enterで進行

以下技術的なメモとかいろいろ。

旧バージョン

プレイザジトーさん3月号
※STAGE 2(森)

プレイザジトーさん2月号
※フォント・エネミー・アイテムを実装、STAGE 1(屋敷)

プレイザジトーさん1月号
※基本的な動作、STAGE A(城)

Godot4 Webエクスポートで必要なもの

詳しい解説は公式と参考文献のほうを確認されたしですが、Godot4のWebエクスポートを動作させるためにはページ表示時のサーバからのHTTPレスポンスヘッダに特定ブラウザ機能の許可をしておく必要があります。

許可の指定は.htaccessで行えますが、以前WordPressの特定のファイルアクセスを封鎖する際に記入したwordpress-htaccess.confが今回も使えるので、

sudo vi /opt/bitnami/apache/conf/vhosts/htaccess/wordpress-htaccess.conf

こちらで開いて末尾に以下のように指定を追加してあります。

<Directory "/opt/bitnami/wordpress/godot_files/">
Header set Cross-Origin-Embedder-Policy "require-corp"
Header set Cross-Origin-Opener-Policy "same-origin"
</Directory>

※/opt/bitnami/wordpress/はこの構成のwebrootです。WordPressとの衝突がないようGodot公開用ディレクトリとしてgodot_filesディレクトリを作成し、そのディレクトリのみを対象としてあります。サーバ全体にかけても害はなさそうですが一応くらいのそれ。

カスタムテンプレート

大まかに言うと、Godotで出力した実行ファイルは形式に関わらず(Windows用のexeファイルであろうと、WEB公開用のwasmファイルであろうと)実態としてはGodotエディタが丸々入っている形になっています。そのエディタ部分がテンプレートと呼ばれるものなのですが、公式が提供しているテンプレートはエディタの機能がすべて入っていますので、ゲーム内で使用されていなくても3Dだのネットワークだのファイルタイプ対応だのが含まれています。

中でもFreeTypeとmbedTLSとENetはライセンス表記の必要なモジュールなので、ライセンス表記を削ったり容量を減らそうと思った場合はGodotエディタ自体をソースからコンパイルしなおし、テンプレートを作成する必要が生じます。

今回はWEB公開用のwasmファイルを出力したいだけなので、先達の内容に沿いまして以下の手順をざっと進めておきます。

  • Python 3.12.2のインストール
  • Emscripten SDKのインストール
  • Godot 4.2.1のソースコードを用意
  • 公式のプラクティスに沿って除外するモジュールの指定をgodotのソースフォルダにcustom.pyとして配置
    いろいろ試行錯誤したのですが、今回は結局プラクティスページの例として掲載されているものに上部5点を加えたものとしました。
disable_3d = "yes"
disable_advanced_gui = "yes"
module_freetype_enabled = "no"
module_text_server_adv_enabled = "no"
module_text_server_fb_enabled = "yes"

module_basis_universal_enabled = "no"
module_bmp_enabled = "no"
module_camera_enabled = "no"
module_csg_enabled = "no"
module_dds_enabled = "no"
module_enet_enabled = "no"
module_gridmap_enabled = "no"
module_hdr_enabled = "no"
module_jsonrpc_enabled = "no"
module_ktx_enabled = "no"
module_mbedtls_enabled = "no"
module_meshoptimizer_enabled = "no"
module_minimp3_enabled = "no"
module_mobile_vr_enabled = "no"
module_msdfgen_enabled= "no"
module_multiplayer_enabled = "no"
module_noise_enabled = "no"
module_navigation_enabled = "no"
module_ogg_enabled = "no"
module_openxr_enabled = "no"
module_raycast_enabled = "no"
module_regex_enabled = "no"
module_squish_enabled = "no"
module_svg_enabled = "no"
module_tga_enabled = "no"
module_theora_enabled = "no"
module_tinyexr_enabled = "no"
module_upnp_enabled = "no"
module_vhacd_enabled = "no"
module_vorbis_enabled = "no"
module_webrtc_enabled = "no"
module_websocket_enabled = "no"
module_webxr_enabled = "no"
module_zip_enabled = "no"

disable_3d = “yes” … 3D機能。今回は使わないのでyes
disable_advanced_gui = “yes” … TextEditノードなど。いまは使っていないのでyes
module_freetype_enabled = “no” … FreeType。TrueTypeやOpenTypeといった形式のフォントを使用する場合に使う。通常はnoにしないほうが便利なものだが、今回はフォント画像を自分で描いて表示しているためno
module_text_server_adv_enabled = “no” … 逆順のような複雑なテキスト処理を行う場合。行わないのでno
module_text_server_fb_enabled = “yes” … text_server_advを無効にしている場合はこちらのtext_server_fbを有効にしないと文字が表示できなくなるのでyes

また、以下の2点がそれぞれENetとmbedTLSの無効化にあたります。
module_enet_enabled = “no”
module_mbedtls_enabled = “no”

準備が整ったらセットアップ&コンパイル。コンソールでEmscriptenディレクトリ側で

emsdk.bat install latest
emsdk.bat activate latest

コンソールに一時的にPATHが通るので、そのままgodotディレクトリ側で

scons platform=web target=template_release javascript_eval=no

するとgodotディレクトリ配下のbinディレクトリに godot.web.template_release.wasm32.zip ができるので、このzipファイルが「カスタムテンプレート」になります。
※なんか”attempt to add bitcode file after LTO.”で怒られて完了しないことがありますが、PC再起動したら直りました。なんなんだ…

0.2.13版でjitoh_2.wasmが33.9 MBから24.0 MBまで削減できました。6割ちょい。容量もさることながら、FreeTypeとmbedTLSとENetが無効化できたのでライセンス表記を減らすことができたので目標達成といったところ。

ジトーさんの攻撃力に関するメモ

ジトーさんの攻撃ダメージ判定は攻撃モーション時にのみdisable=falseとなるArea2Dノードへのbody_enteredシグナルによってエネミー側のhit()メソッドを実行することで発生する。そのためよほど特殊な動き(入って出て入ってを判定発生中に行われる)でない限り多段ヒットすることはない。攻撃・追撃モーション中はキー操作による移動も受け付けないため操作によって誘発することも難しいはず。

攻撃:発生3F、持続18F、ダメージ10 … 21Fで10ダメージ(攻撃DPS28.6)
追撃①:発生6F、持続8F、ダメージ5
追撃②:発生1F、持続8F、ダメージ5
追撃③:発生1F、持続6F、硬直6F、ダメージ10 … 36Fで20ダメージ(追撃DPS33.3)
※ただし、攻撃の持続終了後に踏み込まれた場合、追撃②の発生までの15F(0.25秒)で10ダメージを稼げないので、HP10以上のエネミーや弾だと被ダメでのキャンセルされる可能性がある。攻撃の持続が18Fと長く硬直を持たないのであまり表面化しないが、ここを調整すると結構な隙になるかもしれない。

なお、エネミーからの攻撃ダメージ判定はシグナルではなく_physics_process()ごとにget_overlapping_bodies()で検出してジトーさん側のhit()メソッドを実行することで発生するようになっている。そのためフレームごとにhit()メソッドは動作するが、無敵時間で無効化されるようにしてあるため多段ヒットしない。これは無敵時間が切れるまでエネミーと重なり続けた場合に再度ダメージを食らうようにするためと、複数のエネミーに同時衝突するとあっという間にHPがなくなってしまうためこのようになっている。

参考文献

Godot Engine 4.2ドキュメント
Peanuts Code様
WorkToolSmith様「ド基礎からのGodot」
【Godot Engine】カスタムテンプレートを作成する方法
and 星のカービィ(主に初代の挙動とデザインを参考させてもらっています)