Unityワークフローのスケーリング:中規模から大規模プロジェクトからの教訓

本ブログ記事は、Mega Cat Studiosによるシリーズの第1弾であり、彼らのUnityに関する専門知識と、実際の商用ゲーム開発における課題に対するソリューションを共有します。入力、レベル、環境デザインを網羅した本シリーズの他の記事もぜひご覧ください:
- 千本ノック:Unityのイベント駆動型Input SystemがBackyard Baseball 2026の操作をどのように強化しているか
- レベルデザイン、ワールドビルディング、VFXを用いて、新しい世代のためにクラシックなスポーツゲームを再構築する方法
素晴らしいヒントをいくつか持ち帰っていただければ幸いです!
素晴らしいアイデアを思いつき、コードを打つスピードと同じ速さでアイデアが形になっていきます。コミットするたびに、新しい特徴が形状を成していきます。しかし、アイデアが形になるスピードそのものが、やがてバグだらけの大きな混乱を招く結果になりかねません。
Mega Cat Studiosでは、すべてのプロジェクトを情熱を持って開始するため、迅速かつ柔軟に進め、できるだけ早く物事を成し遂げたいという魅力は理解しています。プロトタイプの場合、このアプローチは問題なく、実際、私たちも推奨しています!賢明な開発者は、いつイテレーションのスピードを優先し、いつ安定性を優先すべきかを心得ています。なぜなら、プロトタイプフェーズを終えると、その「迅速かつ柔軟な」アプローチが負債となるからです。
私たちはMega Cat Studiosでこの遷移を何度も経験しており、プロジェクトごとに新しいことを学んでいます。私たちの最新プロジェクトであるBackyard Baseballをローンチに向けて準備する過程で学んだ教訓をいくつか共有したいと思います。
レッスン 1:スケールを見据えた構造体

スケーリングの問題は、コードの不備によって引き起こされることは稀で、むしろ計画性のないアーキテクチャが原因で発生することが多いです。開発者やアーティストが10秒以内にアセットを見つけられない場合、ワークフローを変更する必要があります。プロジェクトをスケールさせるための設定のヒントをいくつか紹介します。
- タイプと目的で整理する:タイプ、次に目的でグループ化します。タイプには、アート、コード、オーディオなどのカテゴリが含まれます。目的とは、それらが何のために使用されるかということです。直感的な整理は、オンボーディングの摩擦係数を低減します。新しいアーティストは、「Character Idle」スプライトがどこに属するかを、質問しなくても正確に把握できるはずです。
- シーンをシンプルに保つ:私たちは「メガシーン」を廃止し、代わりに小さなシーンを選択しています。例えば、セーブデータや重要なシステムを保持するメインシーンに加え、タイトル画面や、プレイヤーがマッチ中かどうかに応じて追加的にロードされるひし形の野球シーンなどがあります。同様に、自己完結型の機能にはプレハブを使用しているため、変更内容がそれらを含むシーンファイルにシリアル化される可能性が低くなります。これにより、アーティストは環境の作業を行いながら、デザイナーは同じ「レベル」でゲームプレイを調整することができ、ファイル競合が発生しません(これについては後述します)。
- Addressables システムを設定する:従来の Resources フォルダーの代わりに、Addressables システムを使用して必要なときにのみアセットをロードし、メモリ使用量を抑えています。さらに、Addressables キーを使用してアセットをロードする方が、Resources フォルダー内の特定の場所へのファイルパスを介してロードするよりも明確であり、破損しにくくなります。
難しいのは、これらのベストプラクティスを理解することではありません。開始時にそれらを徹底し、何年も先までその規律を維持することです。
開発のどのフェーズにいるのか、その段階で何を優先しているのかを把握してください。
「プロトタイピングのフェーズでは、コードがほとんどないため、モジュール化する前にまずは機能させることを優先しても問題ありません」と、『Backyard Baseball』の開発者である Paolo Roxas 氏は述べています。「プロジェクトをより複雑にする前に、どのようにプレイされるかを確認したいのです。」

レッスン 2:Unityに逆らうのではなく、Unityを活用しましょう。

「コンポーネント、ScriptableObjects、カスタムクラスのいずれであっても、焦点を絞り、簡潔で、自己完結型のビルディングブロックを作成することほど強力なものはありません」と、Mega Cat Studiosのエンジニアリング責任者であるDavid Chávez Armenteros氏は述べています。Unityはその核心においてモジュール性を採用しています。柔軟性を維持するために、私たちは3つの古典的な原則に従っています。
1.単一責任:各スクリプトやクラスは、明確に定義された1つの役割を持つべきです。
2.疎結合:システムは直接的な参照ではなく、インターフェースやイベントを通じて、適切な場合にのみ相互作用するようにします。循環した、あるいは複雑に絡み合ったアーキテクチャを避けるため、コードに実装する前にシステム間の依存関係をグラフ化することをお勧めします。
3.プラグアンドプレイ:広大な「ゴッド」スクリプトを書くのではなく、小さく焦点を絞ったユニットを組み合わせて複雑な動作を作成します。
レッスン 3:制限を設けて自由になる

アセンブリ定義(AsmDefs)は、コードをグループ化するC#の構成要素です。その利点として宣伝されているのはコンパイル時間の短縮ですが、その真の力はモジュール性を強制することにあります。
リード開発者であり、スパゲッティコードを嫌うNico Gaudenziは、それらを強く推奨しています。
「Backyard Baseballでは、入力レイヤーとゲームプレイレイヤーは異なるDLLにあります。」ゲームプレイは、入力の詳細とは完全に無関係です。」
これにより、各依存関係を計算された決定にすることで、エンジニア自身によるミスを防ぐことができます。本当に必要であれば、ゲームパッドの処理からNetcodeまで、プレイヤーの物理演算やAIの動作を壊すリスクを冒すことなく、Input System全体を書き直すことができます。より可能性が高いのは、あるエンジニアがコードベースの単一のドメインで作業できるようにし、誤って他のシステムに変更を波及させることを防ぎ、開発者が特徴の実装やバグ修正のために把握しておく必要のあるコードの量を減らすことです。
レッスン4:より懸命にではなく、より賢くテストする
プロジェクトが成長するにつれて、「ドミノ効果」が支配的になる可能性があります。あちらの小さな変更が、こちらの何かを壊してしまうのです。優れたアーキテクチャは非常に役立ちますが、万能薬ではありません。
特徴の変更が、手動テストを行う当社の評価の高い品質保証担当の猫たちの手に渡る前に、ゲームは一連の自動化された単位テストで厳密に分析されます。
「テストは要件のリストとして機能します」とNicoは言います。「テストは期待される動作を記述し、主要なユースケースを提供します。」
Backyard Baseballのキャラクターが速球を投げたり、盗塁したり、ホームランを打ったりするとき、ボールが投球として本物らしく感じられるスピードで移動すること、ランナーのタイミングが盗塁のメカニズムと一致すること、あるいは野手がヒットに正しく反応することなど、達成したい特定のゲームプレイの結果があります。キャラクターは地面と正しく衝突する必要があり、ボールは適切なスピードで移動する必要があり、さらに、ワインドアップ、スイング、ベース間のスプリントといったアクションを追跡するプレイヤーコントローラーのフラグのような、より詳細なシステムが機能する必要があります。
Pablo Sanchezのパワーを調整したり、さらに重要なこととして、バットスイングを制御する共有コードを調整したりするときは、接触のタイミングからボールの軌道に至るまで、すべてのインタラクションがゲーム全体で一貫して動作することを確認する必要があります。
多くの場合、壊れるのは予想外のことであり、それこそがテストが非常に重要である理由そのものです。
このシステムをワークフローに統合することで、特定の要件が壊れた瞬間にそれを認識できるようになり、干し草の山から針を探すような時間のかかるテストやトラブルシューティングのセッションを削減できます。
UnityのTest Runnerは、システムがモジュール化されている場合に最も効果的に機能します。これが、私たちがアセンブリ定義を使用するもう一つの理由です。
レッスン 5:アセットを準備する

「過ちは人の常、許すは神の業」
しかし、そもそも人為的ミスを防ぐシステムを設定することは、まさに伝説的と言えます。
何時間ものコーディングとデバッグの後、目の疲れた開発者が誤ってクリックしたり、一時的なものに過ぎなかった変更を誤ってリポジトリにプッシュしたりすることは避けられません。許容できることではありますが(時折目が疲れている私としてはそう言わざるを得ませんが)、インポート設定が適切に構成されていないアセットは、大きな結果を招く可能性があります。多くの開発者は高性能なマシンで作業しているため、最悪のシナリオは、キャラクター、アニメーション、効果を含むスタジアムのシーンが、低スペックのハードウェアで動作が遅くなったり不安定になったりするまで、パフォーマンスの問題に気づかないことです。
このリスクを軽減するために、アセットへのアクセス権を持つユーザーを制限することもできますが、ゲームコンテンツを調整する必要がある多くの理由から、これがボトルネックにつながります。
- モデルが大きすぎてカメラ設定に収まりません。
- このオーディオクリップは音量が小さいため、特定の効果が必要です。
- シェーダーが変更されたため、すべてのテクスチャを調整する必要があります。
Backyard Baseballのようなゲームでは、視覚的なアイデンティティが重要視されるため、リリースに向けてルックアンドフィールを完璧にする過程で、モデルやVFXに何百もの微調整が加えられます。
「どれほど技術的な仕様を定めても、コンテンツの多様性がある以上、異なるアセット間でわずかですが重要な違いに対処しなければならないという事実は避けられません」とニコは言います。
ここでも自動化が役立ちます。
- AssetPostprocessor:プロジェクトの基準を強制するカスタムインポートロジックを作成します。
- OnValidate:OnValidateメソッドを使用して、エディター内で欠落している参照をレポートします。これは常にビルド前に実行されます。
とはいえ、自動化に関するこうした話に気を取られて、手動による修正の方が速い場合にそれを見過ごさないようにしてください。
「手作業で10分かかるタスクを自動化するために10日間も費やしてはいけません」とDavidは警告します。
レッスン 6:人間という要素(コラボレーション)をマスターする

Version ControlシステムのようなGitは、毎日何十人もの開発者から寄せられる何百もの変更を調整する際に、真っ先に思い浮かぶものの一つです。Davidは、Mega Catのすべてのプロジェクトにおいて、以下の実証済みの手法を推奨しています。
- 小さく、アトミックな変更:一度に多くのシステムに影響を与える「メガコミット」は避けてください。安定してレビューが完了するまで、個々の特徴ブランチで作業を分離してください。個々の変更を個別のコミットに保持することで、十分に文書化されたVersion Control履歴を維持でき、必要に応じてGitの選択やその他のマジックも容易になります。
- メインからの毎日のマージ:特徴ブランチ、部門ブランチ、および長期運用ブランチをメインブランチで最新の状態に保つことで、最終的なマージのサイズと複雑さを軽減し、大規模な競合を防ぐことができます。
- マージリクエストのレビュー:これは品質保証の第一線であり、バグを発見し、プロジェクトの基準を強制し、システム全体との整合性を確保する場所です。
「大規模なUnityプロジェクトにおいて、コードレビューは単なる形式ではありません」とDavidは助言します。「それらは競合の防止とプロジェクト全体の品質におけるキーとなる部分です。」
コードをレビューする担当者が、実装されている領域の専門知識を持ち、コードのベストプラクティスを認識していることを確認してください。そうすることで、正確性や保守性を的確に評価できるようになります。
UnityでVersion Controlを可能な限り滑らかなものにするための具体的なヒントやコツがあります。シーンとプレハブはプロジェクトの基盤となるため、CPUパフォーマンスだけでなく、開発者のコラボレーションのためにも最適化してください。
私たちは常に、巨大なシーンやモノリシックなプレハブよりも、小さく、追加可能で、ネストされたコンポーネントを好みます。こうすることで、開発者は競合することなく並行して作業できます。
シーンやプレハブのマージ競合は、そのデータが開発者にとって読み取りにくいため、解決が最も困難であり、これは重要なことです。このプロセスを円滑にするために、私たちはこれらのファイルをバイナリではなくテキストとしてシリアル化し、YAMLファイルに対してGit設定の自動マージ機能を有効にしています。これにより、Gitがマージ競合を自ら解決する可能性が高まり、新しい特徴を作るという重要な作業のために開発者の時間を確保できます。
しかし、それらすべてにもかかわらず:
「競合を解決しようとするよりも、競合を防ぐ方が通常は優れた戦略です」とニコは言います。
明確なアセットの所有権は、このために大いに役立ちます。
「誰が特定のシーンやプレハブを変更できるかを定義してください」とデビッドは言います。「そうすれば、チームメンバーはアセットを直接編集する代わりに、自分の所有権の範囲外の変更をリクエストするようになります。」
ニコは同様の手順を「セマフォシステム」と表現しています。これは基本的に、開発者がアセットを変更する際に記録し、実質的にそれを「ロック」するためのスプレッドシートです。別の開発者がそのファイルを変更する必要がある場合は、ファイルをロックした開発者が変更をリポジトリにプッシュして「ロックを解除」するまで待つ必要があります。
いつものように、チームにとって最適な手順を見つけてください。
未来のための構築

Mega Cat Studiosでは、Unityプロジェクトのスケーリングは「より懸命にコーディングする」ことではなく、アーキテクチャの規律に関することであると学びました。Unityのコンポーネントベースの性質を尊重し、アセンブリ定義で境界を強制し、将来を見据えてアセットを整理することで、ローンチ前にプロジェクトが技術的負債に陥ることなく、プロトタイプ段階のクリエイティブなフローの多くを維持しています。
これらの教訓は重要ですが、完璧なコードベースなど存在しないことを忘れないでください。ソフトウェア開発は、推奨されるプログラミングパターンと実用的な考慮事項が日常的に衝突する壮大な戦いです。これらの原則のいずれかに従うことで、有益なトレードオフを得ることなく開発が停滞する場合、それは教科書的な推奨事項ではなく、自身のチームの特性にもっと敏感になる必要があるという兆候です。結局のところ、プロジェクト、チーム、そして人はそれぞれ異なるものです。
私たちはMega Cat Studiosで、日々そのバランスを取るよう努めています。新しいプロジェクトごとに、私たちのゲームライブラリが成長し続ける中で、私たちはより優れたUnity開発者、そしてより優れた協力者になることを目指しています。
