鸟语天空
游戏定时器
post by:追风剑情 2022-1-6 16:10
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
/// <summary>
/// 游戏定时器
/// </summary>
public class GameTimer : MonoBehaviour
{
    public static GameTimer Instance { get; private set; }

    private List<Context> contexts = new List<Context>();

    private void Awake()
    {
        Instance = this;
        DontDestroyOnLoad(gameObject);
    }

    private void OnDestroy()
    {
        Clear();
        Instance = null;
    }

    void Update()
    {
        for (int i = 0; i < contexts.Count; i++)
        {
            var ctx = contexts[i];
            if (ctx == null || ctx.action == null)
            {
                contexts.RemoveAt(i);
                break;
            }
            if (ctx.triggerTime <= Time.time)
            {
                if (ctx.repeating)
                {
                    ctx.action?.Invoke(ctx.p);
                    ctx.triggerTime = Time.time + ctx.interval;
                }
                else
                {
                    //必须先RemoveAt,因为回调函数中可能会进行注册或移除操作,导致索引错位。
                    contexts.RemoveAt(i);
                    ctx.action?.Invoke(ctx.p);
                    ctx.action = null;
                    ctx.p = null;
                    i--;
                }
                break;
            }
        }
    }

    private void Register(Context context)
    {
        if (context == null || context.action == null)
            return;
        //如果triggerTime未设值
        if (context.triggerTime < 0)
            context.triggerTime = Time.time + context.duration;
        contexts.Add(context);
        Debug.LogFormat("[GameTimer] Register {0}", context.action.Method.Name);
    }

    //注册定时器方法
    public void Register(UnityAction<object> action, float duration = 1.0f, object p = null)
    {
        if (action == null)
            return;
        Context context = new Context();
        context.action = action;
        context.duration = duration;
        context.p = p;
        Register(context);
    }

    //注册定时器方法(按间隔时间重复调用)
    public void RegisterRepeating(UnityAction<object> action, float duration = 1.0f, float interval = 1.0f, object p = null)
    {
        Context context = new Context();
        context.action = action;
        context.duration = duration;
        context.interval = interval;
        context.p = p;
        context.repeating = true;
        Register(context);
    }

    //移除定时器方法
    public void Remove(UnityAction<object> action)
    {
        if (action == null)
            return;
        for (int i = 0; i < contexts.Count; i++)
        {
            var ctx = contexts[i];
            if (ctx == null || ctx.action == null)
                continue;
            if (ctx.action.GetHashCode() == action.GetHashCode())
            {
                Debug.LogFormat("[GameTimer] Remove {0}", ctx.action.Method.Name);
                ctx.action = null;
                contexts.RemoveAt(i);
                i--;
            }
        }
    }

    //清空
    public void Clear()
    {
        for (int i = 0; i < contexts.Count; i++)
        {
            var ctx = contexts[i];
            if (ctx == null)
                continue;
            ctx.action = null;
            ctx.p = null;
        }
        contexts.Clear();
    }

    private class Context
    {
        //定时器回传参数
        public object p;
        //回调方法
        public UnityAction<object> action;
        //延迟调用
        public float duration = 1f;
        //调用间隔时间
        public float interval = 1f;
        //是否重复调用
        public bool repeating = false;
        //触发时间(Time.time + x)
        public float triggerTime = -1f;
    }
}
评论:
发表评论:
昵称

邮件地址 (选填)

个人主页 (选填)

内容