#游戲unity-VR場景漫游#統一管理回調函數——觀察者模式


我們不防把上面這樣一件工作成為一個計數器——Timer(這個名字可能不太恰當),把需要被通知者成為觀察者——Oberver,而像下載管理器這樣的對象成為一個主題——Subject。

首先,我們來定義觀察者和主題對象。TimerObserverOrSubject.cs如下:

using UnityEngine;  
using System.Collections;  

public class TimerObserverOrSubject : MonoBehaviour {  

    virtual protected void OnDestroy ()  
    {  
        if(Singleton.IsCreatedInstance("TimerController"))  
        {  
            (Singleton.getInstance("TimerController") as TimerController).ClearTimer(this);  
        }  
    }  
}  

TimerObserverOrSubject.cs的內容非常簡單,它的工作就是在該腳本被析構時,及時地從計數器管理器里面刪除涉及這個對象的所有Timer。

計數器管理器的腳本——TimerController.cs如下:

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

public class TimerController : MonoBehaviour {  

    public delegate void OnCallBack(object arg);  
    public delegate bool OnIsCanDo(object arg);  

    public class Timer {  
        public TimerObserverOrSubject m_Observer;  
        public OnCallBack m_Callback = null;  
        public object m_Arg = null;  

        public TimerObserverOrSubject m_Subject;  
        public OnIsCanDo m_IsCanDoFunc = null;   
        public object m_ArgForIsCanDoFunc = null;  

        public float m_PassTime = 0;  

        public Timer(TimerObserverOrSubject observer, OnCallBack callback, object arg,   
            TimerObserverOrSubject subject, OnIsCanDo isCanDoFunc, object argForIsCanDo) {  
            m_Observer = observer;  
            m_Callback = callback;  
            m_Arg = arg;  

            m_Subject = subject;  
            m_IsCanDoFunc = isCanDoFunc;  
            m_ArgForIsCanDoFunc = argForIsCanDo;  

            m_PassTime = 0;  
                }  

        public Timer(TimerObserverOrSubject observer, OnCallBack callback, object arg, float time) {  
            m_Observer = observer;  
            m_Callback = callback;  
            m_Arg = arg;  

            m_Subject = null;  
            m_IsCanDoFunc = null;  
            m_ArgForIsCanDoFunc = null;  

            m_PassTime = time;  
        }  
        }  
    private List<Timer> m_Timers = new List<Timer>();  
    private List<Timer> m_NeedRemoveTimer = new List<Timer>();  
    private List<Timer> m_CurRunTimer = new List<Timer>();  

    /// <summary> 
    /// Sets the timer. 
    /// </summary> 
    /// <param name='observer'> 
    /// The TimerObserverOrSubject you need to listen 
    /// </param> 
    /// <param name='callback'> 
    /// The callback when condition is true. 
    /// </param> 
    /// <param name='arg'> 
    /// Argument of the callback. 
    /// </param> 
    /// <param name='observer'> 
    /// The TimerObserverOrSubject you need to observe 
    /// </param> 
    /// <param name='isCanDoFunc'> 
    /// The condition function, must return a boolean. 
    /// </param> 
    /// <param name='argForIsCanDo'> 
    /// Argument for condition function. 
    /// </param> 
    public void SetTimer(TimerObserverOrSubject observer, OnCallBack callback ,object arg,  
        TimerObserverOrSubject subject, OnIsCanDo isCanDoFunc,object argForIsCanDo) {  
        if (observer == null || subject == null || callback == null || isCanDoFunc == null) return;  

        if (isCanDoFunc(argForIsCanDo)) {  
            callback(arg);  
            return;  
        }  

        Timer timer = new Timer(observer, callback, arg, subject, isCanDoFunc, argForIsCanDo);       
        m_Timers.Add(timer);  
    }  

    /// <summary> 
    /// Sets the timer. 
    /// </summary> 
    /// <param name='observer'> 
    /// The TimerObserverOrSubject you need to listen 
    /// </param> 
    /// <param name='callback'> 
    /// The callback when time is up. 
    /// </param> 
    /// <param name='arg'> 
    /// Argument of the callback. 
    /// </param> 
    /// <param name='timepass'> 
    /// Timepass before calling the callback. 
    /// </param> 
    public void SetTimer(TimerObserverOrSubject observer, OnCallBack callback , object arg, float timepass) {  
        if (observer != null && callback != null) {             
            Timer timer = new Timer(observer, callback, arg, timepass);  
            m_Timers.Add(timer);  
        }  
    }  

    /// <summary> 
    /// Clears all Timers of the observer. 
    /// </summary> 
    /// <param name='observer'> 
    /// The TimerObserverOrSubject you need to clear 
    /// </param> 
    public void ClearTimer(TimerObserverOrSubject observer) {  
        List<Timer> needRemovedTimers = new List<Timer>();  

        foreach (Timer timer in m_Timers) {  
            if (timer.m_Observer == observer || timer.m_Subject) {  
                needRemovedTimers.Add(timer);  
            }  
        }  

        foreach (Timer timer in needRemovedTimers) {  
            m_Timers.Remove(timer);  
        }  
    }  

        // Update is called once per frame 
        void Update ()   
    {  
        InitialCurTimerDict();  
        RunTimer();  
        RemoveTimer();  
        }  

    private void InitialCurTimerDict() {  
        m_CurRunTimer.Clear();  

        foreach (Timer timer in m_Timers) {  
            m_CurRunTimer.Add(timer);  
        }  
    }  

    private void RunTimer() {  
        m_NeedRemoveTimer.Clear();  

        foreach (Timer timer in m_CurRunTimer) {          
            if (timer.m_IsCanDoFunc == null) {  
                timer.m_PassTime =  timer.m_PassTime - Time.deltaTime;  
                if (timer.m_PassTime < 0) {  
                    timer.m_Callback(timer.m_Arg);  
                    m_NeedRemoveTimer.Add(timer);  
                }  
            } else {  
                if (timer.m_IsCanDoFunc(timer.m_ArgForIsCanDoFunc)) {  
                    timer.m_Callback(timer.m_Arg);  
                    m_NeedRemoveTimer.Add(timer);  
                }  
            }     
        }  
    }  

    private void RemoveTimer() {  
        foreach (Timer timer in m_NeedRemoveTimer) {  
            if (m_Timers.Contains(timer)) {  
                m_Timers.Remove(timer);  
            }  
        }  
    }  

}  

定義了回調函數的類型:

public delegate void OnCallBack(object arg);  
public delegate bool OnIsCanDo(object arg);  

定義了一個數據類型Timer用於保存一個計數器的各個信息。

接下來,就是TimerController的兩個重要的SetTimer函數。我們先看第一個SetTimer函數:

public void SetTimer(TimerObserverOrSubject observer, OnCallBack callback ,object arg,  
    TimerObserverOrSubject subject, OnIsCanDo isCanDoFunc,object argForIsCanDo) {  
    if (observer == null || subject == null || callback == null || isCanDoFunc == null) return;  

    if (isCanDoFunc(argForIsCanDo)) {  
        callback(arg);  
        return;  
       }  

    Timer timer = new Timer(observer, callback, arg, subject, isCanDoFunc, argForIsCanDo);       
    m_Timers.Add(timer);  
}  

根據函數說明可以看出,它負責建立一個計數器,當subject的isCanDoFunc(argForIsCanDo)函數返回true時,通知observer,執行observer的callback(arg)函數。

第二個SetTimer函數更簡單:

public void SetTimer(TimerObserverOrSubject observer, OnCallBack callback , object arg, float timepass) {  
    if (observer != null && callback != null) {             
        Timer timer = new Timer(observer, callback, arg, timepass);  
        m_Timers.Add(timer);  
    }  
}  

它負責建立一個計數器,在timepass的時間后,通知observer,執行observer的callback(arg)函數。

Update()函數里面負責檢查所有Timer是否可以觸發以及是否需要刪除


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com