UnityでGoogle恐竜ゲーム風味のゲーム制作、第3回目です。今回は当たり判定を追加して、ゲームオーバーとリセットを作成していきます。
はじめに
今回は第3回目です。第1回目は下記から。
今回やる事
パート3の今回は障害物に当たり判定を追加して、ゲームオーバーとリセットを作成します。
製作開始
では、前回の続きからです。
当たり判定の追加
まずは当たり判定の追加。
前回追加した障害物にリジッドボディ(Rigidbody)を追加して、コライダーのトリガーにするにチェックを入れます。
とりあえずは、プレイヤーが障害物にぶつかったら止まるようにしてみます。
Player.csの最後に下記の関数をとりあえず追加。
private void OnTriggerEnter(Collider other) { _velocity = new Vector3(0, 0, 0); }
スタートメニュー・ゲーム終了(リセット)
ゲーム開始画面と、ゲーム終了画面を簡単に作成していきます。
UIからパネルを追加。名前をFinishにしておきます。
Finshパネルの配下にUIの「テキスト」と「ボタン」を追加。
ボタンのサイズ、テキストの内容、サイズなどを適当に調整しておきます。
「ゲーム」タブで下記の様な感じになっていればOK。
同じようにメニューパネルも作成。こっちは配下にボタンだけ。
下記の様な感じになっていればOK。
開始画面、終了画面と言うよりは、開始メッセージ、終了メッセージみたいな感じですかね。
作成したら両方とも初期状態は無効にしておきます。
状態遷移
ここからは、状態を管理して動作を制御していきます。
流れとしては、起動したら「メニューパネル」表示、スタートボタンを押したら「ゲームスタート」、ゲームスタートでプレイヤーが進むようにします。GameManagerスクリプトを下記に変更。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class GameManager : MonoBehaviour { public List<GameObject> ground; public GameObject player; public GameObject panelMenu; private float _spawnpoint = 10; private GameObject _ground; public static GameManager instance { get; private set; } public enum Status { MENU, INIT, GAME, FINISH } public Status statusMode; void Start() { instance = this; ChangeStatus(Status.MENU); } void Update() { if (player.transform.position.x > _spawnpoint - 20) { _ground = ground[Random.Range(0, ground.Count)]; Instantiate(_ground, new Vector3(_spawnpoint, 0, 0), Quaternion.identity); _spawnpoint += 10; } } public void ChangeStatus(Status nextstatus) { switch (nextstatus) { case Status.MENU: panelMenu.SetActive(true); break; case Status.INIT: break; case Status.GAME: GameObject.Find("Capsule").GetComponent<Player>().enabled = true; GameObject.Find("Capsule").GetComponent<Player>().PlayerRun(5.0f); break; case Status.FINISH: break; } } public void StartClick() { panelMenu.SetActive(false); ChangeStatus(Status.GAME); } }
Playerスクリプトは下記の様に変更。
障害物に当たったらスクリプトを無効にして終了状態に。後は細かいところを少し修正。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { [SerializeField] float _jump = 15f; private CharacterController _characterController; private Vector3 _velocity; private Transform _transform; private float _gravity = -30f; private float _skinWidth; private bool _isGround = true; void Start() { _characterController = GetComponent<CharacterController>(); _transform = GetComponent<Transform>(); _skinWidth = _characterController.skinWidth; } void Update() { if (_transform.position.y <= 1.5f + _skinWidth) { _velocity.y = 0; _isGround = true; } else { _velocity.y += _gravity * Time.deltaTime; _isGround = false; } if (Input.GetKeyDown(KeyCode.Space) && _isGround) { _velocity.y += _jump; } _characterController.Move(_velocity * Time.deltaTime); } public void PlayerRun(float speed) { _velocity.x = speed; } private void OnTriggerEnter(Collider other) { GetComponent<Player>().enabled = false; GameManager.instance.ChangeStatus(GameManager.Status.FINISH); } }
最終的なGameManagerスクリプトは下記の様な感じ。
ゲームオーバーでリスタートするとき、プレイヤーの位置を初期位置に戻して再スタート。かなりやっつけ感があって結構直すポイントも多いです。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class GameManager : MonoBehaviour { public List<GameObject> ground; public GameObject player; public GameObject panelFinish; public GameObject panelMenu; private float _spawnpoint = 10; private GameObject _ground; public static GameManager instance { get; private set; } public enum Status { MENU, INIT, GAME, FINISH } public Status statusMode; void Start() { instance = this; ChangeStatus(Status.MENU); } void Update() { if (player.transform.position.x > _spawnpoint - 20) { _ground = ground[Random.Range(0, ground.Count)]; Instantiate(_ground, new Vector3(_spawnpoint, 0, 0), Quaternion.identity); _spawnpoint += 10; } } public void ChangeStatus(Status nextstatus) { switch (nextstatus) { case Status.MENU: panelMenu.SetActive(true); break; case Status.INIT: player.transform.position = new Vector3(0, 1.5f, 0); Invoke("ChangeGameMode", 1.5f); break; case Status.GAME: GameObject.Find("Capsule").GetComponent<Player>().enabled = true; GameObject.Find("Capsule").GetComponent<Player>().PlayerRun(5.0f); break; case Status.FINISH: panelFinish.SetActive(true); break; } } private void ChangeGameMode() { ChangeStatus(Status.GAME); } public void StartClick() { panelMenu.SetActive(false); ChangeStatus(Status.GAME); } public void ReStartClick() { panelFinish.SetActive(false); ChangeStatus(Status.INIT); } }
あとは、メニューボタン、終了ボタンのクリック時に関数が実行されるようにすればOK
とりあえず、これで一通り動くように。
実際にはここから「スコア表示」や「スピード変化」、「オブジェクトの画像差し替え」、「アニメーション追加」などなどやることは沢山あります。もちろん、色々と追加した後にスクリプトの見直しも必要ですな。
まあ、一通り動いたので、この続きのPart4はやるかもしれないし、やらないかもしれないです(笑)