当前位置: 首页 > article >正文

Unity 封装一个依赖于MonoBehaviour的计时器(上) 基本功能

        灵感来自下面这本书的协程部分,因此我就自己尝试写了一个

       我的新书Unity3D游戏开发(第3版) | 雨松MOMO程序研究院

   如果你不知道什么是协程:unity保姆级教程之协同程序_unity协同-CSDN博客 

    一句话概括:协程就是单线程的异步操作,其作用于Unity的主线程

1.我写了如下几个功能(只展示无参数):

基础校验

    private bool CheckCount(int count)
    {
        if (count < 0)
        {
            Debug.LogError("循环次数不能为负数!");
            return false;
        }
        return true;
    }

    private bool CheckTime(float time)
    {
        if (time < 0)
        {
            Debug.LogError("等待时间不能为负数!");
            return false;
        }
        return true;
    }

1.等待受缩放时间影响后的秒数

  public void WaitTime(float waitTime, Action callback)
  {
      if (CheckTime(waitTime))
      {
          StartCoroutine(WaitTimeHandle(waitTime, () => callback?.Invoke()));
      }
  }

2.等待不受缩放时间影响后的秒数

    public void WaitRealTime(float waitTime, Action callback)
    {
        if (CheckTime(waitTime))
        {
            StartCoroutine(WaitRealTimeHandle(waitTime, () => callback?.Invoke()));
        }
    }

2.按固定时间间隔循环执行

 public void LoopTime(float spacing, int overNumber, Action callback)
 {
     if (CheckTime(spacing) && CheckCount(overNumber))
     {
         StartCoroutine(LoopTimeHandle(spacing, overNumber, () => callback?.Invoke()));
     }
 }

3.等待固定帧执行一次

    public void WaitFrame(int frameCount, Action callback)
    {
        if (CheckCount(frameCount))
        {
            StartCoroutine(WaitFrameHandle(frameCount, () => callback?.Invoke()));
        }
    }

4.进度反馈

    public void WaitTimeWithProgress(float waitTime, Action<float> progressCallback, Action completeCallback)
    {
        if (CheckTime(waitTime))
        {
            StartCoroutine(ProgressTimer(waitTime, progressCallback, completeCallback));
        }
    }

    private IEnumerator ProgressTimer(float duration, Action<float> progress, Action complete)
    {
        float startTime = Time.time;
        while (Time.time - startTime < duration)
        {
            progress?.Invoke((Time.time - startTime) / duration);
            yield return null;
        }
        complete?.Invoke();
    }

5.等待当前帧渲染结束执行回调(本帧执行)

    public void WaitForEndOfFrame(Action callback)
    {
        StartCoroutine(WaitForEndOfFrameHandle(callback));
    }

    private IEnumerator WaitForEndOfFrameHandle(Action callback)
    {
        yield return new WaitForEndOfFrame();
        callback?.Invoke();
    }

2.总览

      回调函数我写了无参 一参 两参的版本 可以自行添加参数

using System;
using System.Collections;
using UnityEngine;

public class TimeManager : MonoBehaviour
{
    private static TimeManager instance;
    public static TimeManager Instance => instance;

    private void Awake()
    {
        if (instance == null)
        {
            instance = this;
        }
    }

    private bool CheckCount(int count)
    {
        if (count < 0)
        {
            Debug.LogError("循环次数不能为负数!");
            return false;
        }
        return true;
    }

    private bool CheckTime(float time)
    {
        if (time < 0)
        {
            Debug.LogError("等待时间不能为负数!");
            return false;
        }
        return true;
    }

    #region 等待固定时间秒
    /// <summary>
    /// 等待固定时间以后执行回调
    /// </summary>
    /// <param name="waitTime">等待时间(秒)</param>
    /// <param name="callback">回调函数</param>
    public void WaitTime(float waitTime, Action callback)
    {
        if (CheckTime(waitTime))
        {
            StartCoroutine(WaitTimeHandle(waitTime, () => callback?.Invoke()));
        }
    }

    public void WaitTime<T>(float waitTime, T param, Action<T> callback)
    {
        if (CheckTime(waitTime))
        {
            StartCoroutine(WaitTimeHandle(waitTime, () => callback?.Invoke(param)));
        }
    }

    public void WaitTime<T, K>(float waitTime, T param1, K param2, Action<T, K> callback)
    {
        if (CheckTime(waitTime))
        {
            StartCoroutine(WaitTimeHandle(waitTime, () => callback?.Invoke(param1, param2)));
        }
    }

    private IEnumerator WaitTimeHandle(float waitTime, Action action)
    {
        yield return new WaitForSeconds(waitTime);
        action?.Invoke();
    }
    #endregion
    #region 等待固定时间秒(不受缩放影响)
    /// <summary>
    /// 等待固定时间以后执行回调(不受Time.timeScale影响)
    /// </summary>
    /// <param name="waitTime">等待时间(秒)</param>
    /// <param name="callback">回调函数</param>
    public void WaitRealTime(float waitTime, Action callback)
    {
        if (CheckTime(waitTime))
        {
            StartCoroutine(WaitRealTimeHandle(waitTime, () => callback?.Invoke()));
        }
    }

    public void WaitRealTime<T>(float waitTime, T param, Action<T> callback)
    {
        if (CheckTime(waitTime))
        {
            StartCoroutine(WaitRealTimeHandle(waitTime, () => callback?.Invoke(param)));
        }
    }

    public void WaitRealTime<T, K>(float waitTime, T param1, K param2, Action<T, K> callback)
    {
        if (CheckTime(waitTime))
        {
            StartCoroutine(WaitRealTimeHandle(waitTime, () => callback?.Invoke(param1, param2)));
        }
    }

    private IEnumerator WaitRealTimeHandle(float waitTime, Action action)
    {
        yield return new WaitForSecondsRealtime(waitTime);
        action?.Invoke();
    }
    #endregion

    #region 按固定时间间隔循环执行
    public void LoopTime(float spacing, int overNumber, Action callback)
    {
        if (CheckTime(spacing) && CheckCount(overNumber))
        {
            StartCoroutine(LoopTimeHandle(spacing, overNumber, () => callback?.Invoke()));
        }
    }

    public void LoopTime<T>(float spacing, int overNumber, T param, Action<T> callback)
    {
        if (CheckTime(spacing) && CheckCount(overNumber))
        {
            StartCoroutine(LoopTimeHandle(spacing, overNumber, () => callback?.Invoke(param)));
        }
    }

    public void LoopTime<T, K>(float spacing, int overNumber, T param1, K param2, Action<T, K> callback)
    {
        if (CheckTime(spacing) && CheckCount(overNumber))
        {
            StartCoroutine(LoopTimeHandle(spacing, overNumber, () => callback?.Invoke(param1, param2)));
        }
    }

    private IEnumerator LoopTimeHandle(float spacing, int overNumber, Action action)
    {
        for (int i = 0; i < overNumber; i++)
        {
            yield return new WaitForSeconds(spacing);
            action?.Invoke();
        }
    }
    #endregion

    #region 等待固定帧执行一次
    public void WaitFrame(int frameCount, Action callback)
    {
        if (CheckCount(frameCount))
        {
            StartCoroutine(WaitFrameHandle(frameCount, () => callback?.Invoke()));
        }
    }

    public void WaitFrame<T>(int frameCount, T param, Action<T> callback)
    {
        if (CheckCount(frameCount))
        {
            StartCoroutine(WaitFrameHandle(frameCount, () => callback?.Invoke(param)));
        }
    }

    public void WaitFrame<T, K>(int frameCount, T param1, K param2, Action<T, K> callback)
    {
        if (CheckCount(frameCount))
        {
            StartCoroutine(WaitFrameHandle(frameCount, () => callback?.Invoke(param1, param2)));
        }
    }

    private IEnumerator WaitFrameHandle(int frameCount, Action action)
    {
        for (int i = 0; i < frameCount; i++)
        {
            yield return null;
        }
        action?.Invoke();
    }
    #endregion

    #region 进度反馈
    public void WaitTimeWithProgress(float waitTime, Action<float> progressCallback, Action completeCallback)
    {
        if (CheckTime(waitTime))
        {
            StartCoroutine(ProgressTimer(waitTime, progressCallback, completeCallback));
        }
    }

    private IEnumerator ProgressTimer(float duration, Action<float> progress, Action complete)
    {
        float startTime = Time.time;
        while (Time.time - startTime < duration)
        {
            progress?.Invoke((Time.time - startTime) / duration);
            yield return null;
        }
        complete?.Invoke();
    }

    public void WaitTimeWithProgress<T>(float waitTime, T param, Action<float, T> progressCallback, Action<T> completeCallback)
    {
        if (CheckTime(waitTime))
        {
            StartCoroutine(ProgressTimer(waitTime, param, progressCallback, completeCallback));
        }
    }

    private IEnumerator ProgressTimer<T>(float duration, T param, Action<float, T> progress, Action<T> complete)
    {
        float startTime = Time.time;
        while (Time.time - startTime < duration)
        {
            progress?.Invoke((Time.time - startTime) / duration, param);
            yield return null;
        }
        complete?.Invoke(param);
    }

    public void WaitTimeWithProgress<T, K>(float waitTime, T param1, K param2, Action<float, T, K> progressCallback, Action<T, K> completeCallback)
    {
        if (CheckTime(waitTime))
        {
            StartCoroutine(ProgressTimer(waitTime, param1, param2, progressCallback, completeCallback));
        }
    }

    private IEnumerator ProgressTimer<T, K>(float duration, T param1, K param2, Action<float, T, K> progress, Action<T, K> complete)
    {
        float startTime = Time.time;
        while (Time.time - startTime < duration)
        {
            progress?.Invoke((Time.time - startTime) / duration, param1, param2);
            yield return null;
        }
        complete?.Invoke(param1, param2);
    }
    #endregion

    #region 等待当前帧结束执行回调
    public void WaitForEndOfFrame(Action callback)
    {
        StartCoroutine(WaitForEndOfFrameHandle(callback));
    }

    private IEnumerator WaitForEndOfFrameHandle(Action callback)
    {
        yield return new WaitForEndOfFrame();
        callback?.Invoke();
    }

    public void WaitForEndOfFrame<T>(T param, Action<T> callback)
    {
        StartCoroutine(WaitForEndOfFrameHandle(param, callback));
    }

    private IEnumerator WaitForEndOfFrameHandle<T>(T param, Action<T> callback)
    {
        yield return new WaitForEndOfFrame();
        callback?.Invoke(param);
    }

    public void WaitForEndOfFrame<T, K>(T param1, K param2, Action<T, K> callback)
    {
        StartCoroutine(WaitForEndOfFrameHandle(param1, param2, callback));
    }

    private IEnumerator WaitForEndOfFrameHandle<T, K>(T param1, K param2, Action<T, K> callback)
    {
        yield return new WaitForEndOfFrame();
        callback?.Invoke(param1, param2);
    }
    #endregion
    public void Stop(IEnumerator func)
    {
        StopCoroutine(func);
    }

    public void StopAll()
    {
        StopAllCoroutines();
    }

    public TimeChainContext StartChain()
    {
        return new TimeChainContext(this);
    }
}

3.Ai给出了如下拓展思路       

        优先级高

        链式调用扩展

        物理时间步长同步

         优先级中

        调试可视化工具

        网络同步时钟

        优先级低

      自动化测试框架集成

      使用Mono管理类去管理该脚本从而摆脱Mono的控制

        我目前的需求没有这么复杂,当作一个简单的计时器使用

        其是依赖于Unity的这一点可以用await和async来替代,但是可能涉及到了多线程,我这块学了但是用的不多还需加强


http://www.kler.cn/a/583491.html

相关文章:

  • 图片OCR多区域识别并重命名图片文件,基于Python和阿里云的实现方案
  • C#中常量详解
  • 理解C语言中的extern关键字
  • qt之No executable specified
  • QT系列教程(21) 自定义模型的拖动实现
  • ARM嵌入式低功耗高安全:工业瘦客户机的智慧城市解决方案
  • 6. MySQL 索引的数据结构(详细说明)
  • 机器人领域专业名词汇总
  • SpringBoot快速接入DeepSeek-R1大模型(JDK1.8)
  • 机器人交互系统 部署构建
  • Flutter 学习之旅 之 flutter 在设备上进行 全面屏 设置/隐藏状态栏/隐藏导航栏 设置
  • Leetcode做题记录----2
  • 深入理解 C# 反射:基础原理与实际应用
  • 第14章 kali linux(网络安全防御实战--蓝军武器库)
  • c++ 嵌入汇编的方式实现int型自增
  • QT创建项目(项目模板、构建系统、选择类、构建套件)
  • NLP常见任务专题介绍(3)-垂直领域的聊天机器人搭建详细教程
  • Ollama+ WebUI 部署deepseek-r1
  • 第13章贪心算法
  • 【mysql】centOS7安装mysql详细操作步骤!