【Unity技巧】统一管理回调函数——观察者模式
这次的内容有点类似设计模式里的观察者模式。但是和常规意义上的观察者模式也不是完全一致,所以各位就不要咬文嚼字啦!咦?设计模式?!不懂!没关系,说不定你以前就用过。
开场白
实现
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。
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);
关于C#的委托机制,如果有童鞋不了解,请详见官方文档。简单来说,委托类似一个函数指针,常被用于回调函数。
/// <summary>
/// Sets the timer.
/// </summary>
/// <param name='observer'>
/// The observer to observe the subject
/// </param>
/// <param name='callback'>
/// The callback when condition is true.
/// </param>
/// <param name='arg'>
/// Argument of the callback.
/// </param>
/// <param name='subject'>
/// The subject 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 observer to observe the subject
/// </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);
}
}
它负责建立一个计数器,在timepass的时间后,通知observer,执行observer的callback(arg)函数。
例子
using UnityEngine;
using System.Collections; public class TimerSample : TimerObserverOrSubject { private TimerController m_TimerCtr = null; private bool m_IsCanDisplay = false; private string m_DisplayContent = "Hello, candycat!"; // Use this for initialization
void Start () {
m_TimerCtr = Singleton.getInstance("TimerController") as TimerController; //m_TimerCtr.SetTimer(this, Display, m_DisplayContent, 5); m_TimerCtr.SetTimer(this, Display, null, this, IsCanDisplay, null); StartCoroutine(DelayDisplay());
} void Display(object arg) {
if (arg == null) {
Debug.Log(m_DisplayContent);
} else {
string content = arg as string; Debug.Log(content);
}
} bool IsCanDisplay(object arg) {
return m_IsCanDisplay;
} IEnumerator DelayDisplay() {
yield return new WaitForSeconds(5.0f); m_IsCanDisplay = true;
} // Update is called once per frame
void Update () { }
}
首先,它向TimerController请求注册了一个计时器。这里,它的条件是IsCanDisplay函数,它返回bool值m_IsCanDisplay。而这个值将会在5秒后,通过协同函数DelayDisplay来由false置为true。当其为true时,TimerController就将通知TimerSample调用Display函数。
结束语
【Unity技巧】统一管理回调函数——观察者模式的更多相关文章
- Unity 之 C# 利用回调函数实现C++匿名函数
做C++开发的都用过匿名函数很好用,可是C#开发怎么实现呢?前几天做一个拍照功能的时候.我偶然发现某个函数假设是C++的话.用匿名函数太好了,于是開始研究C#的回调,代理.托付等,最后总算是实现了我想 ...
- C++回调函数(callback)的使用
什么是回调函数(callback) 模块A有一个函数foo,他向模块B传递foo的地址,然后在B里面发生某种事件(event)时,通过从A里面传递过来的foo的地址调用foo,通知A发生了什么事 ...
- [转]C++回调函数(callback)的使用
原文地址:http://blog.sina.com.cn/s/blog_6568e7880100p77y.html 什么是回调函数(callback) 模块A有一个函数foo,他向模块B传递fo ...
- jquery的2.0.3版本源码系列(6):2880-3042行,回调对象,对函数的统一管理
目录 1 . 回调对象callbacks的演示 回调的使用有一点像事件绑定,先绑定好,等到有点击事件或者其他时就触发. <script src="js/jquery-2.0.3.js& ...
- 前端基本知识(四):JS的异步模式:1、回调函数;2、事件监听;3、观察者模式;4、promise对象
JavaScript语言将任务的执行模式可以分成两种:同步(Synchronous)和异步(Asychronous). “同步模式”就是一个任务完成之后,后边跟着一个任务接着执行:程序的执行顺序和排列 ...
- 常用js,css文件统一加载方法,并在加载之后调用回调函数
原创内容,转载请注明出处! 为了方便资源管理和提升工作效率,常用的js和css文件的加载应该放在一个统一文件里面完成,也方便后续的资源维护.所以我用js写了以下方法,存放在“sourceControl ...
- Unity C# 调用 C++ DLL 并在 DLL 中调用 C# 的回调函数
Unity C# 调用 C++ DLL 并在 DLL 中调用 C# 的回调函数~~~ 呵呵... 看着有点晕.. 再解释一下就是 在Unity中 使用 C# 调用 C++ 写的 DLL, 但是在 ...
- 观察者模式在One Order回调函数中的应用
例如需求是搞清楚function module CRM_PRODUCT_I_A_CHANGE_ORGM_EC在什么样的场景下会被调用.当然最费时间的做法是设一个断点,然后跑对应的场景,观察断点何时被触 ...
- Lua中用table统一管理需要获取的unity物体
unity上的组件,可以用table统一管理 然后在初始化时候统一给table赋值,这样需要用到时候直接调用table中对应的key便可拿到对应的物体,省下了在脚本开头一堆声明的脚本,这样就不用声明这 ...
随机推荐
- Android简易实战教程--第四十八话《Android - Timer、TimerTask和Handler实现倒计时》
之前本专栏文章中的小案例有写到:第三十九话<Chronometer实现倒计时> 以及使用异步实现倒计时:第三十三话< AsyncTask异步倒计时> 本篇文章 结合Timer. ...
- Android Multimedia框架总结(二十四)MediaMuxer实现手机屏幕录制成gif图
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/53866405 前言:上篇中,介绍 ...
- Mongo DB 初识
前言 2016年伊始,开始研究NoSql.看了couchdb,cloudant,cassandra,redis.却一直没有看过排行榜第一的mongo,实属不该.近期会花时间研究下mongo.本文是初识 ...
- Swift3中dispatch_once废弃的解决办法
在Swift中如果想搞类的单例模式,那么在初始化的时候一般会使用just one time执行的方式,我们使用dispatch_once_t配合调用dispatch_once方法,一般的代码如下: s ...
- Linux 高性能服务器编程——IP协议详解
1 IP服务特点 IP协议是TCP/IP协议族的动力,它为上层协议提供无状态.无连接.不可靠的服务. 无状态:IP通信双方不同步传输数据的状态信息,因此IP数据包的发送.传输和接收都是无序的. ...
- android 网络连接 HttpGet HttpPost方法
1.本文主要介绍利用HttpGet和HtppPost方法来获取网络json数据. 代码如下: public HttpData(String Url,HttpGetDataListener listen ...
- qq安全原理
故事总要有缘由,那么这个故事的缘由就是,当我以前写了一个获取其它进程密码框密码的时候(前几篇博客中有描述),我抱着试一试的心情去试探了一下能不能得到 QQ 的密码,当我抓到密码框的句柄,然后输入给程序 ...
- Spring的DataSource配置、将Hibernate配置全部写到Spring配置
DataSource可以集中管理数据库连接,减少维护工作量,使部署更简单: Spring的DataSource配置:(Spring数据源配置)这里使用dbcp,还有很多其他的如c3p0,jdbc,jn ...
- 小小聊天室 Python实现
相对于Java方式的聊天室,Python同样可以做得到.而且可以做的更加的优雅.想必少了那么多的各种流的Python Socket,你一定会喜欢的. 至于知识点相关的内容,这里就不多说了. UDP方式 ...
- 自制Linux 终端 锁屏防窃助手
很多时候我们不能一直守护在自己的电脑旁边,而且有些文件并不想让别人知道.那么这时候来个锁屏,是再合适不过的了.今天分享一个自制的锁屏工具,如下. 准备 操作系统 : 我这里是ElementaryOS虚 ...