Unity-TimerMgr

以前在开发页游的时候,自己造过很多轮子:TimerMgr 也是其一

现在用 Unity 做开发,也少不了这个功能,所以再次造了个轮子

制作这个功能目的在于,部分场景可替代使用 Unity Coroutine,或是 async/await Task.Delay,因为这两种方式都有 GC 问题

但是 TimerMgr<T>的泛型回调也有 GC 这个是 C#.NET 的问题,但是具体使用消耗最低,可以查看 Git 中的 TimerMgr.cs 的注释说明


运行效果

在这里插入图片描述


C# 应用层代码示例

using UnityEngine;
using UnityEngine.UI;

// author   :   jave.lin
// 测试 TimerMgr
// TimerMgr     无参数 Timer
// TimerMgr<T>  有 T 类型参数的 Timer
public class Testing : MonoBehaviour
{
    public int no_arg_with_time_scale_timer_id = -1;
    public int no_arg_without_time_scale_timer_id = -1;

    public float with_time_scale_count;
    public float without_time_scale_count;

    public Image with_time_scale_img;
    public Image without_time_scale_img;

    public Slider timescale_slider;
    public Text timescale_txt;

    private void Start()
    {
        timescale_slider.value = Time.timeScale;
        timescale_txt.text = timescale_slider.value.ToString();
    }

    public void OnWithTimeScaleAddTimerBtnClick()
    {
        if (no_arg_with_time_scale_timer_id == -1)
        {
            no_arg_with_time_scale_timer_id = TimerMgr.Inst.AddTimer(no_arg_with_time_scale_timer_update, no_arg_with_time_scale_timer_complete, 0.1f, 0, true);
            Debug.Log($"OnWithTimeScaleAddTimerBtnClick, AddTimer, id : {no_arg_with_time_scale_timer_id}");
        }
    }

    public void OnWithTimeScaleRemoveTimerBtnClick()
    {
        if (no_arg_with_time_scale_timer_id != -1)
        {
            var remove_success = TimerMgr.Inst.RemoveTimerById(no_arg_with_time_scale_timer_id);
            Debug.Log($"OnWithTimeScaleRemoveTimerBtnClick, RemoveTimerById, id : {no_arg_with_time_scale_timer_id}, remove_success : {remove_success}");
            no_arg_with_time_scale_timer_id = -1;
        }
    }

    private void no_arg_with_time_scale_timer_update()
    {
        Debug.Log($"no_arg_with_time_scale_timer_update");
        with_time_scale_count += 0.1f;
        if (with_time_scale_count > 1.0f)
        {
            with_time_scale_count = 0.0f;
        }
        with_time_scale_img.fillAmount = with_time_scale_count;
    }

    private void no_arg_with_time_scale_timer_complete()
    {
        Debug.Log($"no_arg_with_time_scale_timer_complete");
    }

    //==========================
    public void OnWithoutTimeScaleAddTimerBtnClick()
    {
        if (no_arg_without_time_scale_timer_id == -1)
        {
            no_arg_without_time_scale_timer_id = TimerMgr.Inst.AddTimer(no_arg_without_time_scale_timer_update, no_arg_without_time_scale_timer_complete, 0.1f, 0, false);
            Debug.Log($"OnWithoutTimeScaleAddTimerBtnClick, AddTimer, id : {no_arg_without_time_scale_timer_id}");
        }
    }

    public void OnWithoutTimeScaleRemoveTimerBtnClick()
    {
        if (no_arg_without_time_scale_timer_id != -1)
        {
            var remove_success = TimerMgr.Inst.RemoveTimerById(no_arg_without_time_scale_timer_id);
            Debug.Log($"OnWithoutTimeScaleRemoveTimerBtnClick, RemoveTimerById, id : {no_arg_without_time_scale_timer_id}, remove_success : {remove_success}");
            no_arg_without_time_scale_timer_id = -1;
        }
    }

    private void no_arg_without_time_scale_timer_update()
    {
        Debug.Log($"no_arg_without_time_scale_timer_update");
        without_time_scale_count += 0.1f;
        if (without_time_scale_count > 1.0f)
        {
            without_time_scale_count = 0.0f;
        }
        without_time_scale_img.fillAmount = without_time_scale_count;
    }

    private void no_arg_without_time_scale_timer_complete()
    {
        Debug.Log($"no_arg_without_time_scale_timer_complete");
    }
    //==========================

    public void OnTimeScaleSlider()
    {
        Time.timeScale = timescale_slider.value;
        timescale_txt.text = Time.timeScale.ToString();
    }

    //==========================

    public void OnDelaySayHiBtnClick()
    {
        TimerMgr<string>.Inst.AddTimer(name => { Debug.Log($"Hi, {name}"); }, "Jave", null, null);
    }
}

Timer原来参考下面的 Project


Project

backup:

### 创建和管理事件计时器 在Unity中创建和管理事件计时器可以通过封装一个专门用于管理定时任务的类来完成。这不仅有助于保持项目的整洁有序,还能提高代码的可维护性和重用率。 对于计时器的需求,在项目开发阶段有许多应用场景,如游戏时间计时、验证码倒计时等。因此,设计并实现了这样一个计时器管理工具是非常必要的[^2]。此工具能够有效地帮助开发者简化这些操作流程,并提供更加灵活的时间控制选项。 #### 定义计时器管理类 为了更好地管理和调度多个计时器实例,可以定义一个名为`TimerManager`的静态类作为全局唯一的计时器管理者。该类内部应包含启动新计时器的方法,以及停止指定ID对应的计时器的功能。考虑到可能存在的并发访问情况,建议对该类进行线程安全的设计。 ```csharp using System; using UnityEngine; public static class TimerMgr { private static Dictionary<int, Coroutine> timers = new Dictionary<int, Coroutine>(); private static int currentId = 0; /// <summary> /// Creates a timer that executes an action after the specified delay. /// </summary> public static IDisposable CreateTimer(Action callback, float delayInSeconds){ var id = Interlocked.Increment(ref currentId); // Start coroutine and store it with its ID Coroutine routine = MonoBehaviourInstance.StartCoroutine(TimerRoutine(id, callback, delayInSeconds)); lock(timers) {timers[id]=routine;} return new DisposableAction(()=>StopTimerById(id)); } private static IEnumerator TimerRoutine(int id, Action callback, float delayInSeconds){ yield return new WaitForSeconds(delayInSeconds); // Execute only if not cancelled lock(timers){ if(!timers.ContainsKey(id))yield break; timers.Remove(id); } callback?.Invoke(); } private static void StopTimerById(int id){ lock(timers){ if (!timers.TryGetValue(id,out Coroutine c)) return; MonoBehaviourInstance.StopCoroutine(c); timers.Remove(id); } } } ``` 上述代码展示了如何通过C#语言特性实现一个简单的计时器管理系统。这里使用了字典数据结构存储正在运行中的所有计时器对象及其唯一标识符;当调用者希望终止某个特定计时器时,则可通过传递相应的ID给`StopTimerById()`方法达到目的。此外,还利用了协程机制(`IEnumerator`)配合`WaitForSeconds`等待一定秒数后再执行回调函数[^3]。 需要注意的是,这里的`MonoBehaviourInstance`是一个假设性的单例组件实例,实际应用中应当确保有一个长期存活的游戏物体上挂着此类以便于发起协程。通常情况下可以选择将它挂在DontDestroyOnLoad的对象上来保证其生命周期贯穿整个应用程序运行期间[^4]。 #### 使用示例 下面给出了一段具体的例子说明怎样运用前面提到的技术方案: ```csharp void ExampleUsage(){ // 创建一个新的计时器, => Debug.Log("This message will appear after one second."), 1f); // 如果想要提前取消这个计时器... timerHandle.Dispose(); } ``` 这段代码片段显示了如何轻松地创建一个将在一秒钟之后触发的日志记录语句。如果中途改变主意不再需要这条日志输出的话,只需简单地调用之前获得的处置接口即可立即撤销预约的操作。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值