第4章 ゲームシステムの仕様

キャラクターを動かしたり、ぶつかって爆発させるだけでは、通常はゲームになりません。タイトルからゲームを開始したり、点数を加えたり、ゲームオーバーにしたり、クリアしたりと、ゲームを進行させていく仕組みが必要です。本章では、キャラとゲームシステムを連携させるための仕様を解説します。

4.1 ゲームを構成するオブジェクト

実装にとりかかる前に、考えられることを可能な限り、具体的に書き出します。書き出したものを、仕様書と呼びます。

プレイヤーやマップのキャラをはじめとする、ゲームを構成しているオブジェクトを挙げます。企画概要書で描いたサムネイル(図4.1)や、ゲーム画面を想定して作成した見本画像であるモックアップ(図4.2図4.3)が参考になります。

ゲーム画面のサムネイル

図4.1: ゲーム画面のサムネイル

Stage1のモックアップ

図4.2: Stage1のモックアップ

Stage2のモックアップ

図4.3: Stage2のモックアップ

4.1.1 見た目で分かるオブジェクトを列挙

画面イメージを眺めながら、目についたものをオブジェクトとして書き出します。

  • スコア
  • 残り秒数
  • カウントダウンテキスト
  • ステージ数
  • プレイヤーキャラ
  • 爆弾
  • コイン
  • 木箱
  • 背景

これらが、表示されているオブジェクトです。

4.1.2 ゲームの進行からオブジェクトを列挙

目に見えないオブジェクトもあります。それらを見つけるために、ゲームがはじまってからの進み方を書き出します。

  1. プレイヤーキャラを、スタート地点に配置
  2. カウントダウンの演出。この間、キャラは操作も移動もしない
  3. カウントダウンが終わったら、操作できるようになる

ここからは、ゲーム中に起きたことに基づいて、ゲームが進行します。

  • プレイヤーが爆弾に触れた
    • 爆弾を爆発させて、消す
    • 操作を停止
    • ゲームオーバーへ遷移
    • コンティニューが選ばれたら、プレイヤーをスタート地点へ戻して、カウントダウンへ
    • タイトルへ戻るなら、何もせずにシーンが切り替わるのを待つ
  • プレイヤーがコインに触れた
    • コインの基本点に、残りの秒数を加味した得点を加算
    • コインをすべて取っていたら、クリアへ遷移
    • 操作を停止して、シーンが切り替わるまで何もしない

ゲームの進み方が明らかになりました。これらを管理するためのオブジェクトを挙げます。

  • ゲームの進行を管理するオブジェクト
    • カウントダウンやゲームの開始、ゲームオーバーやクリアになったことを管理して、ゲーム内のオブジェクトへ通知する
    • スコアや残り秒数、コインの残り数を保持する
  • スコア
    • スコアを管理するための値オブジェクト
  • ステージ数
    • 現在のステージを管理するための値オブジェクト
  • 残り時間
    • 残り時間を管理するための値オブジェクト
  • 爆発
    • 爆弾が爆発したときの演出
  • コインの数の管理
    • ステージにある残りのコインの数を管理するオブジェクト

以上で、ゲームを構成するオブジェクトの概要が把握できました。これらのオブジェクトがやりとりして、ゲームを成立させます。

本書で扱うのは、プレイヤーや爆弾などのキャラの実装です。そこに関連するオブジェクトの詳細を検討して、解説します。

4.2 ゲームの進行の通知システム

プレイヤー、爆弾、コイン、木箱は、次のような動作が必要です。

  • カウントダウンでは停止
  • カウントダウンが終わって、ゲームがはじまったら、動き始める
  • ゲームオーバーやクリアになったら、動きを止める
  • コンティニューしたら、スタート位置に戻る(プレイヤーのみ)

これらを管理するクラスと、プレイヤーなどのすべてのキャラに、進行を通知するオブジェクトに伝える機能のクラスを用意します。

ゲームオーバーは、爆弾に触れたときに、プレイヤーや爆弾から、ゲームオーバーの要求を受け取ります。また、クリアは、コインを取ったときに、コインの数を管理するクラスで判定されて、このクラスに要求が出されます。同一フレームで、ゲームオーバーとクリアが同時に発生したときは、クリアを優先することにします。これは、プレイヤーと爆弾が接触した時点では、まだゲームオーバーになることは確定していないことを表します。クリアが報告されなかったときに、ゲームオーバーになることが確定して、キャラに知らされます。

通知を必要とするオブジェクトに、一斉に通知する方法は、いくつか考えられます。簡単なのは、ゲームの進行管理クラスをstaticにすることです。システムのどこからでもアクセスできるので、通知が必要なオブジェクトからポーリングします。

また、通知を送信するオブジェクトが、通知を受け取るためのインターフェースを検索しておいて、通知したいときに、インターフェースの通知メソッドを呼び出す方法が考えられます。

staticを使う方法は、手軽な反面、テスト時に機能が入れ替えにくいので、嫌われる傾向にあります。staticでの実装は簡単なので、今回は後者で実装します。

4.2.1 ゲームの進行変化を受け取る方法

通知を受け取りたいクラスに、IGameStateListenerインターフェースを実装します。ステージが開始する時に、システムがIGameStateListenerを実装しているクラスを検索して、進行に応じて、メソッドを呼び出します。各ゲームオブジェクトは、インターフェースで定義されているメソッドに、進行に応じて状態を変える処理を実装します。

爆弾やコインは、ステージからなくなる可能性があります。リストやイベントに、消えたオブジェクトのインスタンスが残っていると、実行時にエラーがでてしまいます。そこで、状態の切り替えに加えて、消えた時に、自身のインスタンスを渡して、リストから削除を要求する機能も、IGameStateListenerに定義します。

IGameStateListenerの定義は、リスト4.1の通りです。

リスト4.1: IGameStateListenerインターフェース

public interface IGameStateListener {
    void OnReset();
    void OnGameStart();
    void OnGameOver();
    void OnClear();
    UnityEvent<IGameStateListener> GameStateListenerDestroyed {get;}
}

4.2.2 ゲームオーバーの要求

ゲームオーバーを要求する機能を持たせたいクラスに、IGameOverEmitterインターフェースを実装することにします。ゲームシステムは、シーンからこのインターフェースを実装しているオブジェクトを検索して、ゲームオーバーを要求するメソッドを登録します。ゲームオーバーを要求するときは、受け取ったメソッドを呼び出します。

実行者から直接メソッドを呼び出すのではなく、実行してもらいたい側から実行者にメソッドを渡して、必要なタイミングで呼び出してもらう方法を、オブザーバーパターンと呼びます。Unityのボタンがこれで、UnityEventやUnityActionを使うと、手軽に実装できます。

このインターフェースを実装するのは、プレイヤーか爆弾のどちらでも構いません。実装時に、検討します。

4.2.3 コインの取得

クリアの要求は、ゲームオーバーよりやや複雑です。

コインを取ったら、コインの数を管理するオブジェクトに知らせて、残り数を減らします。残りが0になったら、クリアを要求します。コインの残り数を管理するクラスは、値オブジェクトとして実装します。それを、どこに持たせるかを検討します。

コインを取ったことは、プレイヤーとコインの双方が知り得ます。ただ、双方とも、コインの数を管理する役目ではないと感じます。ゲームのパラメータなので、ゲームの進行管理クラスにもたせるのが自然です。

以上から、クリアを要求するのではなく、プレイヤーかコインから、ゲームの進行管理オブジェクトに、コインを取ったことを知らせることにします。クリアするかどうかは、ゲームの進行管理側で判断します。

ここまで整理したら、ゲームオーバーと同様です。コインを取ったことを通知するIGetCoinEmitterを用意して、プレイヤーかコインに実装します。ゲームの開始時に、このインターフェースをもつインスタンスを検索して、コインを取ったときに呼び出して欲しいメソッドを渡します。これも、オブザーバーパターンです。

4.3 スコアシステム

スコアは、ゲームシステムのデータとして、定義しています。ゲームシステムのデータは、ゲームの進行管理クラスからアクセスできます。

スコアは、コインを取ったときに入ります。コインを取ったら、プレイヤーかコインから、ゲームの進行管理オブジェクトに基本点が報告されます。そこで、残り時間を反映させて、点数を加えればよさそうです。

4.4 ゲームシステムのまとめ

企画の構想をもとにして、目に見えるオブジェクトや、ゲームの進行に必要なオブジェクトを列挙しました。それらがどのように連携するかを検討しました。

企画構想で、面白い場面の具体例や、プロットを書き出したことが、ここで活きてきます。何もない状態で、このような作業をするのは大変です。考えたことは、すぐに具体的に書き出します。書き出したものを目で見ることで、想像が補強されて、より具体的なイメージが沸いてきます。それを書き出していくことを繰り返すことで、頭の中のゲームを、現実に変換します。

オブジェクトや進行が多すぎて、すべて挙げるのが難しいと感じたら、企画を分解して、小さくしましょう。考えきれないものを完成させることは困難です。確実に完成できる規模の企画を作って、ゲームを完成させる経験を積むことが大切です。