Unity で テトリス風ゲームを作ってみる(実装編)#1
Unity Version 2022.3.4
全体構造の整理
前回までで何を作るかどう作るかが整理できたので、今回からプロト実装をベースに具体的な実装を検討していく。
- 構造の整理
まず実装を考える前に、何をGameObject として、何をMonoBehaviour クラスとして、何をそれ以外のクラスとして実装するのかを整理する。自分の中でも曖昧な部分が多いが、一旦下記の方針で設計を進める。
-
- GameObject にするもの
- Unity エンジンによって認識・管理されるゲーム要素。GameObject 以外のオブジェクトはUnity エンジンは感知しておらず無いも同前(イベントのコールバックとしてUnity 画面上の選択肢にも表れない)。
- 画面上に配置されるオブジェクトはすべてGameObject になる(GameObject は、必ずTransform コンポーネントがアタッチされている)。見えるオブジェクトか見えないオブジェクトかは関係なし。
- Unity エンジンからのイベントを受けて処理をする必要がある、つまりMonoBehaviour クラスを使って実装するクラスのアタッチ先としてGameObject を作るケース。
- 複数のGameObject をまとめて操作するのに都合がよいケースで、親GameObject として作るケース。
- GameObject にするもの
-
- MonoBehaviour クラス(の派生クラス)にするもの
- Unity エンジンからのライフサイクルやイベントを受け取り、アタッチしているGameObject をスクリプトから制御するためのクラス。必ず何かのGameObject にアタッチされていないといけない。でないとUnity エンジンには認知されないので。
- 例えば、ライフサイクルやキーイベントを受け取ってアタッチしているGameObject の位置を動かしたいとかなら、このクラスから派生したクラスを生成してコールバック用の関数を実装しGameObject にアタッチする必要がある。他にもUnity エンジンからゲーム起動のイベントを受け取って、それをトリガーに初期化処理を実行したいとか、ゲーム終了のイベントを受け取って、データの保存処理をしたいとか。
- MonoBehaviour クラス(の派生クラス)にするもの
-
- その他のクラスにするもの
- Unity エンジンのライフサイクルやイベントと直接的には関係ないが、ゲームの処理を実現するのに必要なクラス。
- MonoBehaviour クラスとの境界線が曖昧だが、複雑になりすぎない程度に分離。
- その他のクラスにするもの
上記を踏まえてGameObject(クラスではなく)を抽出すると、下記のようになる。
-
- GameControl オブジェクト
- 全てのオブジェクトの親オブジェクト。
- NextArea オブジェクト
- NextArea を表現するオブジェクト。NextArea のテクスチャを表示。
- テトリミノを子オブジェクトとして保持する。
- Field オブジェクト
- フィールドを表現するオブジェクト。このオブジェクト自体はテクスチャを持っておらず透明だが、画面内のフィールド表示位置の起点になる。
- テトリミノ、ブロックオブジェクトを子オブジェクトとして保持する
- Tetrimino オブジェクト(Prefab)
- テトリミノを表現するオブジェクト。
- Block オブジェクトを4つ生成時に子オブジェクトとして保持する。着地後は、ブロックオブジェクトをフィールドオブジェクトに渡し、自身は削除される。
- このオブジェクト自体は、テクスチャを持っていない透明なオブジェクト。
- Block オブジェクト(Prefab)
- Tetrimino、Fieldの枠を表現するブロックのオブジェクト
- 親のテトリミノオブジェクトに追従して移動する
- Title / Play / GameOver Panel オブジェクト
- UI 表示用のオブジェクト
- 親Panel オブジェクトのSetActive で表示・非表示を制御する
- GameControl オブジェクト
それをHierarchy 上に作成すると下記のような感じ。
次にクラス構造。
GameObject と同じ名前なのでわかりずらいが、以下のとおり。
-
- GameControl クラス
- GameControl オブジェクトにアタッチされるゲームの全体制御を行うクラス。
- 各UI Panel のオブジェクト、NextArea、Field クラスのインスタンスをSerializeField で静的に保持する。また、起動時にLevelScore クラスのインスタンスを生成する。
- ゲーム中は、GameControl クラスから、NextArea クラスにTetrimino 生成指示を出し、生成されたTetrimino をField クラスにPushする。Tetriminoの着地イベントをField クラスからのコールバックで受け取り、スコアのアップデートと次のTetriminoの生成を行う。
- GameControl クラス
-
- NextArea クラス
- NextArea オブジェクトにアタッチされる。
- Tetrimino オブジェクトの生成を行うクラス。
- NextArea クラス
-
- Field クラス
- Field オブジェクトにアタッチされる。
- Field 枠(ブロック)の生成を行い、Fieldで内で起こる事象を管理する。
- GameControl クラスからTetrimino インスタンスを受け取り、Field 内の初期位置に移動させる(落下処理自体はTetrimino クラスが行う)。
- Tetrimino クラスからの着地イベントをコールバックで受け取って、ラインの削除、ラインの落下処理を行う。その結果をGameControl クラスにコールバックする。
- Field クラス
-
- Tetrimino クラス
- Tetrimino オブジェクトにアタッチされる。
- Block オブジェクトをSerializeField にて4つ保持する。
- 各Block の配置情報を持ち、Tetrimino の種別に応じて配置する。
- キーイベントを受信して、Tetrimino オブジェクトの移動、回転、落下を処理を行う。
- 移動、回転、落下に伴うコンフリクトチェックもこのクラスが行う。
- Tetrimino クラス
-
- LevelScore クラス
- GameControl クラスによりインスタンス化されるクラス。GameObject にはアタッチされない。
- スコアとレベルを管理し、Score Text UI、Level Text UI のテキストをアップデートする。
- LevelScore クラス
-
- ScreenConfig クラス
- Singleton クラス。GameObject にはアタッチされない。
- 画面のサイズやオフセットを計算する。
- GameControl クラスや、Field クラスなどから参照される。
- ScreenConfig クラス
ざっと必要なGameObject とClass 構成はこんな感じ大丈夫。
次回より各クラスの詳細を説明する。
次の記事