1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Unityで制限時間やN秒に一回行う処理をサクッと実装

Posted at

はじめに

少し前に書いたコードがメモ帳にあったので、Qiitaを始めたついでに投稿してみる
カウントダウンやカウントアップができる簡単なタイマークラス KitchenTimer を作ってみた

「N秒に1回 〜する」 のような処理を簡単に試したい時に使う。

結論

完成形がこちら。使い方は下の方で説明。

KitchenTimer.cs

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

/// Unity で簡単に使えるタイマークラス
public class KitchenTimer: MonoBehaviour
{
    //-----------------------------------------------------    
    /// [CountUp] 0秒からカウントアップ, u秒毎にeveryUが呼ばれる
    public void CountUp(float u, Action<float> everyU)
    {
        isCountUp = true;
        this.currentTime = 0; // 正確に保持している秒
        StartCoroutine(this.IECountUp(u, everyU));
    }

    //-----------------------------------------------------
    /// [CountDown] c秒からカウントダウン, d秒毎にeveryDが呼ばれる
    public void CountDown(float c, float d, Action<float> everyD, Action timeOver)
    {
        isCountUp = false;
        this.currentTime = c; // 正確に保持している秒
        StartCoroutine(this.IECountDown(c, d, everyD, timeOver));
    }

    //-----------------------------------------------------
    /// [StopCount] カウントをストップ
    public float StopCount()
    {
        this.isTimeRunning = false;
        return this.currentTime;
    }

    //-----------------------------------------------------
    /// [RestartCount] ストップのあとで、もう一度カウント再開
    public void RestartCount()
    {
        this.isTimeRunning = true;
        if(isCountUp)
        {
            StartCoroutine(this.IECountUp(this.tempInterval, this.tempAction));
        }
        else
        {
            this.CountDown(this.currentTime, this.tempInterval, this.tempAction, this.tempTimeOver);
        }
    }

    //-----------------------------------------------------
    /// [Wait] W秒間待ったあとで実行
    public void Wait(float w, Action action)
    {
        this.action = action;
        Invoke("DoAction",w);
    }
    
    //-----------------------------------------------------
    /// [Repeat] 実行 -> r秒待つ -> 実行 を繰り返す
    public void Repeat(float r, Action action)
    {
        this.action = action;
        InvokeRepeating("DoAction",0f, r);
    }

    //-----------------------------------------------------
    /// [WaitAndRepeat] Wait と Repeat を両方する
    public void WaitAndRepeat(float waitTime, float intervalTime, Action action)
    {
        this.action = action;
        InvokeRepeating("DoAction", waitTime, intervalTime);
    }

    //-----------------------------------------------------
    /// [Dispose] 使い終わった タイマー を捨てる
    public void Dispose()
    {
        CancelInvoke();
        Destroy(this);
    }

    //*******************************************************************
    //                その他
    //*******************************************************************

    /// 時間を保持するプロパティ
    private float currentTime;

    /// カウントを進めて良いかどうか(時間が進んでいるか)
    private bool isTimeRunning = true;

    /// カウントアップ中かダウン中か
    private bool isCountUp;

    /// メソッドを保持するプロパティ
    private Action action;

    // 中断中のカウントの変数を一時保持する
    private float tempInterval;
    private Action<float> tempAction;
    private Action tempTimeOver;

    /// 保持したメソッドを実行する
    private void DoAction()
    {
        this.action();
    }

    /// カウントアップ用のIE
    private IEnumerator IECountUp(float u, Action<float> everyU)
    {
        // 中断用の一時変数を保存
        this.tempAction = everyU;
        this.tempInterval = u;

        var count = 0f; 
        while(currentTime < 600f) // 限界は600秒までとする
        {
            if (isTimeRunning)
            {
                this.currentTime += Time.deltaTime;
                count += Time.deltaTime;
            }
            else
            {
                break;
            }
            if(count > u)
            {
                everyU(this.currentTime);
                count -= u;
            }
            yield return null;
        }
        if (isTimeRunning) 
        { 
            // 最後に忘れず、一時変数をnullに
            this.tempAction = null;
        }
    }
    
    /// カウントダウン用のIE
    private IEnumerator IECountDown(float c, float d, Action<float> everyD, Action timeOver)
    {
        // 中断用の一時変数を保存
        this.tempInterval = d;
        this.tempAction = everyD;
        this.tempTimeOver = timeOver;

        var count = 0f; 
        while(currentTime > 0)
        {
            if (isTimeRunning)
            {
                this.currentTime -= Time.deltaTime;
                count += Time.deltaTime;
            }
            else
            {
                break;
            }
            if(count > d)
            {
                everyD(this.currentTime);
                count -= d;
            }
            yield return null;
        }
        if (isTimeRunning)
        {
            timeOver(); // 中断以外でここに来た場合はタイムオーバーということ
        
            // 最後に忘れず、一時変数をnullに
            this.tempAction = null;
            this.tempTimeOver = null;
        }
    }
}

使い方

1. KitchenTimer.cs をProjectウィンドウの中の好きなところに置く

2. timerインスタンスの生成

新しいタイマーを作る。
※このスクリプトを貼り付けたオブジェクトが消滅すると、タイマーもなくなるので注意。

    var timer = this.gameObject.AddComponent<KitchenTimer>(); 

カウントアップ(0, 1, 2 ...) timer.StartCountUp

1.0秒に1回、処理をする例
time には、その時の時間が少数まで入っている。 「1.13」 「2.04」
場合に合わせて四捨五入して使う

    timer.StartCountUp(1.0f, 
        (time) => 
        {
            // ここに1秒に1回やりたい処理を書く
            Debug.Log(time);
        }
    );

カウントダウン(30, 29, 28 ...) timer.StartCountDown

残り30秒からスタートして、1秒に1回処理をする例。

    timer.StartCountDown(30.0f, 1.0f, 
        (time) => 
        {
            // ここに1秒に1回やりたい処理を書く
            Debug.Log(time);
        }, 
        () => 
        {
            // 30.0秒のカウントダウンが終わったらここに来る
            Debug.Log("時間切れ");
        }
    );

一時ストップ timer.Stop

    timer.Stop(
        (time)=>
        {
            // time にはタイマーが止まった時の時間が入っている
            Debug.Log(time);
        }
    );

ストップ時点から再開 timer.StartFromStopPoint

    timer.StartFromStopPoint();

最初から測り直し timer.ResetAndReStart

    timer.ResetAndReStart();

タイマーを捨てる(メモリ開放を明示的にしたいとき) timer.Dispose

    timer.Dispose();

さいごに

時間の単位は全て 「秒」 です。変換クラスと上手いこと合わせて使ってやってください。
以上です!

それにしても「キッチンタイマー」て。。。変な命名にハマる時期ってありますよね。。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?