シンプルなアクションゲームを作ってみようの第13回です。
今回はキャラクターがゲームクリアするまでの時間を計測する機能を作成していきます。
前回はゲームクリアとゲームオーバーのエリアを作成しました。
シンプルなアクションゲームを作ってみようの他の記事は
シンプルなアクションゲームを作るのを通してUnityの使い方を学ぶカテゴリです。
から参照出来ます。
時間を表示するUIの作成
まずは経過時間を表示するUI(ユーザーインタフェース)を作成していきたいと思います。
UIも親のゲームオブジェクトの子要素に配置するようにし、管理しやすいようにします。
Stage1シーンのヒエラルキーで右クリックからCreate Emptyを選択し、名前をUIとします。
インスペクタのTransformの右の3つの丸を押しResetを選択し値をリセットします。
時間を表示するテキストを作成する
次にUIを選択した状態で右クリックからUI→Text – TextMeshProを選択します。
UI→Textでも同じように作れますが、TextMeshProの方が細かい設定が出来たり、カメラが接写してもテキストがにじんで表示されにくくなります。
選択すると新しくウインドウが表示されます。
Import TMP Essentialsボタンを押します。
TMP Essentialsをインポートしたらウインドウの右上の×を押してウインドウを閉じます。
ヒエラルキーを見るとCanvasとその子要素にText(TMP)が作成されています。
テキストやボタンなどのUIの要素を作成すると必ずCanvasの子要素に作成されます。
また、ボタン等を押した時のイベントを処理するEventSystemも作成されます。
ヒエラルキーのCanvasを選択し、F2キーを押して名前をTimerに変更します。
またText(TMP)を選択し、F2キーを押して名前をTimerTextに変更します。
テキストの設定をする
TimerTextを選択し、インスペクタで設定をしていきます。
Rect TransformのWidthを200、Heightを50であることを確認します。
これはテキストの表示範囲の幅と高さを指定しています。
次にTextMeshPro – Text(UI)の入力欄に00:00:00を入力します。
これは最初の時間を設定しています。
次にAlignmentでCenterとMiddleを押します。
Alignmentはテキストの幅と高さでの配置場所の指定です。
次にタイマーはゲーム画面の右上に表示したいのでテキストをキャンバスの右上に移動させます。
Anchor Presetsの部分を押し、Shift+Altキーを押しながらright topの選択をします。
Shiftキーを押しながら選択するとPivotの設定、Altキーを押しながら選択すると位置の設定もしてくれるので、それを同時に行っています。
これで時間を表示するテキストがGameビューで右上に表示されます。
時間計測スクリプトの作成
経過時間を表示するテキストが出来たので、次は経過時間を計算するスクリプトを作成していきます。
Assets/Scriptsフォルダ内に新しくTimerScriptスクリプトを作成し、ヒエラルキーのTimerTextゲームオブジェクトにドラッグ&ドロップして取り付けます。
スクリプトを書いていきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using TMPro; using UnityEngine; public class TimerScript : MonoBehaviour { // ゲームマネージャー private GameManager gameManager; // タイマーを表示するテキスト private TextMeshProUGUI timerText; // 経過秒数 private float seconds; // ストップウォッチ用フィールド private Stopwatch stopWatch; // Start is called before the first frame update void Start() { // コンポーネントの取得 gameManager = GameObject.Find("GameManager").GetComponent<GameManager>(); timerText = GetComponent<TextMeshProUGUI>(); // ストップウォッチクラスを使う場合 stopWatch = new Stopwatch(); } void Update() { // ゲームオーバー時は以降何もしない if (gameManager.GameOver) { return; } // 時間を計測する TakeTime(); //// ストップウォッチクラスを使う場合 //stopWatch.Stop(); //var timeSpan = stopWatch.Elapsed; //timerText.SetText("{0:00}:{1:00}:{2:00}", timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds); //stopWatch.Start(); } // 時間計測メソッド void TakeTime() { // 1秒増やす seconds += Time.deltaTime; // TimeSpanクラスを使って時間秒を取得する為の準備 var timeSpan = new TimeSpan(0, 0, (int)seconds); // 数値を更新 timerText.SetText("{0:00}:{1:00}:{2:00}", timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds); // あまりに時間がかかったらゲームオーバー if (seconds >= 60 * 60 * 60) { gameManager.EndGame(); } } // 経過時間を返す public int GetSeconds() { return (int)seconds; } } |
gameManagerはGameManagerを取得し入れます。
timerTextにはTimerTextのTextMeshPro – Text(UI)を取得し入れます。
secondsは経過秒数をfloatで入れます。
stopWatchはStopwatch型を入れるフィールドで、別のやり方としてStopwatchを使ったやり方もありますが、今回は使っていません(やり方は書いてあります)。
StartメソッドではGameManagerスクリプトの取得、TextMeshPro – Text(UI)であるTextMeshProUGUIの取得とStopwatchクラスのインスタンスを生成しています。
UpdateメソッドではGameManagerスクリプトのGameOverプロパティがtrueの時はゲームクリアかゲームオーバーなのでreturnをして、それ以降の処理をせず時間計測を行いません。
その後、時間計測をするTakeTimeメソッドを呼び出しています。
TakeTimeメソッドはこの後作成していきます。
Stopwatchクラスを使う場合はstopWatch.Stop()メソッドで一旦ストップウォッチを止めた後にstopWatch.Elapsedで経過時間をTimeSpan型で取得します。
TimeSpan型で経過時間を得ると、プロパティで経過時間や経過分等を得られます。
timerText.SetTextメソッドの引数に表示するテキストを指定しますが、時間、分、秒はそれぞれ00や01等、必ず二桁表示にしています。
そこで
1 2 3 | timerText.SetText("{0:00}:{1:00}:{2:00}", timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds); |
{0:00}等の書式設定を使って表示形式を設定しています。
SetTextの第1引数の文字列では第2引数以降のどの引数が文字列内のどの場所に表示されるかを{0}{1}{2}として第2引数以降の0番目であれば{0}のところ、第2引数の2番目であれば{2}のところにその引数の値を表示するようになっています。
{0:00}と0の後に:がありその後00となっている部分が書式設定でこれは割り当てた引数の数値が00に置き換えられます。
なのでtimeSpan.Hoursで経過時間が得られますが、例えば値が1だとして、これは{0}の部分に表示され、書式設定で00となっているので、数字でそれを置き換えて実際にはテキストに01と表示されます。
書式設定については色々あるのでC#のプログラミングガイドなどを参照してみてください。
テキストに経過時間を表示したら
1 2 3 | stopWatch.Start(); |
でストップウォッチをスタートさせます(ストップウォッチを使う場合)。
次にTakeTimeメソッドを見ていきます。
TakeTimeメソッドではsecondsにTime.deltaTimeを足しています。
Time.deltaTimeは前回のUpdateから今のUpdateを実行するまでにかかった時間なので、これをUpdate毎(今回の場合はUpdate内でTakeTimeメソッドを呼び出しその中で使ってますが)に呼び出すと経過時間が得られます。
それを使ってTimeSpanのインスタンス生成時にint型の値にキャスト(型変換)してコンストラクタに渡しています。
キャストはその値を別の型に無理やり変換する事で、小さい型(例えばint)から大きい型(例えばfloat)への代入時のキャストは自動で行ってくれますが、大きい型から小さい型へ代入したい場合は(型)のように明示的にキャストをする必要があります。
1 2 3 4 5 6 7 8 | // 自動でキャスト int a = 1; float b = a; // 明示的なキャストが必要 float c = 1f; int d = c; |
キャストできない場合はエラーが起きるので、キャストできるかどうか?を確認してキャストしたり、確実にキャスト出来る場合に限り使うようにします。
TimeSpanのコンストラクタにはint型の数値で渡す必要があったので、seconds(float型)の値を
(int)
とint型に変換して与えています。
TimerTextのテキストに設定している個所は先ほどのStopwatchを使った場合と同じです。
float型で表示出来る数字も決まっているので一定の時間経過したらGameManagerのEndGameメソッドを呼んでゲームオーバーにしてしまいます。
GetSecondsメソッドは外部からsecondsの値を取得する為のメソッドです。
実行して確認してみる
機能が出来たので実行して確認してみましょう。
上のようになりました。
終わりに
今回はゲームクリアやゲームオーバーするまでの経過時間を計測する機能を作成しました。
次回はキャラクターがただ単にゴールエリアを目指すだけでは簡単なので、敵キャラクターを配置して邪魔をするようにしていきます。