原文链接
按照我的习惯进行修改
完整代码:
///
/// 计时器工具类
///
public class Timer : MonoBehaviour
{
public delegate void CompleteEvent();
public delegate void UpdateEvent(float t);
UpdateEvent updateEvent;
CompleteEvent completedEvent;
bool isEnableLog = true; //是否打印消息
bool isDestory = true; //计时结束后是否销毁
bool isDownNow = false; //是否是倒计时
bool isIgnoreTimeScale = true; //是否忽略时间速率
float timeTarget; //目标时间
float timeStart; //开始计时时间
float offsetTime; //计时偏差
bool isBegin; //是否开始计时
bool isEnd; //计时是否结束
bool isRepeate; //是否重复执行
float now; //正计时
float downNow; //倒计时
public bool IsEnableLog
{
get { return isEnableLog; }
set { isEnableLog = value; }
}
//是否使用游戏的真实时间 不依赖游戏的时间速度
float TimeNow
{
get { return isIgnoreTimeScale ? Time.realtimeSinceStartup : Time.time; }
}
///
/// 创建计时器
///
public static Timer CreateTimer(string name = "Timer")
{
GameObject go = new GameObject(name);
Timer timer = go.AddComponent<Timer>();
return timer;
}
///
/// 设置参数,开始计时
///
/// 目标时间
/// 完成回调函数
/// 计时器进程回调函数
/// 是否是倒计时
/// 是否重复
/// 是否忽略时间倍数
/// 完成后是否销毁
/// 是否开始
public void StartTiming(float timeTarget, CompleteEvent onCompleted, UpdateEvent update = null,
bool isDownNow = false, bool isRepeate = false, bool isIgnoreTimeScale = true, bool isDestory = true,
float offsetTime = 0)
{
this.timeTarget = timeTarget;
this.isIgnoreTimeScale = isIgnoreTimeScale;
this.isRepeate = isRepeate;
this.isDestory = isDestory;
this.offsetTime = offsetTime;
this.isDownNow = isDownNow;
this.isBegin = true;
this.isEnd = false;
timeStart = TimeNow;
if (onCompleted != null)
completedEvent = onCompleted;
if (update != null)
updateEvent = update;
}
void Update()
{
if (isBegin)
{
now = TimeNow - offsetTime - timeStart;
downNow = timeTarget - now;
if (updateEvent != null)
{
if (isDownNow)
{
updateEvent(downNow);
}
else
{
updateEvent(now);
}
}
if (now > timeTarget)
{
if (completedEvent != null)
completedEvent();
if (!isRepeate)
Destory();
else
RestartTimer();
}
}
}
///
/// 获取剩余时间
///
///
public float GetTimeNow()
{
return Mathf.Clamp(timeTarget - now, 0, timeTarget);
}
///
/// 计时结束
///
public void Destory()
{
isBegin = false;
isEnd = true;
if (isDestory)
{
Destroy(gameObject);
}
}
float _pauseTime;
///
/// 暂停计时
///
public void PauseTimer()
{
if (isEnd)
{
if (isEnableLog) Debug.LogWarning("计时已经结束!");
}
else
{
if (isBegin)
{
isBegin = false;
_pauseTime = TimeNow;
}
}
}
///
/// 继续计时
///
public void ConnitueTimer()
{
if (isEnd)
{
if (isEnableLog) Debug.LogWarning("计时已经结束!请重新计时!");
}
else
{
if (!isBegin)
{
offsetTime += (TimeNow - _pauseTime);
isBegin = true;
}
}
}
///
/// 重新计时
///
public void RestartTimer()
{
timeStart = TimeNow;
offsetTime = 0;
}
///
/// 更改目标时间
///
///
public void ChangeTargetTime(float time_)
{
timeTarget = time_;
timeStart = TimeNow;
}
///
/// 游戏暂停调用
///
///
void OnApplicationPause(bool isPause_)
{
if (isPause_)
{
PauseTimer();
}
else
{
ConnitueTimer();
}
}
}
工具更改:
using UnityEngine;
namespace MTools.Timer
{
///
/// 计时器工具类
///
public class Timer : MonoBehaviour
{
private System.Action completedEvent;
private System.Action<float> progressEvent;
private bool isDestory = true; //计时结束后是否销毁
private bool isDownNow = false; //是否是倒计时
private bool isIgnoreTimeScale = true; //是否忽略时间速率
private float timeTarget; //目标时间
private float timeStart; //开始计时时间
private float offsetTime; //计时偏差
private bool isBegin; //是否开始计时
private bool isEnd; //计时是否结束
private bool isRepeate; //是否重复执行
private float now; //正计时
private float downNow; //倒计时
//是否使用游戏的真实时间 不依赖游戏的时间速度
private float TimeNow
{
get { return isIgnoreTimeScale ? Time.realtimeSinceStartup : Time.time; }
}
///
/// 创建计时器
///
///
/// 计时任务完成是否销毁
/// 是否倒计时
/// 是否重复
/// 是否忽略时间倍数
///
public static Timer CreateTimer(GameObject node, bool isDestory, bool isDownNow = false, bool isRepeate = false, bool isIgnoreTimeScale = true)
{
if (node == null) return null;
Timer timer = node.GetComponent<Timer>();
if (timer == null)
timer = node.AddComponent<Timer>();
timer.isDestory = isDestory;
timer.isDownNow = isDownNow;
timer.isRepeate = isRepeate;
timer.isIgnoreTimeScale = isIgnoreTimeScale;
return timer;
}
///
/// 创建计时器
///
///
/// 计时任务完成是否销毁
/// 是否倒计时
/// 是否重复
/// 是否忽略时间倍数
///
public static Timer CreateTimer(Transform node, bool isDestory, bool isDownNow = false, bool isRepeate = false, bool isIgnoreTimeScale = true)
{
if (node == null) return null;
Timer timer = node.gameObject.GetComponent<Timer>();
if (timer == null)
timer = node.gameObject.AddComponent<Timer>();
timer.isDestory = isDestory;
timer.isDownNow = isDownNow;
timer.isRepeate = isRepeate;
timer.isIgnoreTimeScale = isIgnoreTimeScale;
return timer;
}
///
/// 启动/开始计时
///
/// 目标时间
/// 回调函数
/// 计时偏差
public void StartTimer(float timeTarget, System.Action onCompleted, float offsetTime = 0)
{
this.timeTarget = timeTarget;
this.offsetTime = offsetTime;
timeStart = TimeNow;
if (onCompleted != null)
completedEvent = onCompleted;
isEnd = false;
isBegin = true;
}
///
/// 启动/开始计时
///
/// 目标时间
/// 回调函数
/// 进度回调函数
/// 计时偏差
public void StartTimer(float timeTarget, System.Action onCompleted, System.Action<float> onUpdateEvent, float offsetTime = 0)
{
this.timeTarget = timeTarget;
this.offsetTime = offsetTime;
timeStart = TimeNow;
if (onCompleted != null)
completedEvent = onCompleted;
if (onUpdateEvent != null)
progressEvent = onUpdateEvent;
isEnd = false;
isBegin = true;
}
///
/// 重置计时器参数
///
/// 计时任务完成是否销毁
/// 是否倒计时
/// 是否重复
/// 是否忽略时间倍数
public void ResetOptions(bool isDestory, bool isDownNow = false, bool isRepeate = false, bool isIgnoreTimeScale = true)
{
completedEvent = null;
progressEvent = null;
this.isDestory = isDestory;
this.isDownNow = isDownNow;
this.isIgnoreTimeScale = isIgnoreTimeScale;
timeTarget = 0f;
timeStart = 0f;
offsetTime = 0f;
isBegin = false;
isEnd = false;
this.isRepeate = isRepeate;
now = 0f;
downNow = 0f;
}
void Update()
{
if (isBegin && !isEnd)
{
now = TimeNow - offsetTime - timeStart;
downNow = timeTarget - now;
if (isDownNow)
{
progressEvent?.Invoke(downNow);
}
else
{
progressEvent?.Invoke(now);
}
if (now > timeTarget)
{
completedEvent?.Invoke();
if (isRepeate)
{
timeStart = TimeNow;
offsetTime = 0;
}
else
{
Destory();
}
}
}
}
///
/// 获取剩余时间
///
///
public float GetTimeNow()
{
return Mathf.Clamp(timeTarget - now, 0, timeTarget);
}
///
/// 计时结束
///
public void Destory()
{
isBegin = false;
isEnd = true;
if (isDestory)
{
Destroy(this);
Debug.Log("销毁了");
}
}
float _pauseTime;
///
/// 暂停计时
///
public void PauseTimer()
{
if (isEnd)
{
Debug.LogWarning("计时已经结束!");
}
else
{
if (isBegin)
{
isBegin = false;
_pauseTime = TimeNow;
}
}
}
///
/// 继续计时
///
public void ConnitueTimer()
{
if (isEnd)
{
Debug.LogWarning("计时已经结束!请重新计时!");
}
else
{
if (!isBegin)
{
offsetTime += (TimeNow - _pauseTime);
isBegin = true;
}
}
}
///
/// 更改目标时间
///
/// 目标时间
public void ChangeTargetTime(float timeTarget)
{
this.timeTarget = timeTarget;
timeStart = TimeNow;
}
///
/// 游戏暂停调用
///
///
void OnApplicationPause(bool isPause_)
{
if (isPause_)
{
PauseTimer();
}
else
{
ConnitueTimer();
}
}
}
}
测试代码
/* $Header: 2022/12/07 星期三 下午 04:46:45 MTools 2020.2.6f1 $ */
/*******************************************************************************
*** C O N F I D E N T I A L --- M T O O L S ***
*******************************************************************************
* *
* Project Name : Test *
* *
* File Name : NewBehaviourScript.cs *
* *
* Programmer : MTools *
* *
* Start Date : 2022/12/07 16:46:45 *
* *
* Last Update : 2022/12/07 16:46:45 *
* *
*-----------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
using MTools;
using MTools.Timer;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
namespace M
{
public class NewBehaviourScript : MonoBehaviour
{
Timer timer = null;
void Start()
{
//创建计时器
timer = Timer.CreateTimer(gameObject, false);
//启动计时器
timer.StartTimer(1f, () => Debug.Log("任务重复执行"), (f) => Debug.Log($"进度: {f}"));
//突然不想执行,执行另一个计时任务
timer.ResetOptions(false); //重置参数
timer.StartTimer(2f, () => Debug.Log("新任务不重复执行"), (f) => Debug.Log($"新进度: {f}"));
StartCoroutine(Stop());
}
private IEnumerator Stop()
{
Debug.Log("Stop");
yield return new WaitForSeconds(5f);
timer.ResetOptions(true, false, true);
timer.StartTimer(3f, () => Debug.Log("新新任务重复执行"), (f) => Debug.Log($"新新进度: {f}"));
Debug.Log("StopEnd");
}
}
}
如果要复用同一个Timer, 注意CreateTimer和ResetOptions中指定是否销毁(计时任务完成时)