【Unity】シューティングゲームのリファクタリング(拡張性を向上)
プロジェクトウィンドウのフォルダの構成の例
構成イメージ
実際のプロジェクトウィンドウ
プレファブ
シーン構成
スクリプト
GameDirectorゲームオブジェクト
GameDirector
using UnityEngine;
public class GameDirector : MonoBehaviour
{
[SerializeField]
Transform arrowsParent;
PlayerGenerator playerGenerator;
ArrowGenerator arrowGenerator;
GaugeController gaugeController;
void Awake()
{
playerGenerator = GetComponent<PlayerGenerator>();
arrowGenerator = GetComponent<ArrowGenerator>();
gaugeController = GetComponent<GaugeController>();
CreateInstance();
}
private void CreateInstance()
{
// プレイヤーのインスタンス作成
GameObject player = playerGenerator.Generate();
// 矢のインスタンスを繰り返し作成
arrowGenerator.Generate(arrowsParent, player, gaugeController, 1);
}
}
このコードは、UnityのゲームオブジェクトにアタッチされたGameDirectorスクリプトを表しています。
このスクリプトは、次の変数を宣言しています。
• arrowsParent :Transform型の変数で、矢を生成する親オブジェクトのTransformコンポーネントを参照します。
• playerGenerator :PlayerGenerator型の変数で、プレイヤーを生成するために使用されます。
• arrowGenerator :ArrowGenerator型の変数で、矢を生成するために使用されます。
• gaugeController :GaugeController型の変数で、ゲージを制御するために使用されます。
そして、Awake()メソッド内で、それぞれの変数を初期化し、CreateInstance()メソッドを呼び出して、プレイヤーと矢を生成します。
CreateInstance()メソッドは、プレイヤーのインスタンスを作成し、矢のインスタンスを繰り返し作成するために、 arrowGenerator.Generate() メソッドを呼び出します。 arrowGenerator.Generate() メソッドには、矢の親オブジェクトのTransformコンポーネント、プレイヤーのGameObject、ゲージコントローラー、矢の生成数が渡されます。
以上のように、このスクリプトは、プレイヤーと矢を生成し、それらを制御するためのゲージコントローラーを初期化します。
PlayerGenerator
using UnityEngine;
public class PlayerGenerator : MonoBehaviour
{
public GameObject player;
public GameObject Generate()
{
return Instantiate(player);
}
}
PlayerGenerator クラスには、 player というpublic変数があります。これは、生成するプレイヤーオブジェクトのプレハブ(Prefab)を格納するためのものです。
また、Generate()というメソッドがあります。このメソッドは、 player に設定されたプレハブを元に、新しいプレイヤーオブジェクトを生成して返します。具体的には、 Instantiate() メソッドを呼び出して player プレハブのコピーを作成しています。
このコードは、 PlayerGenerator クラスを使ってプレイヤーオブジェクトを生成するためのものです。他のスクリプトで PlayerGenerator クラスを使用する場合は、 Generate() メソッドを呼び出して新しいプレイヤーオブジェクトを生成できます。
ArrowGenerator
using UnityEngine;
public class ArrowGenerator : MonoBehaviour
{
public GameObject arrowPrefab;
GameObject player;
Transform parent;
GaugeController gaugeController;
/// <summary>
/// 落下させる矢を生成します
/// </summary>
/// <param name="parent">矢の生成先の親</param>
/// <param name="player">プレイヤーのゲームオブジェクト</param>
/// <param name="gaugeController">ライフの残りを表示するゲージ</param>
/// <param name="repeatRate">生成間隔</param>
public void Generate(Transform parent, GameObject player, GaugeController gaugeController, int repeatRate)
{
this.parent = parent;
this.player = player;
this.gaugeController = gaugeController;
// GenerateArrowメソッドをrepeatRat秒間隔で繰り返します
InvokeRepeating(nameof(GenerateArrow), 0, repeatRate);
}
void GenerateArrow()
{
GameObject arrowObject = Instantiate(arrowPrefab, new Vector3(Random.Range(-6, 7), 7, 0), Quaternion.identity, parent);
ArrowController arrowController = arrowObject.GetComponent<ArrowController>();
arrowController.player = player;
arrowController.OnArrowCollision.AddListener(gaugeController.ViewHp);
}
}
アタッチされたゲームオブジェクトは、矢を生成するためのメソッド Generate() を公開します。
Generate() メソッドは、親の Transform、プレイヤーの GameObject、ライフを表示するためのゲージを表す GaugeController、そして矢を生成する間隔を表す repeatRate の 4 つの引数を受け取ります。
メソッドは、これらの引数をメンバー変数として保持し、 InvokeRepeating() を使用して GenerateArrow() メソッドを繰り返し呼び出します。
GenerateArrow() メソッドは、ランダムな x 座標を持つ位置に arrowPrefab オブジェクトのインスタンスを生成し、矢を制御する ArrowController を取得し、プレイヤーの GameObject への参照を設定します。また、矢の衝突時に GaugeController の ViewHp メソッドを呼び出すために、 OnArrowCollision イベントに GaugeController の ViewHp メソッドを追加します。
Instantiateメソッドの第4引数は、ヒエラルキーでの親ゲームオブジェクトを登録しています
Quaternion.identity
は、回転を表すQuaternionオブジェクトのデフォルト値を表します。具体的には、x、y、z、wのすべての値が0のQuaternionオブジェクトで、回転がない状態を表します。
Unityの3D空間では、オブジェクトの回転はQuaternionオブジェクトで表されます。Quaternion.identityは、回転が必要ない場合に便利で、以下のような場合に使用できます。
- オブジェクトを作成するときに、回転を0に設定する必要がある場合。
- オブジェクトを回転する必要がない場合、例えばスケール変換を適用するときに回転を避けたい場合。
Quaternion.identity
を使用すると、回転がない状態でオブジェクトを操作でき、コードがより簡潔になります。
Playerゲームオブジェクト
PlayerController
using UnityEngine;
using UnityEngine.UI;
public class PlayerController : MonoBehaviour
{
// 左ボタン
Button leftButton;
// 右ボタン
Button rightButton;
// プレイヤーの横の移動速度
public float playerMoveSpeed = 3.0f;
void Start()
{
leftButton = GameObject.Find("LButton").GetComponent<Button>();
leftButton.onClick.AddListener(MoveLeft);
rightButton = GameObject.Find("RButton").GetComponent<Button>();
rightButton.onClick.AddListener(MoveRight);
}
void Update()
{
// 左矢印が押された時
if (Input.GetKey(KeyCode.LeftArrow))
{
MoveLeft();
}
// 右矢印が押された時
if (Input.GetKey(KeyCode.RightArrow))
{
MoveRight();
}
// 左右の移動制限の計算
float x = transform.position.x;
float y = transform.position.y;
transform.position = new Vector2(Mathf.Clamp(x, -8, 8), y);
}
public void MoveLeft()
{
transform.Translate(-playerMoveSpeed * Time.deltaTime, 0, 0);
}
public void MoveRight()
{
transform.Translate(playerMoveSpeed * Time.deltaTime, 0, 0);
}
}
このコードは、Unityのゲームオブジェクトを制御するためのスクリプトです。具体的には、左右に移動するプレイヤーキャラクターを制御します。以下に、コードの各部分を説明します。
Button はUnityのUI機能で、ボタンを表します。leftButton と rightButton は、それぞれ左右の移動を制御するためのボタンです。
public float playerMoveSpeed = 3.0f; は、プレイヤーの横移動速度を示す変数です。初期値は 3.0f に設定されています。
void Start() は、スクリプトが開始されたときに実行されるメソッドです。GameObject.Find と GetComponent を使用して、ボタンオブジェクトを検索し、左右のボタンに対して onClick.AddListener を呼び出して、左右の移動を制御するメソッドを登録しています。
void Update() は、フレームごとに実行されるメソッドです。このメソッドでは、左右のキー入力があった場合に、それぞれ MoveLeft メソッドと MoveRight メソッドを呼び出して、プレイヤーを移動させています。また、プレイヤーの移動制限を Mathf.Clamp を使用して計算して、画面の端に到達した場合には、それ以上移動しないようにしています。
public void MoveLeft() と public void MoveRight() は、それぞれプレイヤーを左右に移動させるメソッドです。transform.Translate を使用して、プレイヤーの座標を移動させています。Time.deltaTime を乗算することで、フレームレートの変化による移動速度の変化を吸収します。
PlayerStatus
using UnityEngine;
// プレイヤーの状態管理
public class PlayerStatus : MonoBehaviour
{
public int hp = 100;
}
プレイヤーの状態を管理するスクリプトです
public int hp = 100; は、プレイヤーの体力を表す hp 変数を宣言して、初期値を100に設定しています。この変数は、他のスクリプトからアクセスできます
UIオブジェクト
GaugeController
using UnityEngine;
using UnityEngine.UI; // UIを使うので忘れずに追加
public class GaugeController : MonoBehaviour
{
Image hpGaugeImage;
void Start()
{
hpGaugeImage = GameObject.Find("hpGauge").GetComponent<Image>();
}
// ゲージの円を更新する
public void ViewHp(PlayerStatus playerStatus)
{
hpGaugeImage.fillAmount = playerStatus.hp / 100.0f;
}
}
ImageクラスのインスタンスであるhpGaugeImageを宣言しています。
Start()メソッドで、hpGaugeImageに、GameObject.Find()メソッドを使用して、hpGaugeという名前のオブジェクトのImageコンポーネントを取得しています。
ViewHp(PlayerStatus playerStatus)メソッドは、引数としてPlayerStatusという型の変数を受け取ります。この目ドッドは、プレイヤーのステータスに応じて、hpGaugeImageの円のゲージの量を更新します。具体的には、fillAmountプロパティを使用して、playerStatusのhpの値を0から1の範囲に変換しています。 hpの値が100の場合、fillAmountは1になり、円のゲージが完全に塗りつぶされます。
このスクリプトは、ゲームオブジェクトにアタッチされることが想定されており、Start()メソッドでhpGaugeオブジェクトのImageコンポーネントを取得します。その後、プレイヤーのステータスに基づいて、円のゲージを更新するためにViewHp(PlayerStatus playerStatus)メソッドが呼び出されます。
クラス図
おまけ
ArrowGenerator
using UnityEngine;
public class ArrowGenerator : MonoBehaviour
{
public ArrowController arrowPrefab;
GameObject player;
Transform parent;
GaugeController gaugeController;
/// <summary>
/// 落下させる矢を生成します
/// </summary>
/// <param name="parent">矢の生成先の親</param>
/// <param name="player">プレイヤーのゲームオブジェクト</param>
/// <param name="gaugeController">ライフの残りを表示するゲージ</param>
/// <param name="repeatRate">生成間隔</param>
public void Generate(Transform parent, GameObject player, GaugeController gaugeController, int repeatRate)
{
this.parent = parent;
this.player = player;
this.gaugeController = gaugeController;
// GenerateArrowメソッドをrepeatRat秒間隔で繰り返します
InvokeRepeating(nameof(GenerateArrow), 0, repeatRate);
}
void GenerateArrow()
{
ArrowController arrowController = Instantiate(arrowPrefab, new Vector3(Random.Range(-6, 7), 7, 0), Quaternion.identity, parent);
arrowController.player = player;
arrowController.OnArrowCollision.AddListener(gaugeController.ViewHp);
}
}
「arrowPrefab」というpublic変数で、矢のプレハブを指定することができます。
「player」と「parent」というGameObjectとTransformの変数で、矢の生成先の親とプレイヤーのゲームオブジェクトを指定することができます。
「gaugeController」というGaugeControllerの変数で、ライフの残りを表示するゲージを指定することができます。
「Generate」メソッドを使用して、矢を生成する処理を実行します。このメソッドは、「parent」「player」「gaugeController」変数と、「repeatRate」整数値を引数として受け取ります。このメソッドは、「InvokeRepeating」メソッドを使用して、「GenerateArrow」メソッドをrepeatRate秒間隔で繰り返し呼び出します。
「GenerateArrow」メソッドは、矢のプレハブから「ArrowController」のインスタンスを生成し、「Random.Range」メソッドを使用してランダムなx座標を決定して、指定された親オブジェクトの下に配置します。次に、この矢の「player」変数にプレイヤーのゲームオブジェクトを割り当て、「OnArrowCollision」イベントに「gaugeController.ViewHp」メソッドを追加します。これにより、矢がプレイヤーに当たった時にライフの残りを更新することができます。
ディスカッション
コメント一覧
まだ、コメントがありません