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はやるかもしれないし、やらないかもしれないです(笑)
