首页 > 其他分享 >Unity中实现Timer定时器

Unity中实现Timer定时器

时间:2022-12-03 16:00:27浏览次数:60  
标签:UpdateMode 定时器 void private Unity Timer using public

前言:好久没写博客了,倒不是没写的了, 现在手里堆着的demo和小功能很多,而是懒,我是真滴懒啊。
需求:1.延迟执行方法;2.循环执行,间隔可控制;3.可以改变更新模式(update、fixedupdate,lateupdate),可以决定是否会受到Unity时间缩放影响;4.调用简单,可复用

思路:
1.改变更新模式和受到unity时间缩放的功能,可以使用全局静态变量控制

2.目前网上做定时器的方法三种:Coroutine、update、invoke,我选的第二种,使用MonoBehavior的update来做更新

3.不搞什么单例Manager之类的,调用麻烦,写的一长串,什么Instance的,看着很low

4.Timer对象只对数据信息做保存之用,更新时间状态等,集中由一个脚本的Update处理,分割数据层和逻辑层

5.虽然大部分使用Timer都是随用随丢,不会暂存,但是我new对象时,仍要保留这个功能,而且还要重置、完成等功能

 实现:

第一步就是先实现UpdateRegister功能,继承自MonoBehavior,使用Unity自己的Update方法。提供给外部注册和取消注册的功能

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

namespace JunFramework
{
    public enum UpdateMode
    {
        Update,
        FixedUpdate,
        LateUpdate
    }

    public enum TimeMode
    {
        Scaled,
        UnScaled
    }
    public class UpdateRegister : MonoBehaviour
    {
        /// <summary>
        /// update注册列表
        /// </summary>
        private static Dictionary<int, Action> update = new Dictionary<int, Action>();

        /// <summary>
        /// fixedupfate注册列表
        /// </summary>
        private static Dictionary<int, Action> fixedupdate = new Dictionary<int, Action>();

        /// <summary>
        /// lateupdate注册列表
        /// </summary>
        private static Dictionary<int, Action> lateupdate = new Dictionary<int, Action>();

        /// <summary>
        /// 全局唯一update下标
        /// </summary>
        private static int updateIndex = 0;
      
        /// <summary>
        /// 是否初始化
        /// </summary>
        private static bool isInit = false;

        /// <summary>
        /// 是否已经初始化
        /// </summary>
        public static bool IsInit
        {
            get => isInit;
        }

        /// <summary>
        /// 注册
        /// </summary>
        /// <param name="mode"></param>
        /// <param name="handler"></param>
        /// <returns></returns>
        public static int Register(UpdateMode mode, Action handler)
        {
            ++updateIndex;
            switch (mode)
            {
                case UpdateMode.Update:
                    update.Add(updateIndex, handler);
                    break;
                case UpdateMode.FixedUpdate:
                    fixedupdate.Add(updateIndex, handler);
                    break;
                case UpdateMode.LateUpdate:
                    lateupdate.Add(updateIndex, handler);
                    break;
            }
            return updateIndex;
        }

        /// <summary>
        /// 根据updateindex取消注册
        /// </summary>
        /// <param name="mode"></param>
        /// <param name="index"></param>
        public static void Cancle(UpdateMode mode, int index)
        {
            switch (mode)
            {
                case UpdateMode.Update:
                    update.Remove(index);
                    break;
                case UpdateMode.FixedUpdate:
                    fixedupdate.Remove(index);
                    break;
                case UpdateMode.LateUpdate:
                    lateupdate.Remove(index);
                    break;
            }
        }

        private void Awake()
        {
            isInit = true;
        }

        private void Update()
        {
            using (var e = update.GetEnumerator())
            {
                if (e.MoveNext())
                {
                    e.Current.Value?.Invoke();
                }
            }
        }

        private void FixedUpdate()
        {
            using (var e = fixedupdate.GetEnumerator())
            {
                if (e.MoveNext())
                {
                    e.Current.Value?.Invoke();
                }
            }
        }

        private void LateUpdate()
        {
            using (var e = lateupdate.GetEnumerator())
            {
                if (e.MoveNext())
                {
                    e.Current.Value?.Invoke();
                }
            }
        }
    }
}

第二步实现Timer对象,存储调用者传入的信息,可获取Timer状态(是否完成?是否正在工作?当前进度?)。可调用开始、结束、暂停、继续、重置、完成功能

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

namespace JunFramework.Timer
{
    public class Timer
    {
        #region timer设置

        /// <summary>
        /// Timer是否自动释放
        /// </summary>
        public static bool IsAutoRelease = true;

        /// <summary>
        /// Timer更新模式
        /// </summary>
        public static UpdateMode TimerUpdateMode = UpdateMode.FixedUpdate;

        /// <summary>
        /// Timer时间是否收到Unity缩放影响
        /// </summary>
        public static TimeMode TimerScaledModel = TimeMode.UnScaled;

        #endregion

        private float currentTime = 0f;//当前时间(0 -- steptime)
        private int currentRepeat = 0;//当前重复次数
        private float stepTime = 0f;//间隔
        private int repeatTimes = 0;//重复次数
        private bool isLoop = false;//是否循环
        private bool isDone = false;//是否完成
        private bool isStart = false;//是否开始
        private int updateIndex = 0;//update注册获取的下标,用于移除update注册
        private Action callback;//回调
        private float timeAcceleration;//每帧增加的时间

        /// <summary>
        /// 是否完成
        /// </summary>
        public bool IsDone
        {
            get => isDone;
        }

        /// <summary>
        /// 当前进度
        /// </summary>
        public float Progress
        {
            get => currentTime / stepTime;
        }

        /// <summary>
        /// 是否正在工作
        /// </summary>
        public bool IsWokring
        {
            get => !isDone && isStart;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="stepTime">间隔时长</param>
        /// <param name="repeatTimes">重复次数</param>
        /// <param name="callback">回调</param>
        public Timer(float stepTime, int repeatTimes, Action callback)
        {
            this.currentTime = 0f;
            this.currentRepeat = 0;
            this.stepTime = stepTime;
            this.repeatTimes = repeatTimes;
            this.isLoop = false;
            this.isDone = false;
            this.timeAcceleration = GetPerTime();
            this.callback = callback;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="stepTime">间隔</param>
        /// <param name="callback">回调</param>
        public Timer(float stepTime, Action callback)
        {
            this.currentTime = 0f;
            this.currentRepeat = 0;
            this.stepTime = stepTime;
            this.repeatTimes = 1;
            this.isLoop = false;
            this.isDone = false;
            this.timeAcceleration = GetPerTime();
            this.callback = callback;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="stepTime">间隔</param>
        /// <param name="isLoop">是否循环</param>
        /// <param name="callback">回调</param>
        public Timer(float stepTime, bool isLoop, Action callback)
        {
            this.currentTime = 0f;
            this.currentRepeat = 0;
            this.stepTime = stepTime;
            this.isLoop = isLoop;
            if (!isLoop)
            {
                this.repeatTimes = 1;
            }
            this.timeAcceleration = GetPerTime();
            this.isDone = false;
            this.callback = callback;
        }

        /// <summary>
        /// 每帧更新
        /// </summary>
        /// <param name="addTime">每帧增加的时间</param>
        private void Update(float addTime)
        {
            if (isDone)
                return;
            if (!isStart)
                return;

            currentTime += addTime;
            if (currentTime >= stepTime)
            {
                callback?.Invoke();
                currentTime = 0f;
                if (!isLoop)
                {
                    ++currentRepeat;
                    if (currentRepeat >= repeatTimes)
                    {
                        isDone = true;
                        if (IsAutoRelease)
                        {
                            Stop();
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 开始计时器
        /// </summary>
        public void Start()
        {
            if (!UpdateRegister.IsInit)
            {
                Debug.LogWarning("UpdateRegister is not init, so this action will not works, please init UpdateRegister first!!!");
                return;
            }
            isStart = true;
            this.updateIndex = UpdateRegister.Register(TimerUpdateMode, () => this.Update(timeAcceleration));
        }

        /// <summary>
        /// 停止计时器(如果只是想暂停可用Pause,stop操作不可恢复)
        /// </summary>
        public void Stop()
        {
            isStart = false;
            isDone = true;
            UpdateRegister.Cancle(TimerUpdateMode, this.updateIndex);
        }

        /// <summary>
        /// 暂停
        /// </summary>
        public void Pause()
        {
            isStart = false;
        }

        /// <summary>
        /// 继续
        /// </summary>
        public void Resume()
        {
            isStart = true;
        }

        /// <summary>
        /// 重置
        /// </summary>
        public void Reset()
        {
            isStart = false;
            isDone = false;
            currentTime = 0f;
            currentRepeat = 0;
        }

        /// <summary>
        /// 不用等待,直接完成
        /// </summary>
        public void Complete()
        {
            if (isLoop)
                return;
            isDone = true;

            int tempRepeat = repeatTimes;
            while (tempRepeat > 0)
            {
                callback?.Invoke();
                --tempRepeat;
            }
            Stop();

        }

        /// <summary>
        /// 通过更新模式和time模式获取每帧更新时间
        /// </summary>
        /// <returns></returns>
        private float GetPerTime()
        {
            float resultTime = 0f;
            if (TimerScaledModel == TimeMode.Scaled && TimerUpdateMode == UpdateMode.FixedUpdate)
            {
                resultTime = Time.fixedDeltaTime;
            }
            else if (TimerScaledModel == TimeMode.UnScaled && TimerUpdateMode == UpdateMode.FixedUpdate)
            {
                resultTime = Time.fixedUnscaledDeltaTime;
            }
            else if (TimerScaledModel == TimeMode.Scaled && TimerUpdateMode == UpdateMode.Update)
            {
                resultTime = Time.deltaTime;
            }
            else if (TimerScaledModel == TimeMode.UnScaled && TimerUpdateMode == UpdateMode.FixedUpdate)
            {
                resultTime = Time.unscaledDeltaTime;
            }
            return resultTime;
        }
    }
}

第三步,简单编写测试代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using JunFramework.Timer;

public class TimerExample : MonoBehaviour
{
    private Timer timer = null;
    // Start is called before the first frame update
    void Start()
    {
        Timer.IsAutoRelease = true;
        Timer.TimerScaledModel = JunFramework.TimeMode.UnScaled;
        Timer.TimerUpdateMode = JunFramework.UpdateMode.FixedUpdate;

        //Example1
        //int i = 0;
        //Timer timer = new Timer(2, 2, () => Debug.Log(i++));
        //timer.Start();

        //Example2
        //timer = new Timer(2, true, () => Debug.Log("执行"));
        //timer.Start();

        //Example3
        timer = new Timer(2, 3, () => Debug.Log("看我看我"));
        timer.Start();
        timer.Complete();

        timer.Reset();
        timer.Start();
    }

    // Update is called once per frame
    void Update()
    {
        //Example2
        //if (Input.GetKeyDown(KeyCode.Space))
        //{
        //    timer.Pause();
        //}
        //else if (Input.GetKeyDown(KeyCode.A))
        //{
        //    timer.Resume();
        //}
    }
}

 

 总结:

本次Timer参考的是公司的lua Timer,其实这Timer也是大神蒙占志写的。我这个是C#写的,用于自己的游戏Demo。接受各种改进建议

标签:UpdateMode,定时器,void,private,Unity,Timer,using,public
From: https://www.cnblogs.com/JunJiang-Blog/p/16948170.html

相关文章

  • Pycharm Community 2020.2.3 Python代码设计软件下载
    关注微信公众号【工控羊】或者微信号【gksheep】,微信公众号后台输入数字编号【0014】即可获取下载链接。......
  • unity 在指定范围内随机生成怪物
    usingUnityEngine;publicclasstest2:MonoBehaviour{publicfloatRandomPos;publicGameObjectMonsterPrefab;privatevoidOnMouseDown()......
  • 【服务器数据恢复】通过自由数据块拼接方法恢复EMC Unity存储误删除数据的案例
    服务器数据恢复环境:EMCUnity某型号存储;存储设备连接的2台硬盘柜上共创建2组独立的POOL;2组POOL共包含21块520字节的硬盘。服务器故障&检测:误操作删除了2组POOL上的部分......
  • ShareSDK for Unity
    本文档使用Unity2019进行演示下载unitypackage从Mob的github地址下载ShareSDK.unitypackage:​​Git地址​​,如下图所示)![image.png]//download.sdk.mob.com/2022/06/22/15/......
  • 思腾合力成为开放通用服务器平台社区(OCSP Community)正式成员
    近日,思腾合力成为开放通用服务器平台社区(OCSPCommunity)的正式成员,愿与社区合作伙伴携手共同打造健康、开放、繁荣的服务器产业生态社区。在近几年“数字中国万里行”的实地......
  • unity RPG Builder v1.1.0.8 插件分享
    仅供学习使用 一款制作RPG游戏的插件,提供了所有RPG游戏的功能包含技能,锻造,强化,任务,对话,背包等让开发者可以简单地点点点实现创造新的装备,怪物,NPC等功能有兴趣的小伙......
  • ElementUI Button定时器
    今天遇到的问题是在做王老师的作业项目中遇到的,就是我要通过邮箱登录,我把这一部分的功能完善了,但是我发现有一个问题,就是可以一直发,这个显然是不行的,因为不加以限制用户可......
  • 定时器:ScheduledExecutorService
    方式二:ScheduledExecutorServiceScheduledExecutorService定时器ScheduledExecutorService是jdk1.5中引入了并发包,目的是为了弥补Timer的缺陷,ScheduledExecutorServic......
  • 定时器:Timer
    定时器定时器是一种控制任务延时调用,或者周期调用的技术。作用:闹钟、定时邮件发送。定时器的实现方式方式一:TimerTimer定时器Timer定时器的特点和存在的问题1、Timer是......
  • FSR-Unity-URP 1.0 的性能和兼容性问题
    1)FSR-Unity-URP1.0的性能和兼容性问题​2)计算大文件MD5耗时问题3)如何监听Unity即将ReloadScript4)如何对Unity游戏的Android崩溃和ANR问题进行符号化解析这是第315篇UW......