Unity制作一个定时器Timer

Timer和TimerManager代码
using System.Collections;
using UnityEngine;
public class Timer : MonoBehaviour
{
    public delegate void Notifier();
    public Notifier onTimer;
    public Notifier onTimerReset;
    public Notifier onTimerComplete;
    public float interval;
    public int repeatCount = 0;

    public bool forever
    {
        get
        {
            return repeatCount == 0;
        }
    }
    public float time
    {
        get
        {
            if (running)
            {
                return crtCount * interval + Time.time - startTime;
            }
            return crtCount * interval + crtTime;
        }
    }
    protected float startTime;
    public int count
    {
        get
        {
            return crtCount;
        }
    }
    public bool complete
    {
        get
        {
            if (forever)
            {
                return false;
            }
            return crtCount == repeatCount;
        }
    }
    protected int crtCount = 0;
    protected float crtTime = 0f;
    public bool running = false;
    public void Dispose()
    {
        StopAllCoroutines();
        ClearNotifiers();
    }
    protected void OnDestroy()
    {
        ClearNotifiers();
    }
    public void Reset()
    {
        if (running)
        {
            ClearCoroutine();
        }
        crtCount = 0;
        crtTime = 0f;
        startTime = 0f;

        OnTimerReset();
    }
    public void ResetPlay()
    {
        Play(0f);
        OnTimerReset();
    }
    public void Stop()
    {
        if (running)
        {
            ClearCoroutine();
            crtTime = Time.time - startTime;
            if (crtTime >= interval)
            {
                crtTime = interval - 0.00001f;
            }
        }
    }
    public void Play()
    {
        if (!running)
        {
            Play(time);
        }
    }
    public void Play(float offset)
    {
        if (running)
        {
            ClearCoroutine();
        }

        if (offset < 0)
        {
            offset = 0;
        }
        else if (offset > 0 && !forever)
        {
            float totalTime = interval * repeatCount;
            if (offset > totalTime)
            {
                offset = totalTime;
            }
        }
        crtCount = Mathf.FloorToInt(offset / interval);
        crtTime = offset % interval;
        startTime = Time.time - crtTime;

        if (crtCount < repeatCount || forever)
        {
            StartCoroutine(Run());
            running = true;
        }
    }
    private IEnumerator Run()
    {
        while (true)
        {
            if (crtTime > 0)
            {
                yield return new WaitForSeconds(interval - crtTime);
                OnTimer();
                crtTime = 0;
            }
            yield return new WaitForSeconds(interval);
            OnTimer();
        }
    }
    private void OnTimer()
    {
        crtCount++;
        if (!forever && crtCount >= repeatCount)
        {
            ClearCoroutine();
        }
        else
        {
            startTime = Time.time;
        }

        if (onTimer != null)
        {
            onTimer();
        }
        if (onTimerComplete != null && !forever && crtCount >= repeatCount)
        {
            onTimerComplete();
        }
    }
    private void OnTimerReset()
    {
        if (onTimerReset != null)
        {
            onTimerReset();
        }
    }
    public void ClearNotifiers()
    {
        onTimer = null;
        onTimerComplete = null;
        onTimerReset = null;
    }
    private void ClearCoroutine()
    {
        StopAllCoroutines();
        running = false;
    }
}
using System.Collections.Generic;
using UnityEngine;

public class TimerManager : MonoBehaviour
{
    private const string MonoSingleName = "TimerManager";
    private static GameObject monoSingle;
    private static TimerManager instance;

    private bool destroyed { get; set; }

    public static bool HasInstance
    {
        get
        {
            return instance != null;
        }
    }

    public static TimerManager InitInstance()
    {
        return Instance;
    }


    public static TimerManager Instance
    {
        get
        {
            if (monoSingle == null)
            {
                monoSingle = GameObject.Find(MonoSingleName);
                if (monoSingle == null)
                {
                    monoSingle = new GameObject();
                    monoSingle.name = MonoSingleName;
                    //monoSingle.transform.SetParent(Core.Instance.transform);
                }
            }

            if (instance == null)
            {
                instance = monoSingle.GetComponent<TimerManager>();
                if (instance == null)
                {
                    instance = monoSingle.AddComponent<TimerManager>();
                }
                if (monoSingle.transform.parent == null)
                {
                    DontDestroyOnLoad(monoSingle);
                }
            }
            return instance;
        }
    }
    private GameObject timerGO;
    private List<Timer> freeTimers;

    protected void Awake()
    {
        timerGO = new GameObject();
        timerGO.name = "TimerCpts";
        timerGO.transform.SetParent(monoSingle.transform);

        freeTimers = new List<Timer>();
    }

    internal void Dispose()
    {
        if (timerGO != null)
        {
            Timer[] timers = timerGO.GetComponents<Timer>();
            for (int i = 0; i < timers.Length; i++)
            {
                timers[i].Dispose();
            }

            GameObject.Destroy(timerGO);
            timerGO = null;
        }
        freeTimers = null;
    }

    protected void OnDestroy()
    {
        if (!destroyed)
        {
            Dispose();
        }
    }

    /// <summary>
    /// 创建一个定时器
    /// </summary>
    /// <param name="interval">每N秒触发一次onTimer事件</param>
    /// <param name="repeatCount">一总触发多少次onTimer,所有出发完成后会自动删除,如果为0,forever</param>
    /// <returns></returns>
    private Timer CreateTimer(float interval, int repeatCount)
    {
        Timer timer = timerGO.AddComponent<Timer>();
        timer.interval = interval;
        timer.repeatCount = repeatCount;
        return timer;
    }

    /// <summary>
    /// 临时租用
    /// </summary>
    /// <param name="interval">间隔</param>
    /// <param name="repeatCount">最多触发次数如果为0,表示forever</param>
    /// <returns></returns>
    public Timer BorrowTimer(float interval, int repeatCount)
    {
        Timer timer;
        if (freeTimers.Count > 0)
        {
            timer = freeTimers[0];
            freeTimers.RemoveAt(0);
            timer.enabled = true;
            timer.interval = interval;
            timer.repeatCount = repeatCount;
        }
        else
        {
            timer = CreateTimer(interval, repeatCount);
        }
        return timer;
    }

    /// <summary>
    /// 归还,备下次用
    /// </summary>
    /// <param name="timer"></param>
    public void ReturnTimer(Timer timer)
    {
        if (destroyed)
            return;
        if (freeTimers.IndexOf(timer) != -1)
        {
            Debug.LogError("TimeMgr.ReturnTimer:freeTimers.IndexOf(timer) != -1,退还逻辑出错,请检查逻辑,同一个Timer被多次退还");
            return;
        }
        timer.Stop();
        timer.ClearNotifiers();
        timer.Reset();
        timer.enabled = false;
        freeTimers.Add(timer);
    }
}

测试用法:

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

public class Test : MonoBehaviour
{
    private Timer timer;
    void Start()
    {
        if (timer==null)
        {
            timer = TimerManager.Instance.BorrowTimer(3,5);
            timer.onTimer += Print;
            timer.Play();
        }
    }

    private void Print()
    {
        Debug.Log(Time.time);
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

 

 

 

posted @ 2024-05-21 15:03  weigang  阅读(154)  评论(0编辑  收藏  举报