バッテラのハローワールド研究室

エンジニア、プログラミングに関する情報を掲載中!

【Unity】UniRXで作るタイムカウント機能

Unity

はじめに

今回はUniRXを使ったタイムカウント機能を作ってみました。

要件は以下としました。

・左クリックしたらカウント開始
・3秒をカウントしたら終わり
・カウント中は残り秒数を表示(小数点第二位まで)
・カウント完了後にテキストの文言を「GOGO」に変える

ゲームやアプリのレシピとして参考にして頂けると幸いです。

環境

  • MacOS BigSur (11.4)

  • Unity (2020.3.14f1)

  • UniRX (7.1.0)

実装

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UniRx; // これを忘れずに

public class Scene_0001 : MonoBehaviour
{
    [SerializeField] Text _txt_time;

    void Start()
    {

    }

    void Update()
    {
        // 左クリック押されたら
        if (Input.GetMouseButtonDown(0))
        {
            float limitTime = 3.0f;

            // 毎フレーム呼ばれるイベントを作る
            Observable.EveryUpdate()
                // 前フレームからの時間を取得
                .Select(x => Time.deltaTime)
                // 経過時間を足しこむ
                .Scan((prev, x) => prev + x)
                // 経過時間がlimitTime(3秒)超えたら終わり(DoOnCompletedに飛びます)
                .TakeWhile(x => x < limitTime)
                // 残り時間表記にするための変換処理だと思って
                .Select(x => limitTime - x)
                // limitTimeになるまで毎フレーム呼ばれます
                .Do(x =>
                {
                    _txt_time.text = $"{x:F2}";
                })
                // limitTimeになったらここが呼ばれます
                .DoOnCompleted(() =>
                {
                    // カウント終了後に呼ばれます
                    _txt_time.text = "GOGO";

                // 表示を消したいなら↓のような書き方でいけます
                //_txt_time.gameObject.SetActive(false);
            })
            .Subscribe(_ => { });
        }
    }
}

補足

Observable.EveryUpdateを使っている理由

本来は一定時間経ったら一度だけ○○するというのはObservable.Timer()でいいのですが、

残り時間を表示する条件だとObservable.Timer()だとうまく実装する方法が浮かびませんでした。

残り時間を算出するには短時間周期で呼ばれるファクトリメソッドがいるってことで、

Observable.EveryUpdateを使った次第であります。

Scanを使うと変数使わなくても合計時間を持つことができる

Scanをいまいち理解していないのですが、変数を作らずに値をプールできる機能だと思っています。

これのおかげでメンバ変数に累計時間を格納するということをしなくてもよくなりました。

カウント時間を変更するには

limitTimeの値を変えてあげることでタイマーの時間を変えられます。

limitTimeの単位は秒です。1.5fなら1.5秒になります。
(Time.deltaTimeの単位が秒なので、そこに単位を合わしてます)

カウントを終えた時の処理

.DoOnCompletedの箇所でタイムカウント完了した時の処理がかけるので、

自身のアプリの仕様に応じて適切な処理をするとよいでしょう。

参考にしたサイト

light11.hatenadiary.com

おわりに

最後まで見て頂きありがとうございました。

UniRXを使ったレシピを今後も作っていこうと思います。

読者登録・Twitterのフォローをしていただけると、ハッピーになります。