カウントダウンタイマーを作る

ここまででゲームの基本的な流れができました。しかし、このままでは単にユニティちゃんを走らせるだけのゲームになってしまい単調なので、これからゲーム的な部分を作り込んでいく必要があります。今回はステージに制限時間を設けて緊張感が出るようにしてみましょう。

タイマーオブジェクトとタイマー用Canvasの作成

まず、空のゲームオブジェクトを作成して名前を「Timer」に変更し、その子として「Timer Canvas」というCanvasを作成してください。さらに、Timer Canvasの中に「00:00」と書かれたテキストと、フォントサイズを大きくした空のテキストを配置してください(下図参照)。

タイマー用UIの作成

タイマー管理プログラム

次にタイマーの管理プログラムを作ります。「TimeManager」という名前のC#スクリプトを作り、Timerオブジェクトにアタッチしたら次のプログラムを記入します。


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityStandardAssets.Characters.ThirdPerson;

[RequireComponent(typeof(CountDownTimer))]
public class TimeManager : MonoBehaviour
{
	[SerializeField]
	float waitTime = 2.0f;
	[SerializeField]
	Text readyGoText;

	CountDownTimer timer;
	ThirdPersonCharacter character;
	Rigidbody playerRigidbody;
	GameManager gameManager;

	void Start ()
	{
		timer = GetComponent<CountDownTimer>();
		character = GameObject.FindGameObjectWithTag("Player").GetComponent<ThirdPersonCharacter>();
		playerRigidbody = GameObject.FindGameObjectWithTag("Player").GetComponent<Rigidbody>();
		gameManager = GameObject.Find("GameManager").GetComponent<GameManager>();

		StartCoroutine(ReadyGo());
	}

	IEnumerator ReadyGo()
	{
		yield return new WaitForEndOfFrame();

		//プレイヤーを停止させる
		character.enabled = false;
		playerRigidbody.isKinematic = true;

		yield return new WaitForSeconds(waitTime);

		readyGoText.text = "Ready?";

		yield return new WaitForSeconds(waitTime);

		readyGoText.text = "GO!!";

		//プレイヤーを移動可能にさせる
		character.enabled = true;
		playerRigidbody.isKinematic = false;

		//カウントダウン開始
		gameManager.countDown = true;

		yield return new WaitForSeconds(waitTime);

		readyGoText.enabled = false;

	}

}

カウントダウンタイマーのプログラム

次にタイマーのプログラムを作ります。「CountDownTimer」という名前のC#スクリプトを作り、Timerオブジェクトにアタッチしたら次のプログラムを記入します。


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class CountDownTimer : MonoBehaviour
{

	// 制限時間(分)
	[SerializeField]
	private int minute;
	// 制限時間(秒)
	[SerializeField]
	private float seconds;
	[SerializeField]
	private Text timerText;

	// トータル制限時間
	private float totalTime;
	// 前回Update時の秒数
	private float oldSeconds;
	GameManager gameManager;

	void Start()
	{
		totalTime = minute * 60 + seconds;
		oldSeconds = 0f;
		gameManager = GameObject.Find("GameManager").GetComponent<GameManager>();
	}

	void Update()
	{
		// 制限時間が0秒以下、countDownがfalseなら何もしない
		if (totalTime <= 0f  || !gameManager.countDown)
		{
			return;
		}

		// 一旦トータルの制限時間を計測;
		totalTime = minute * 60 + seconds;
		totalTime -= Time.deltaTime;

		// 再設定
		minute = (int)totalTime / 60;
		seconds = totalTime - minute * 60;

		// タイマー表示用UIテキストに時間を表示する
		if ((int)seconds != (int)oldSeconds)
		{
			timerText.text = minute.ToString("00") + ":" + ((int)seconds).ToString("00");
		}
		oldSeconds = seconds;

		// 制限時間終了
		if (totalTime <= 0f)
		{
			gameManager.GameOver();
		}
	}

}

※上記プログラムは「Unityで経過時間、制限時間を表示する機能を作成する | Unityを使った3Dゲームの作り方(かめくめ)」を参考にさせていただきました。

プログラムができたら、Timerオブジェクトのインスペクタを開いて下の図のようにTextコンポーネントを登録してください。

Textコンポーネントの登録

GameManager.csの変更

最後に、またしてもGameManager.csを変更します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityStandardAssets.Characters.ThirdPerson;
using UnityStandardAssets.Cameras;

public class GameManager : MonoBehaviour
{

	[System.NonSerialized]
	public int currentStageNum = 0; //現在のステージ番号(0始まり)
	[System.NonSerialized]
	public bool countDown = false;

	[SerializeField]
	string[] stageName; //ステージ名
	[SerializeField]
	GameObject fadeCanvasPrefab;
	[SerializeField]
	GameObject gameOverCanvasPrefab;
	[SerializeField]
	float fadeWaitTime = 1.0f; //フェード時の待ち時間

	GameObject fadeCanvasClone;
	FadeCanvas fadeCanvas;
	GameObject gameOverCanvasClone;
	ThirdPersonCharacter character;
	FreeLookCam freeLookCam;
	Rigidbody playerRigidbody;
	Button[] buttons;

	//最初の処理
	void Start ()
	{
		//シーンを切り替えてもこのゲームオブジェクトを削除しないようにする
		DontDestroyOnLoad(gameObject);

		//デリゲートの登録
		SceneManager.sceneLoaded += OnSceneLoaded;

		LoadComponents();
	}

	//シーンのロード時に実行(最初は実行されない)
	void OnSceneLoaded(Scene scene, LoadSceneMode mode)
	{
		countDown = false;

		LoadComponents();
	}

	//コンポーネントの取得
    void LoadComponents()
    {
		//タイトル画面じゃないなら取得
		if(SceneManager.GetActiveScene().name != stageName[0])
		{
			character = GameObject.FindGameObjectWithTag("Player").GetComponent<ThirdPersonCharacter>();
			playerRigidbody = GameObject.FindGameObjectWithTag("Player").GetComponent<Rigidbody>();
			freeLookCam = GameObject.Find("FreeLookCameraRig").GetComponent<FreeLookCam>();
		}
    }

	//次のステージに進む処理
	public void NextStage()
	{
		countDown = false;

		int maxStageNum = stageName.Length - 1;

		currentStageNum += 1;

		//最後のステージの場合、タイトルに戻る
		if (currentStageNum > maxStageNum)
		{
			currentStageNum = 0;
		}

		//コルーチンを実行
		StartCoroutine(WaitForLoadScene(currentStageNum));
	}

	//任意のステージに移動する処理
	public void MoveToStage(int stageNum)
	{
		currentStageNum = stageNum;

		//コルーチンを実行
		StartCoroutine(WaitForLoadScene(stageNum));
	}

	//シーンの読み込みと待機を行うコルーチン
	IEnumerator WaitForLoadScene(int stageNum)
	{
		//タイトル画面じゃないならキャラを停止
		if (SceneManager.GetActiveScene().name != stageName[0])
		{
			character.enabled = false;
			playerRigidbody.isKinematic = true;
		}

		//フェードオブジェクトを生成
		fadeCanvasClone = Instantiate(fadeCanvasPrefab);

		//コンポーネントを取得
		fadeCanvas = fadeCanvasClone.GetComponent<FadeCanvas>();

		//フェードインさせる
		fadeCanvas.fadeIn = true;

		yield return new WaitForSeconds(fadeWaitTime);

		//シーンを非同期で読込し、読み込まれるまで待機する
		yield return SceneManager.LoadSceneAsync(stageName[stageNum]);

		//フェードアウトさせる
		fadeCanvas.fadeOut = true;
	}

	//ゲームオーバー処理
	public void GameOver()
	{
		countDown = false;

		//キャラやカメラの移動を停止させる
		character.enabled = false;
		playerRigidbody.isKinematic = true;
		freeLookCam.enabled = false;

		//ゲームオーバー画面表示
		gameOverCanvasClone = Instantiate(gameOverCanvasPrefab);

		//ボタンを取得
		buttons = gameOverCanvasClone.GetComponentsInChildren<Button>();

		//ボタンにイベント設定
		buttons[0].onClick.AddListener(Retry);
		buttons[1].onClick.AddListener(Return);

	}

	//リトライ
	public void Retry()
	{
		Destroy(gameOverCanvasClone);

		MoveToStage(currentStageNum);
	}

	//最初のシーンに戻る
	public void Return()
	{
		Destroy(gameOverCanvasClone);

		MoveToStage(0);
	}

	//ゲーム終了
	public void ExitGame()
	{
		Application.Quit();
	}

	//操作方法とタイトル表示の切り替え
	public void SwitchTitle(bool isTitle)
	{
		Canvas titleCanvas = GameObject.Find("Title Canvas").GetComponent<Canvas>();
		Canvas howtoCanvas = GameObject.Find("HowtoPlay Canvas").GetComponent<Canvas>();

		if (isTitle)
		{
			titleCanvas.enabled = true;
			howtoCanvas.enabled = false;
		}
		else
		{
			titleCanvas.enabled = false;
			howtoCanvas.enabled = true;
		}
	}

}

カウントダウン用のフラグを追加しました。CountDownTimerではこのフラグを見て、ゲームオーバー中やステージクリア時ならタイマーを止めるようにします。

テストプレイしてカウントダウンが行われれば成功です!

次のページ→動く障害物を作る