1 ポイント 投稿者 GN⁺ 2023-09-18 | 1件のコメント | WhatsAppで共有
  • 『Caves of Qud』は長年のUnity依存を取り除き、Godot上でゲームコアをビルド・起動する技術検証を進めており、当面の目標はモダンなVFXやUIなしでASCII+タイルモードで動作させること
  • 作業はタイルアセットの取り込み、コアC#アセンブリの移植、レンダリング・入力リグの構築に分かれており、古いBMPタイルファイルはPNGに変換してGodotへ読み込ませた
  • 初期ビルドの5,641件のエラーは、GeneratedCode、ConsoleLib、Genkit、Language、HistoryKit、Newtonsoft JSON、CodeDomなどを移しながら減っていき、UnityEngine依存の表面はスタブで狭めていった
  • UnityのColor、GameObject、AudioSource、Debug.Log、Screenの使用箇所はUnityEngineReplacerと代替クラスで処理し、PlayFabやUnity UIに近いchargen・presentation層は一時的に外すか、glueモジュールとして分離候補に残した
  • 結果として約50万行のC#ゲームコアがGodot上で起動し、フレームを供給して入力待ちになる段階に到達したが、レンダラー・入力ハーネスやVFX・サウンド・UIのリギング作業はまだ残っている

UnityからGodotへ移す作業範囲

  • 移植作業は3つに分かれる
    • アセット取り込み: タイルアセットをGodotプロジェクトに入れる作業
    • コアアセンブリ移植: UnityではないメインゲームエンジンであるXRL Applicationと、エンジン側のGameManagerを移す作業
    • レンダリングリグ構築: コア起動後に画面出力と入力を接続する作業
  • Godotの“mobile”プロジェクトを作成し、Qudのテクスチャコンテンツをプロジェクトのルートフォルダにコピーした
  • Godotが古い**.bmpファイル**を扱えないため、ASCIIタイルを含むファイル群を一括でPNGへ変換した
  • 変換後はアセットを読み込めたが、インポート進行表示が出るまで約30秒かかった

ビルドエラーを減らしながらコアアセンブリを移す

  • XRL Applicationをコピーした後、GodotでC#プロジェクトとソリューションを生成し、初期状態では5,641件のエラーが発生した
  • ConsoleLibGenkitのような汎用ライブラリは丸ごと移し、古いスプライト・アトラシング用ソリューションのKoboldは、ファイルごとに必要性を確認しながら取り込むことにした
  • KoboldJSONは単純なJSONシリアライズライブラリなので、そのまま移した
  • Colorの使用箇所85件を全体置換したことで、エラーは4,700件まで減った
  • 抜けていたGeneratedCodeフォルダを追加すると、イベント別クラスのコード生成結果が含まれ、エラーは1,557件まで減少した
    • Caves of Qudは、ボイラープレートの多いイベント別クラスをコード生成し、性能と強い型付けのイベント表面を得る構造になっている

Unity依存とglue層の整理

  • Embark Builderとキャラクター作成chargenにはUnity UIコードが多く、初期のASCII技術検証では削除した
    • コンソール版はまだないが、初期検証はセーブデータのロードやランダム開始でテストできる
  • Gameフォルダは大部分がUnityとゲームの間のglueだが、CodeGenerationのようにglueではないフォルダもあるため、別ルートやPlatformフォルダへ移す方針を取った
  • LanguageHistoryKitライブラリを移し、エラーは454件まで減った。完全ではなくてもgame/glue分離ができていたことが助けになった
  • 残る大きなエラー分類は、CodeDom/RoslynPlayFabHarmony、一部のコンパイラ関連問題、そしてゲーム層へ漏れ出したUnityEngine表面だった
  • PlayFab関連コードは一時的にコメントアウトし、glueモジュールへ上げる候補として残した

Unity API代替スタブとGodot C#の違い

  • Color32はbyteベースの色型なので、すぐに代替実装を書いた
  • UnityEngineReplacerフォルダを作り、Unityのドキュメントやコード参照なしに、コンパイルエラーを見ながら必要な表面だけを実装した
  • GameObjectスタブを作ると、「GameObjectが分からない」というエラーが実際に必要なフィールドやメソッドのエラーへ変わり、ゲームが使っているインターフェース表面を把握できた
  • AudioSourceもエラー一覧を見ながらアクセスされるメンバーを1つずつ追加し、ゲームが実際に使う完全なAudioSourceポートインターフェースを完成させた
  • そのほかに処理した表面は以下の通り
    • **Debug.Log**の代替shim
    • Screenの代替実装
    • IsNullOrEmpty拡張メソッドライブラリの移植
    • Math参照とPI/Piの違いへの対応
    • GodotのXYという大文字座標名の違いへの対応
    • System.Drawing.ColorSystem.Numerics.Vector3がIDEによって誤ってimportされる問題の整理
  • Newtonsoft JSONはVisual StudioでNuGetパッケージを追加して解決し、CodeDomもCodeDom NuGetパッケージで解決した

Godotで完全起動するまで

  • エラーが11件まで減った時点で残っていた問題は、mod managementの動的C#コンパイル関連コードで、必須ではないが複雑なため最後まで残った
  • その後、リンク段階とスタブフィールドのエラーを処理し、約**50万行のC#**コードがビルドできた
  • 次の段階は小さなレンダラーと入力ハーネスを作ってコアアセンブリを起動することで、目標はASCII+タイルモードでゲームを実行可能にすることだった
  • Godotで空のsceneを作り、基本nodeにGameManager.csを付けた。GameManagerNodeを継承し、partialコードが必要だった
  • Godotの_ReadyはUnityのAwake_ProcessはUnityのUpdateに対応する形で使った
  • 初期化過程ではload pathとmod managementを移し、型resolverが名前で型を見つけられない問題をprintf方式で追跡した
  • 原因はdynamic assemblyの処理だった
    • mod assemblyがdynamicのため、main assembly検査でdynamic assemblyを除外していた
    • Godot editorではmain game assemblyもdynamicのため、型探索対象から外れていた
  • 修正後、完全起動に成功し、50万行規模のゲームコアがフレームを供給しながら入力待ちする状態になった
  • 残作業は“just work”と表現されたが、実際にはVFX、サウンド、UIリギングにかなりの作業量が残っている

1件のコメント

 
GN⁺ 2023-09-18
Hacker Newsのコメント
  • このゲームはほぼ全て独自エンジンを使っていて、Unityはハードウェア抽象化レイヤーと移植用の枠組みとしてだけ使っているようなので、移植の難易度という面では最良に近いケースに見える
    こういうゲームは意外と多いけれど、もちろん大半のUnityタイトルを代表するものではない

    • その通り。あるインタビューで、Qudは当時Unityの中でコンソールアプリのように動いていると言っていたことがある
      UI刷新後もまだそうなのかは分からないが、もしそうなら、MonoGameに移植してコストを抑えなかったのがいつも不思議に思えた
    • Unityの基本コンポーネントは、長期的にはほとんど全て役に立たなくなる結果だと思う
      Androidも似ていて、OSはカメラ検出や暗号化のようなものを置き換えるライブラリを呼び出す用途にしか使われなくなり、ある日、OSは実質的に薄い金属層とブートローダーにすぎないのだと気づくことになる
  • https://nitter.net/unormal/status/1703163364229161236

  • うわあ、本当に素晴らしい。この移植プロセスを段階ごとに見られるのも良いし、かかった時間もかなり妥当で驚いた

    • Godotは機能はずっと少ないけれど、学ぶのは本当に簡単だと思う
    • Caves of Qud特有のビジュアルの雰囲気をGodotでどう実現したのか見てみたい
  • カスタムコードが非常に多く、エディタ機能をあまり使わない構造なら、エンジンの代わりにレンダリングライブラリを使ってもよさそう

    • 複数プラットフォームで同時にゲームを出したいなら、プラットフォームごとのレンダリング・サウンド・入力コードを直接扱うのはすぐに面倒になる
      土台にエンジンがあれば、こうしたものを無料で手に入れられる。Unityなら費用が発生するかもしれないが
    • すでにレンダリングライブラリを使っている。名前は「Unity」だ
  • Brianがどう考えているのか気になるなら、この動画を見るとよい: https://www.youtube.com/watch?v=U03XXzcThGU
    以前ここで多くを学んだ

  • 最近のDHHのTypeScript論争を思い出す
    静的型付けなしでこういう移植をすると想像してみると、変更のたびにビルドして実行し、クラッシュを探さなければならない。こういう時には、リファクタリングしやすい言語と良いアーキテクチャで作っておいたことが本当にありがたくなる

  • Twitterアカウントを持っていないんだけど、何が起きているの?