アクションゲームやレースゲームなどでは
”時間”という概念を設けることによって、
難易度を調整したり、
一度クリアしたステージでも、もっと早くクリアを促す
といったように飽きさせない工夫を施すことができます。
大規模なストーリーゲームより、カジュアルゲームで実装することが多いといった感じ。
本記事では、この頻出の時間機能の実装方法を解説します。
1.UIの設計
1-1.時間を示すText
CanvasからTextを作成します。
本記事では、カウントダウンとカウントアップを解説するので、
それらの時間を示すように2つ配置します。
Inspectorは図参照
1-2.時間を示すTextMeshPro
せっかくなので、TextMeshProを使ったバージョンも作ります。
(不要な人はスキップください^^;)
TextMeshProは、デザイン性のあるTextを扱う際に有用です。
(Asset Storeで得られるフォントはTextMeshProが多い)
使用するには、UIからTextMeshProを選びます。
ない場合は、WindowタブのPackage ManagerよりTextMashProをInstallして使います。
配置の仕方は、Textと何ら変わりません。
後で説明する、スクリプトで扱う際に、少し変わるくらいです。
1-3.Groupで整理
カウントダウン用とカウントアップ用のTextが入り乱れるので、
整理のためにCreate Emptyから作ります。
(別に作らなくてもいいですけどね^^;)
CdGroupとCuGroupと名付けて格納し、Y座標を調整して、ずらします。
1-4.さらにTextとButton
Textをもう1つ画面中央上に配置します。
これはゲームの開始・終了を示すものです。
そして、時間を止めるためのButtonも作成します。
カウントダウンは時間切れで終了しますが、
カウントアップはクリア条件を設けないと終わりません。
カウントアップを実装するのは、
大抵クリアタイムを意識したゲームだと思うので、
このButtonは、
ゴールに辿り着いたり、ミッションクリアに対応する処理だと見なしてくださいw
2.時間経過(カウントダウン&カウントアップ)のスクリプト
UIの準備が整ったら、スクリプトで動かすだけです。
GameManager.csというスクリプトを作って、ゲーム内にGameManagerという空のゲームオブジェクトを作り、アタッチします。
スクリプトの内容は次の通り↓
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class GameManager : MonoBehaviour
{
[SerializeField] float playTime1;
float playTime2;
[SerializeField] Text timeCdText;
[SerializeField] Text timeCuText;
[SerializeField] TextMeshProUGUI timeCdTMP;
[SerializeField] TextMeshProUGUI timeCuTMP;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
playTime1 -= Time.deltaTime; //時間経過で減算
timeCdText.text = playTime1.ToString("F1"); //四捨五入して小数1桁まで表示
timeCdTMP.text = playTime1.ToString("F1");
playTime2 += Time.deltaTime; //時間経過で加算
timeCuText.text = playTime2.ToString("F1");
timeCuTMP.text = playTime2.ToString("F1");
}
}
それでは、Inspectorよりスクリプトの項目にTextオブジェクトを紐づけます。
playTime1は制限時間を設定できるようになっています。
ゲーム時間10秒なら、10と入力します。
ゲームを実行すると、
CdTextは時間が減り、CuTextは時間が増えていくのがみられます。
3.スタートコールとゴールの設計
ゲームのスタート、時間切れ、ゴールといったリアクションがないと
ゲームの時間実装とはいきませんね^^
ここで、まだ使っていないCallTextとClearButtonの出番です。
次のようにコードを少し追記します↓
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class GameManager : MonoBehaviour
{
[SerializeField] float playTime1;
float playTime2;
[SerializeField] Text timeCdText;
[SerializeField] Text timeCuText;
[SerializeField] TextMeshProUGUI timeCdTMP;
[SerializeField] TextMeshProUGUI timeCuTMP;
[SerializeField] Text callText; // 追記
bool ready =true; // 追記
// Start is called before the first frame update
void Start()
{
StartCoroutine(StartCall()); // 追記
}
IEnumerator StartCall() // コルーチンの追記
{
callText.text = "よーい";
yield return new WaitForSeconds(2f);
callText.text = "スタート!";
ready = false;
yield return new WaitForSeconds(1f);
callText.text = "";
}
// Update is called once per frame
void Update()
{
if(ready) // 追記
{
return;
}
if(playTime1 <= 0) // 時間切れ処理の追記
{
ready = true;
callText.text = "時間切れ~!";
}
playTime1 -= Time.deltaTime;
timeCdText.text = playTime1.ToString("F1");
timeCdTMP.text = playTime1.ToString("F1");
playTime2 += Time.deltaTime;
timeCuText.text = playTime2.ToString("F1");
timeCuTMP.text = playTime2.ToString("F1");
}
public void OnClickClearBtn() // ボタンで呼ぶ関数の追記
{
ready = true;
callText.text = "クリア!";
}
}
readyというboolをUpdate関数のはじめに設ければ、
簡単に時間の停止を制御することができます。
(returnで以下のコードは読まれないため)
スタートがコールされるまでは、ready = true
↓
ゲーム中は、ready = false
↓
・時間切れ(playTime1が0以下)になったら、ready = true
・Goal Buttonが押されたら、ready = true
CallTextの紐付け、
Clear ButtonのOnClickにも関数を紐づけます。
これで実行してみると、
スタートコールや時間切れ、クリアとともに時間の停止が実装されたことがわかります。
このような時間制御は頻出なので
今回のスクリプトはテンプレとして使っちゃってください^^
