Unity3D 使用鏈?zhǔn)骄幊趟枷氲腡imer Trigger

談到鏈?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含示例。

使用示例:

添加回調(diào)
Timer交互

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)号枕。

暫停與恢復(fù)

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市夭咬,隨后出現(xiàn)的幾起案子啃炸,更是在濱河造成了極大的恐慌,老刑警劉巖卓舵,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件南用,死亡現(xiàn)場離奇詭異,居然都是意外死亡掏湾,警方通過查閱死者的電腦和手機(jī)裹虫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來融击,“玉大人筑公,你說我怎么就攤上這事∽鹄耍” “怎么了匣屡?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長拇涤。 經(jīng)常有香客問我捣作,道長,這世上最難降的妖魔是什么工育? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任虾宇,我火速辦了婚禮,結(jié)果婚禮上如绸,老公的妹妹穿的比我還像新娘嘱朽。我一直安慰自己旭贬,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布搪泳。 她就那樣靜靜地躺著稀轨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪岸军。 梳的紋絲不亂的頭發(fā)上奋刽,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天,我揣著相機(jī)與錄音艰赞,去河邊找鬼佣谐。 笑死,一個(gè)胖子當(dāng)著我的面吹牛方妖,可吹牛的內(nèi)容都是我干的狭魂。 我是一名探鬼主播,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼党觅,長吁一口氣:“原來是場噩夢啊……” “哼雌澄!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起杯瞻,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤镐牺,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后魁莉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體睬涧,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年旗唁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了宙地。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,643評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡逆皮,死狀恐怖宅粥,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情电谣,我是刑警寧澤秽梅,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站剿牺,受9級特大地震影響企垦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜晒来,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一钞诡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦荧降、人聲如沸接箫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽辛友。三九已至,卻和暖如春剪返,著一層夾襖步出監(jiān)牢的瞬間废累,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工脱盲, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留邑滨,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓钱反,卻偏偏與公主長得像驼修,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子诈铛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,509評論 2 348

推薦閱讀更多精彩內(nèi)容