このページでは、電子書籍 「Create modular game architecture in Unity with ScriptableObjects」の関連デモ プロジェクトである PaddleBallSOの概要を示し、コード アーキテクチャでデザイン パターンとモジュール性をどのように使用しているかについて説明します。
これは、電子書籍に付属するデモを使用して Unity 開発者を支援するために作成された 6 つのミニガイド シリーズの最初のものです。このデモは、古典的なボールとパドルのアーケード ゲームの仕組みにヒントを得たもので、ScriptableObjects を使用してテスト可能でスケーラブル、かつデザイナーに優しいコンポーネントを作成する方法を示しています。
電子書籍、デモ プロジェクト、およびこれらのミニ ガイドを組み合わせることで、Unity プロジェクトで ScriptableObject クラスを使用して プログラミング デザイン パターン を使用するためのベスト プラクティスが提供されます。これらのヒントは、コードを簡素化し、メモリ使用量を削減し、コードの再利用性を促進するのに役立ちます。
このシリーズには以下の記事が含まれます。
ScriptableObject デモ プロジェクトとこの一連のミニ ガイドに進む前に、デザイン パターンは本質的には単なるアイデアであるということを覚えておいてください。これらはあらゆる状況に当てはまるわけではありません。これらのテクニックは、Unity と ScriptableObjects を操作する新しい方法を学ぶのに役立ちます。
それぞれのパターンには長所と短所があります。特定のプロジェクトに有意義なメリットをもたらすものだけを選択してください。あなたのデザイナーは Unity エディターに大きく依存していますか?ScriptableObject ベースのパターンは、開発者との共同作業を支援するのに適した選択肢となる可能性があります。
結局のところ、最適なコード アーキテクチャとは、プロジェクトとチームに適したものになります。
PaddleBallSO は 、2 人のプレイヤー、2 つのパドル、およびボールを特徴とする、現代のビデオ ゲームを生み出した古典的なゲームを中心にしています。
ここでは、ゲームの仕組みではなくインフラストラクチャに重点が置かれています。これを「ゲーム配管」と考えてください。これは、アプリケーションを実行し続けるための、それほど魅力的ではないが非常に重要な基盤です。
このプロジェクトでは、ScriptableObject がバックグラウンドでどのように動作して統合アプリケーションを構築するかに焦点を当てています。これらを使用して、プロジェクトのメンテナンスを簡素化し、コードの再利用性を促進する多目的ゲーム システムを構築します。また、プレイヤーデータ、ゲーム状態の管理、ゲーム内の動作などにも活用できます。
PaddleBallSO プロジェクトは、最新バージョンの Unity Long Term Support (LTS)、現在は 2022 LTSと互換性があります。ランタイム UI を作成するための UI ツールキットと、ユーザー入力を処理するための入力システムが組み込まれています。
GitHub リポジトリでプロジェクトを見つけてダウンロードします。
Bootloader_scene をロードするか、GameSystems メニューから Load Bootstrap Scene on Play を有効にします。開始するには、再生モードに入ります。
これらは ScriptableObjects に固有のものではありませんが、デモ プロジェクトでは、ゲーム アプリケーションを一貫性のある予測可能な状態で起動するために、いくつかの一般的な手法を使用しています。
シーンブートストラップ (またはブートローダー) は、ゲームの初期状態を設定するエディター拡張スクリプトです。この初期化コードはゲーム ロジックとは別であり、シーン内のオブジェクトのすべての依存関係が正しく設定されていることを確認します。
依存関係の問題を回避するために、ブートストラッパーはシーンがロードされるときに重要なゲーム オブジェクト、マネージャー、またはサービスを構成します。
Unity アプリケーションが複数のシーンにまたがる場合、ブートローダーはビルド設定の最初のシーンである特定のブートストラップ シーンを強制的に読み込むことができます。再生モードを終了すると、エディターは前のシーンを再読み込みします。
ブートストラップ シーンの別のコンポーネントである シーケンス マネージャーは、シーンのロード時に重要なプレハブをインスタンス化できます。この特定のデモ プロジェクトでは、カメラ、スプラッシュ スクリーン、UI メニュー、シーンローダーなど、ゲームの作成に必要なものはすべてプレハブです。
SceneLoader は 必要に応じてゲームプレイ シーンを追加的にロード (およびアンロード) します。ほとんどの場合、これらのシーンは主にプレハブで構成されています。
プロジェクトシーン
各ミニゲーム レベルは個別の Unity シーンであり、ビルド設定に表示されます。個々のシーンを調べたい場合は、GameSystems メニューで SceneBootstrapper を無効にします。
多くのプロジェクトには、ブートストラップ シーンの後のメイン メニュー用のステージング領域も含まれています。この簡略化されたデモ プロジェクトでは、メイン メニュー シーンが省略されています。
再生メニュー と パターン メニューを使用して、次の内容を含む PaddleBallSOをテストします。
- デザインパターンの デモ、または一口サイズの例では、特定のテクニックを示し、各パターンを個別に説明します。
- これらを機能的に動作するサンプルに組み合わせたミニゲーム
Core フォルダーには、基本的なパターン スクリプト、シーン管理、UI ロジックなど、アプリケーション固有ではないコード ベースの部分が含まれています。これらは、さまざまなアプリケーションに適用できる、より一般的なクラスです。
サンプル ゲームは、象徴的な 2D 物理シミュレーションを再現し、ScriptableObject ベースのデザイン パターンの可能性を紹介します。
ただし、パターンの詳細に進む前に、アプリケーションを構成する MonoBehaviour について理解しておく必要があります。ご想像のとおり、Paddle、Ball、Bouncer、ScoreGoal スクリプトなどのコンポーネントが基本的なゲームプレイを制御します。
いくつかの高レベル マネージャー スクリプトがゲーム フローを制御します。
- GameManger は 、ゲームの状態 (開始、終了、リセット) を制御し、ゲーム コンポーネントを初期化し、UI を管理し、イベントに応答します。
- GameSetup は GameManager と連携して、ボール、パドル、壁、ゴールを設定します。
- ScoreManager は スコア値を更新し、ゲーム イベントを処理し、スコア表示の UI 更新を制御します。
これらの MonoBehaviour は ScriptableObject と連携して動作します。これらは、これらのコンポーネントを橋渡しして、それらの間で通信し、データを共有できるようにする上で重要な役割を果たします。
イベントは、プロジェクトのさまざまな部分間のコミュニケーションに役立ちます。これらのマネージャー スクリプトは、他のシーン オブジェクトやユーザー インターフェイスに接続されます。このイベント駆動型アーキテクチャは、コードをより整理し、デバッグしやすくするのに役立ちます。
また、最も一般的な ScriptableObject パターンごとに簡略化されたデモ例も提供しています。これらに慣れてくると、ScriptableObject がミニゲームのアーキテクチャの基盤となっていることがわかってきます。
紹介したミニゲームは、はるかに少ないコード行数で作成することもできましたが、このデモでは特に ScriptableObjects を使用したデザイン パターンに焦点を当てています。これらのパターンの多くは、ScriptableObject を使用せずに実装することもできます。
各パターンをプロジェクトにどのように適用するかをチームとして決定し、最適なアプローチを選択します。
ソフトウェア開発におけるモジュール化では、アプリケーションをより小さく、より独立した部分に分割します。これらのモジュールは特定の目的を果たすため、個別に開発およびテストできます。
それぞれの小さなオブジェクト セットは 1 つのユニットとして機能し、ゲームの 1 つの側面を処理します。これには、プレーヤーの入力の制御、物理の処理、スコアの集計など、あらゆることが含まれます。
プロジェクト スクリプトを調べる際には、次の重要なポイントに注意してください。
- プレハブからシーンを構築します。プロジェクト内のほとんどのシーンは、最小限のオーバーライドを含むプレハブのコレクションにすぎないことに気付くでしょう。プレハブは本質的にモジュール性のレベルを提供します。機能のトラブルシューティングは、特定のプレハブを個別にテストすることになります。ScriptableObject と同様に、プレハブは複数のシーンで再利用および共有できるプロジェクト レベルのアセットです。
- データの保存などに ScriptableObject を使用します。静的なゲームプレイ データを保存するために MonoBehaviour を使用しないでください。代わりに、再利用性を高めるために ScriptableObject を活用します。また、特定のゲーム ロジックを ScriptableObject に委任したり、シーン オブジェクト間の通信を容易にしたりすることもできます。
- 個別の懸念事項:プロジェクト内のデータ、ロジック、ユーザー インターフェイスを明確に区別します。これにより、コードの保守性が向上し、デバッグが簡素化されます。当社のメニュー画面システムは、新しい UI ツールキットを利用しています。この UI システムは、インターフェースとその基礎となるロジックを分離するワークフローを強制します。詳細については、Unity でのユーザー インターフェイスの設計と実装に関する 電子書籍をご覧ください。
- 依存関係を最小限に抑える:コンポーネント間の依存関係を減らすと、予期しない問題を引き起こすことなく、プロジェクトの一部を変更または置き換えやすくなります。
- コミュニケーションにイベントを使用する:イベントにより、コンポーネント間の疎結合が可能になり、直接の依存関係なしにコンポーネント間でメッセージを送信できるようになります。ScriptableObject ベースの「イベント チャネル」を使用して、さらに分離することができます。
- 不要なシングルトンを避ける:シングルトン設計パターンは、クラスの単一のインスタンスが不可欠な場合にのみ役立ちます。シングルトンを過度に使用すると、コードが密結合になり、テストが妨げられる可能性があります。必要ない場合はシングルトンをスキップします。
大規模なモノリシック スクリプトを小さな部分にリファクタリングすると、再利用性とスケーラビリティが向上します。これにより、チームのコラボレーションが向上し、テストが簡素化されます。
ScriptableObject の使用例を示すために、PaddleBallSO プロジェクトを作成しました。実際に動作しているのが見られる具体的な場所をいくつか紹介します。
- GameDataSOScriptableObject は、ゲーム設定の中心的なデータ コンテナーとして機能します。共通データを一度編集し、それを必要とする他のオブジェクトと共有します。
- ミニゲームは、分離された方法で通信するために多数の イベント チャネル に依存しています。これらの ScriptableObject ベースのイベントは、オブジェクトが互いにメッセージを送信する方法のバックボーンを形成します。
- サウンドの再生では、ScriptableObject ベースの デリゲート オブジェクト を使用して、MonoBehaviour コンポーネントからロジックを分離します。
- PlayerIDSOScriptableObject ベースの 列挙型 を使用して、Player1 と Player2 の「チーム」を区別します。
- LevelLayoutSOScriptableObject は、パドル、ゴール、壁、ボールなどのゲーム要素の開始位置のデータ コンテナーとして機能します。これにより、Unity 内およびエクスポートされた JSON ファイルを介して外部でレベル レイアウトを簡単に変更できます。Unity 外でのレベル デザインの改造により、プレイヤーの創造性が促進され、カスタム レイアウトの共有が促進されます。
デザイン パターンのデモも ぜひチェックして、さらにいくつかの追加情報も確認してください。
ScriptableObject はゲーム データを保存し、ワークフローを効率化するための強力なツールですが、プロジェクトが乱雑にならないように効果的に使用することが重要です。
Unity で ScriptableObject を使用する際のベスト プラクティスをいくつか紹介します。
- データをモジュール化して整理します。異なるデータ タイプごとに個別の ScriptableObject を使用します (例: 1 つはプレイヤーの統計用、もう 1 つは敵の動作用など)。複雑なデータを、簡単に管理できる小さな部分に分割します。
- フォルダーと命名規則を使用します。ScriptableObjects を使用するとスクリプト内のコードを削減できますが、その代わりにプロジェクト フォルダー内のアセットの処理量が増えます。適切な命名とディレクトリ構成により、これらの ScriptableObject を効率的に管理できます。命名のヒントについては、 コード スタイル ガイド をご覧ください。
- ScriptableObjects の過度な使用は避けてください。ScriptableObject は素晴らしいデータ コンテナーですが、使いすぎないことが重要です。ScriptableObject はプロジェクトを複雑にする可能性があるため、明確なメリットがある場合にのみ導入するようにしてください。(たとえば、永続的なデータを保存する場合には使用しないでください。)
- 定期的にデータをバックアップする:ScriptableObject への変更は実行時に「ライブ」で行われ、アセット ファイルとして保存されます。データが失われないように、プロジェクトを定期的にバックアップしてください。バージョン管理ソフトウェアを使用して、ScriptableObject への変更を追跡します。
- インスペクター ウィンドウを使用します。ScriptableObject の主な利点の 1 つは、シリアル化可能であり、インスペクターに表示されることです。エディター インターフェイスを利用して、ScriptableObject に保存されているデータを表示および操作します。
- カスタム エディター スクリプトを活用してください。ScriptableObjects は、シーン階層からランタイム オブジェクトをネイティブに参照できません。これらのオブジェクトを視覚化する必要がある場合は、エディター スクリプトを使用して、インスペクターをよりユーザーフレンドリーなインターフェイスにします。
これらのガイドラインに従うことで、開発でよくある落とし穴を回避できます。
ScriptableObjects を使用したデザイン パターンの詳細については、電子書籍「ScriptableObjects を使用して Unity でモジュール式ゲーム アーキテクチャを作成する」をご覧ください。一般的な Unity 開発設計パターンの詳細については、電子書籍「ゲーム プログラミング パターンを使用してコードをレベルアップする」を参照してください。