アクションゲームやレースゲームなどでは
”時間”という概念を設けることによって、
難易度を調整したり、
一度クリアしたステージでも、もっと早くクリアを促す
といったように飽きさせない工夫を施すことができます。
大規模なストーリーゲームより、カジュアルゲームで実装することが多いといった感じ。
本記事では、この頻出の時間機能の実装方法を解説します。
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にも関数を紐づけます。
これで実行してみると、
スタートコールや時間切れ、クリアとともに時間の停止が実装されたことがわかります。
このような時間制御は頻出なので
今回のスクリプトはテンプレとして使っちゃってください^^