談到鏈?zhǔn)骄幊蹋蠹叶紩氲椒椒〝U(kuò)展伴鳖,具象一些节值,就是想到DoTween,但是DoTween鏈?zhǔn)剿枷肜锩孢€有個(gè)很有意思的分支榜聂,那就是
委托+方法+返回This
完成的鏈?zhǔn)骄幊谈懔啤1疚闹攸c(diǎn)來了,那就是學(xué)習(xí)一下這個(gè)思路實(shí)現(xiàn)一個(gè)小巧實(shí)用的定時(shí)器须肆。
代碼
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace TimeTrigger
{
public class Timer
{
static List<Timer> timers = new List<Timer>();
Action<float> UpdateEvent;
Action EndEvent;
private float _time = -1; // 用戶設(shè)定的定時(shí)時(shí)長
private bool _loop; // 是否循環(huán)執(zhí)行
private bool _ignorTimescale; // 是否忽略Timescale
private string _flag;// 用戶指定的定時(shí)器標(biāo)志匿乃,便于手動(dòng)清除、暫停休吠、恢復(fù)
private static TimerDriver driver = null;//拿驅(qū)動(dòng)器的引用只是為了初始化驅(qū)動(dòng)器
private float CurrentTime { get { return _ignorTimescale ? Time.realtimeSinceStartup : Time.time; } }// 獲得當(dāng)前時(shí)間
private float cachedTime;//緩存時(shí)間
float timePassed; //已經(jīng)過去的時(shí)間
private bool _isFinish = false; //計(jì)時(shí)器是否結(jié)束
private bool _isPause = false; //計(jì)時(shí)器是否暫停
private static bool showLog = true; //確認(rèn)是否輸出Debug信息
public static bool ShowLog { set { showLog = value; } }
public bool IsPause // 暫停計(jì)時(shí)器
{
get { return _isPause; }
set
{
if (value)
{
Pause();
}
else
{
Resum();
}
}
}
/// <summary>
/// 構(gòu)造定時(shí)器
/// </summary>
/// <param name="time">定時(shí)時(shí)長</param>
/// <param name="flag">定時(shí)器標(biāo)識符</param>
/// <param name="loop">是否循環(huán)</param>
/// <param name="ignorTimescale">是否忽略TimeScale</param>
private Timer(float time, string flag, bool loop = false, bool ignorTimescale = true)
{
if (null == driver) driver = TimerDriver.Get; //初始化Time驅(qū)動(dòng)
_time = time;
_loop = loop;
_ignorTimescale = ignorTimescale;
cachedTime = CurrentTime;
if (timers.Exists((v) => { return v._flag == flag; }))
{
if (showLog) Debug.LogWarningFormat("【TimerTrigger(容錯(cuò))】:存在相同的標(biāo)識符【{0}】扳埂!", flag);
}
_flag = string.IsNullOrEmpty(flag) ? GetHashCode().ToString() : flag;//設(shè)置辨識標(biāo)志符
}
private void Pause() // 暫停計(jì)時(shí)
{
if (!_isFinish)
{
_isPause = true;
}
}
private void Resum() // 繼續(xù)計(jì)時(shí)
{
if (!_isFinish&&_isPause)
{
cachedTime = CurrentTime-timePassed;
_isPause = false;
}
}
private void Update() // 刷新定時(shí)器
{
if (!_isFinish && !_isPause) //運(yùn)行中
{
timePassed = CurrentTime - cachedTime;
if (null != UpdateEvent) UpdateEvent(Mathf.Clamp01(timePassed / _time));
if (timePassed >= _time)
{
if (null != EndEvent) EndEvent();
if (_loop)
{
cachedTime = CurrentTime;
}
else
{
Stop();
}
}
}
}
private void Stop() // 回收定時(shí)器
{
if (timers.Contains(this))
{
timers.Remove(this);
}
_time = -1;
_isFinish = true;
_isPause = false;
UpdateEvent = null;
EndEvent = null;
}
#region--------------------------靜態(tài)方法擴(kuò)展-------------------------------------
#region-------------添加定時(shí)器---------------
/// <summary>
/// 添加定時(shí)觸發(fā)器
/// </summary>
/// <param name="time">定時(shí)時(shí)長</param>
/// <param name="flag">定時(shí)器標(biāo)識符</param>
/// <param name="loop">是否循環(huán)</param>
/// <param name="ignorTimescale">是否忽略TimeScale</param>
public static Timer AddTimer(float time, string flag = "", bool loop = false, bool ignorTimescale = true)
{
Timer timer = new Timer(time, flag, loop, ignorTimescale);
timers.Add(timer);
return timer;
}
#endregion
#region-------------刷新所有定時(shí)器---------------
public static void UpdateAllTimer()
{
for (int i = 0; i < timers.Count; i++)
{
if (null != timers[i])
{
timers[i].Update();
}
}
}
#endregion
#region-------------暫停和恢復(fù)定時(shí)器---------------
/// <summary>
/// 暫停用戶指定的計(jì)時(shí)觸發(fā)器
/// </summary>
/// <param name="flag">指定的標(biāo)識符</param>
public static void PauseTimer(string flag)
{
Timer timer = timers.Find((v) => { return v._flag == flag; });
if (null != timer)
{
timer.Pause();
}
}
/// <summary>
/// 恢復(fù)用戶指定的計(jì)時(shí)觸發(fā)器
/// </summary>
/// <param name="flag">指定的標(biāo)識符</param>
public static void ResumTimer(string flag)
{
Timer timer = timers.Find((v) => { return v._flag == flag; });
if (null != timer)
{
timer.Resum();
}
}
#endregion
#region-------------刪除定時(shí)器---------------
/// <summary>
/// 刪除用戶指定的計(jì)時(shí)觸發(fā)器
/// </summary>
/// <param name="flag">指定的標(biāo)識符</param>
public static void DelTimer(string flag)
{
Timer timer = timers.Find((v) => { return v._flag == flag; });
if (null != timer)
{
timer.Stop();
}
}
/// <summary>
/// 刪除用戶指定的計(jì)時(shí)觸發(fā)器
/// </summary>
/// <param name="flag">指定的定時(shí)器</param>
public static void DelTimer(Timer timer)
{
if (timers.Contains(timer))
{
timer.Stop();
}
}
/// <summary>
/// 刪除用戶指定的計(jì)時(shí)觸發(fā)器
/// </summary>
/// <param name="completedEvent">指定的完成事件(直接賦值匿名函數(shù)無效)</param>
public static void DelTimer(Action completedEvent)
{
Timer timer = timers.Find((v) => { return v.EndEvent == completedEvent; });
if (null != timer)
{
timer.Stop();
}
}
/// <summary>
/// 刪除用戶指定的計(jì)時(shí)觸發(fā)器
/// </summary>
/// <param name="updateEvent">指定的Update事件(直接賦值匿名函數(shù)無效)</param>
public static void DelTimer(Action<float> updateEvent)
{
Timer timer = timers.Find((v) => { return v.UpdateEvent == updateEvent; });
if (null != timer)
{
timer.Stop();
}
}
#endregion
#endregion
#region-------------添加事件-------------------
public Timer OnCompleted(Action completedEvent) //添加完成事件
{
if (null == EndEvent)
{
EndEvent = completedEvent;
}
return this;
}
public Timer OnUpdated(Action<float> updateEvent) //添加update更新事件
{
if (null == UpdateEvent)
{
UpdateEvent = updateEvent;
}
return this;
}
#endregion
#region ---------------運(yùn)行中的定時(shí)器參數(shù)修改-----------
public void Setloop(bool loop) // 設(shè)置運(yùn)行中的定時(shí)器的loop狀態(tài)
{
if (!_isFinish)
{
_loop = loop;
}
}
public void SetIgnoreTimeScale(bool ignoreTimescale)// 設(shè)置運(yùn)行中的定時(shí)器的ignoreTimescale狀態(tài)
{
if (!_isFinish)
{
_ignorTimescale = ignoreTimescale;
}
}
#endregion
}
public class TimerDriver : MonoBehaviour
{
#region 單例
private static TimerDriver _instance;
public static TimerDriver Get
{
get
{
if (null == _instance)
{
_instance = FindObjectOfType<TimerDriver>() ?? new GameObject("TimerEntity").AddComponent<TimerDriver>();
}
return _instance;
}
}
private void Awake()
{
_instance = this;
}
#endregion
private void Update()
{
Timer.UpdateAllTimer();
}
}
}
Tips:上面腳本為了節(jié)省篇幅,刪除了很多注釋和輸出Log信息瘤礁,可以下載下面的Demo體驗(yàn)更好阳懂,Demo含示例。
使用示例:
Tips:使用
Timer.DelTimer("12545");
即可隨時(shí)停止計(jì)時(shí)器柜思,當(dāng)然岩调,DelTimer也提供了多個(gè)重載。
動(dòng)畫示例:
Tips: 演示了延時(shí)+是否循環(huán)+是否忽略TimeScale+回調(diào)赡盘,當(dāng)然也包含Lambda表達(dá)式支持下的多參數(shù)回調(diào)号枕。
Tips:由于所有定時(shí)器的驅(qū)動(dòng)是同一個(gè),并非Itween的那種對誰起作用就綁定在誰身上驅(qū)動(dòng)陨享。所以葱淳,如果回調(diào)中用到了游戲?qū)嶓w對象且對象總是顯示隱藏不停切換的話,建議定時(shí)器也隨之暫停和恢復(fù).避免游戲?qū)ο蟛豢梢娏伺坠茫〞r(shí)器依舊觸發(fā)的尷尬局面(Itween是隨著游戲?qū)ο蟮娘@示隱藏自動(dòng)暫停和恢復(fù)的赞厕,畢竟就在那個(gè)游戲?qū)ο笊向?qū)動(dòng)嘛)
寫到最后:
這個(gè)定時(shí)器使用了靜態(tài)的管理器,所以請養(yǎng)成銷毀游戲?qū)ο髸r(shí)主動(dòng)移除事件的好習(xí)慣哈~
這個(gè)計(jì)時(shí)核心算法(假裝是算法哈)除了上面這個(gè)方案定硝,還有-=(+=)Time.deltatime皿桑,還有 協(xié)程
說道協(xié)程,這里筆者也不是不想封裝,有诲侮,只是后來發(fā)現(xiàn)協(xié)程的頻繁開啟停止發(fā)現(xiàn)有安全問題镀虐。所以摒棄了。
再說協(xié)程怎么點(diǎn)對點(diǎn)關(guān)閉呢沟绪,剛剛好刮便,關(guān)于協(xié)程管理的筆者也恰寫了點(diǎn)文字可以挪步瞧一瞧的;
Unity3D 協(xié)程管理
Unity3D IEnumerator 做一個(gè)通用的定時(shí)器
筆者編程實(shí)數(shù)小菜級別绽慈,互相學(xué)習(xí)咯诺核。
Demo下載:https://pan.baidu.com/s/1pHSX6-6cTfI6KEKy2xqKmA
擴(kuò)展閱讀
【大話鏈?zhǔn)骄幊讨〞r(shí)器Timer(四)】-開發(fā)者專欄-【游戲蠻牛】久信,有木有很熟悉的感覺?嗯哼漓摩,就是本文的詳盡版啦~
標(biāo)簽: 定時(shí)器裙士,定時(shí)觸發(fā)器, 鏈?zhǔn)骄幊坦鼙校琓imer 腿椎,TimeTrigger