unity 消息分发
2015-11-12 09:52
627 查看
有2种方法,第一种,封装U3D中的发消息函数,自己写一个事件机制出来。第2种,用C#内置的事件机制。
第一种方法,下面这个类是Digital-tutors出的Unity Mobile Game Development这一套教程里06.Communication with Notification Center里的事件机制类,他是用JS写的,我把这个脚本翻译成了C#的。并加了详细的中文注释。本质是一个观察者模式的实现,该类是一个单例的类,用哈希表来保存场景中的所有消息,哈希表中每个键值对,表示的是【某一消息(函数名)——该消息的所有观察者线性表】。最终以u3d
api的SendMessage函数将消息发了过去,所以只能传递一个数据实参,受SendMessage函数本身限制。但是你传的参数可以是脚本对象,把参数写到对象中,这样就可以传多个参数了。
=======================NotificationCenter.cs======================================================
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
// 2013年8月23日11:19:44,郭志程
/// <summary>
/// 信息中心类,用来处理GameObjects相互发消息。本质是观察者模式。
/// 通过AddObserver函数注册观察者,RemoveObserver注销观察者。
/// 内部通过哈希表对场景中所有的消息进行管理
/// </summary>
public class NotificationCenter : MonoBehaviour {
private
static NotificationCenter defaultCenter = null;
///
<summary>
///
单例模式, 在场景中自动造一个挂有NotificationCenter脚本的Default Notification Center游戏物体,如果手动创建了一个则不再创建
///
</summary>
public
static NotificationCenter DefaultCenter ()
{
if
(null == defaultCenter) {
GameObject
notificationObject = new GameObject("Default Notification Center");
defaultCenter =
notificationObject.AddComponent<NotificationCenter>();
}
return
defaultCenter;
}
//
哈希表包含了所有的发送的信息。其中每个键值对,表示的是【某一消息——该消息的所有观察者线性表】
private
Hashtable notifications = null;
void
Awake() {
this.notifications
= new Hashtable();
}
///
<summary>
///
注册观察者
///
</summary>
public
void AddObserver(Component observer, string name) { AddObserver(observer, name, null); }
public
void AddObserver(Component observer, string name, Component sender) {
//
对观察者的名字进行检查
if
(name == null || name == "") { Debug.Log("在AddObserver函数中指定的是空名称!."); return; }
//
哈希表中的值是List,new list
if
(null == this.notifications[name]) {
this.notifications[name]
= new List<Component>();
}
//
该条消息的所有观察者,通过List将他拉出来对其操作
List<Component>
notifyList = this.notifications[name] as List<Component>;
//
将观察者加入到哈希表中值LIST中去,也就是注册上了
if
(!notifyList.Contains(observer)) { notifyList.Add(observer); }
}
///
<summary>
///
注销观察者
///
</summary>
public
void RemoveObserver(Component observer, string name) {
//
该条消息的所有观察者,通过List将他拉出来对其操作
List<Component>
notifyList = this.notifications[name] as List<Component>;
if
(null != notifyList) {
//
删除这个已注册的观察者
if
(notifyList.Contains(observer)) { notifyList.Remove(observer); }
//
如果这个消息没有观察者,则在哈希表中删除这个消息关键字
if
(notifyList.Count == 0) { this.notifications.Remove(name); }
}
}
///
<summary>
/// 事件源把发消息出去
///
</summary>
public
void PostNotification(Component aSender, string aName) { PostNotification(aSender, aName, null); }
public
void PostNotification(Component aSender, string aName, object aData) { PostNotification(new Notification(aSender, aName, aData)); }
public
void PostNotification(Notification aNotification) {
if
(aNotification.name == null || aNotification.name == "") { Debug.Log("Null name sent to PostNotification."); return; }
//
该条消息的所有观察者,通过List将他拉出来对其操作
List<Component>
notifyList = this.notifications[aNotification.name] as List<Component>;
if
(null == notifyList) { Debug.Log("在PostNotification的通知列表中未找到: " + aNotification.name); return; }
List<Component>
observersToRemove = new List<Component>();
foreach
(Component observer in notifyList) {
if
(!observer) {
observersToRemove.Add(observer);
}
else {
//
最终以u3d api的SendMessage函数将消息发了过去,所以只能传递一个数据实参,受SendMessage函数本身限制
observer.SendMessage(aNotification.name,
aNotification, SendMessageOptions.DontRequireReceiver);
}
}
//
清除所有无效的观察者
foreach
(Component observer in observersToRemove) {
notifyList.Remove(observer);
}
}
}
/// <summary>
/// 通信类是物体发送给接受物体的一个通信类型。这个类包含发送的游戏物体(U3D的Component类对象,
/// 而不是GameObject),通信的名字(函数名),可选的数据实参
/// </summary>
public class Notification {
public
Component sender;
public
string name;
public
object data;
//
构造函数
public
Notification(Component aSender, string aName) { sender = aSender; name = aName; data = null; }
public
Notification(Component aSender, string aName, object aData) { sender = aSender; name = aName; data = aData; }
}
==================================================================================================
怎么用,很简单,就跟写事件是一样的。观察者注册事件,事件源发出事件,观察者就对其响应,对其处理。下面我写个简单的小例子演示如何使用。
==================TestTongXing_source.cs==========================================================
using UnityEngine;
using System.Collections;
//此教程通信类的测试,事件源
public class TestTongXing_source : MonoBehaviour {
private
A aa = null;
void
Start () {
aa
= new A(10,48);
}
void
Update () {
if(Input.GetKeyUp(KeyCode.P)){
//
事件源,将消息发出去,注册了的观察者会接受消息,进行对应的处理
NotificationCenter.DefaultCenter().PostNotification(this,
"printShow", this);
}
}
public
A getA(){
return
this.aa;
}
}
public class A {
public
int i, j;
public
A(int i,int j) {
this.i
= i;
this.j
= j;
}
}
==================================================================================================
我在update里写,按下P键事件源就发出事件,对这个事件注册监听的观察者就会对其处理。
接下来是观察者
===============================TestTongXing.cs====================================================
using UnityEngine;
using System.Collections;
// 此教程通信类的测试,观察者
public class TestTongXing : MonoBehaviour {
private
A aa = null;
void
Start () {
//
注册,观察者,注册后才会接受消息,对消息进行对应的处理
NotificationCenter.DefaultCenter().AddObserver(this,
"printShow");
}
void
printShow(Notification note) {
Debug.Log(transform
+ "从," + note.sender + "," + "接收一个信息内容:" + note.data + ",通知名称为:" + note.name);
aa
= ((TestTongXing_source)(note.data)).getA();
Debug.Log("i
= " + aa.i + ", j = " + aa.j);
}
}
==================================================================================================
在start里注册监听事件,并写出了监听事件的实现函数,对其处理。注意我得到参数那里的类型转换,因为所有的参数都是以object类型传过去的,所有任何类型都可以传。
在场景里建了个CUBE和SPHERE,一个挂测试的事件源脚本,一个挂观察者脚本。
总结,这个脚本确实写的还是很不错的,1.写完这个脚本,对C#的事件实现能有更好的理解。肯定也有用到LIST和哈希表来搞定吧。2.手写实现了观察者模式,这样脚本和脚本之间没有了getComponent这样的紧耦合,而是观察者使用ADD函数注册监听,事件源可以不知道观察者的存在,只管POST发出事件。3.因为是用U3D
API的发消息函数,所以支持协程函数,这个我自己测试过了,而用C#内置的事件就不支持。不过缺点是U3D API的发消息函数是用反射来实现的,所以速度比较慢,C#内置的事件是用委托实现的,速度快。
第2种方法,大家可以看看这篇文章,http://zijan.iteye.com/blog/871207,讲的就挺好。在easy touch等这种触屏插件就是用的C#的事件机制来响应各种触屏的效果的。
第一种方法,下面这个类是Digital-tutors出的Unity Mobile Game Development这一套教程里06.Communication with Notification Center里的事件机制类,他是用JS写的,我把这个脚本翻译成了C#的。并加了详细的中文注释。本质是一个观察者模式的实现,该类是一个单例的类,用哈希表来保存场景中的所有消息,哈希表中每个键值对,表示的是【某一消息(函数名)——该消息的所有观察者线性表】。最终以u3d
api的SendMessage函数将消息发了过去,所以只能传递一个数据实参,受SendMessage函数本身限制。但是你传的参数可以是脚本对象,把参数写到对象中,这样就可以传多个参数了。
=======================NotificationCenter.cs======================================================
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
// 2013年8月23日11:19:44,郭志程
/// <summary>
/// 信息中心类,用来处理GameObjects相互发消息。本质是观察者模式。
/// 通过AddObserver函数注册观察者,RemoveObserver注销观察者。
/// 内部通过哈希表对场景中所有的消息进行管理
/// </summary>
public class NotificationCenter : MonoBehaviour {
private
static NotificationCenter defaultCenter = null;
///
<summary>
///
单例模式, 在场景中自动造一个挂有NotificationCenter脚本的Default Notification Center游戏物体,如果手动创建了一个则不再创建
///
</summary>
public
static NotificationCenter DefaultCenter ()
{
if
(null == defaultCenter) {
GameObject
notificationObject = new GameObject("Default Notification Center");
defaultCenter =
notificationObject.AddComponent<NotificationCenter>();
}
return
defaultCenter;
}
//
哈希表包含了所有的发送的信息。其中每个键值对,表示的是【某一消息——该消息的所有观察者线性表】
private
Hashtable notifications = null;
void
Awake() {
this.notifications
= new Hashtable();
}
///
<summary>
///
注册观察者
///
</summary>
public
void AddObserver(Component observer, string name) { AddObserver(observer, name, null); }
public
void AddObserver(Component observer, string name, Component sender) {
//
对观察者的名字进行检查
if
(name == null || name == "") { Debug.Log("在AddObserver函数中指定的是空名称!."); return; }
//
哈希表中的值是List,new list
if
(null == this.notifications[name]) {
this.notifications[name]
= new List<Component>();
}
//
该条消息的所有观察者,通过List将他拉出来对其操作
List<Component>
notifyList = this.notifications[name] as List<Component>;
//
将观察者加入到哈希表中值LIST中去,也就是注册上了
if
(!notifyList.Contains(observer)) { notifyList.Add(observer); }
}
///
<summary>
///
注销观察者
///
</summary>
public
void RemoveObserver(Component observer, string name) {
//
该条消息的所有观察者,通过List将他拉出来对其操作
List<Component>
notifyList = this.notifications[name] as List<Component>;
if
(null != notifyList) {
//
删除这个已注册的观察者
if
(notifyList.Contains(observer)) { notifyList.Remove(observer); }
//
如果这个消息没有观察者,则在哈希表中删除这个消息关键字
if
(notifyList.Count == 0) { this.notifications.Remove(name); }
}
}
///
<summary>
/// 事件源把发消息出去
///
</summary>
public
void PostNotification(Component aSender, string aName) { PostNotification(aSender, aName, null); }
public
void PostNotification(Component aSender, string aName, object aData) { PostNotification(new Notification(aSender, aName, aData)); }
public
void PostNotification(Notification aNotification) {
if
(aNotification.name == null || aNotification.name == "") { Debug.Log("Null name sent to PostNotification."); return; }
//
该条消息的所有观察者,通过List将他拉出来对其操作
List<Component>
notifyList = this.notifications[aNotification.name] as List<Component>;
if
(null == notifyList) { Debug.Log("在PostNotification的通知列表中未找到: " + aNotification.name); return; }
List<Component>
observersToRemove = new List<Component>();
foreach
(Component observer in notifyList) {
if
(!observer) {
observersToRemove.Add(observer);
}
else {
//
最终以u3d api的SendMessage函数将消息发了过去,所以只能传递一个数据实参,受SendMessage函数本身限制
observer.SendMessage(aNotification.name,
aNotification, SendMessageOptions.DontRequireReceiver);
}
}
//
清除所有无效的观察者
foreach
(Component observer in observersToRemove) {
notifyList.Remove(observer);
}
}
}
/// <summary>
/// 通信类是物体发送给接受物体的一个通信类型。这个类包含发送的游戏物体(U3D的Component类对象,
/// 而不是GameObject),通信的名字(函数名),可选的数据实参
/// </summary>
public class Notification {
public
Component sender;
public
string name;
public
object data;
//
构造函数
public
Notification(Component aSender, string aName) { sender = aSender; name = aName; data = null; }
public
Notification(Component aSender, string aName, object aData) { sender = aSender; name = aName; data = aData; }
}
==================================================================================================
怎么用,很简单,就跟写事件是一样的。观察者注册事件,事件源发出事件,观察者就对其响应,对其处理。下面我写个简单的小例子演示如何使用。
==================TestTongXing_source.cs==========================================================
using UnityEngine;
using System.Collections;
//此教程通信类的测试,事件源
public class TestTongXing_source : MonoBehaviour {
private
A aa = null;
void
Start () {
aa
= new A(10,48);
}
void
Update () {
if(Input.GetKeyUp(KeyCode.P)){
//
事件源,将消息发出去,注册了的观察者会接受消息,进行对应的处理
NotificationCenter.DefaultCenter().PostNotification(this,
"printShow", this);
}
}
public
A getA(){
return
this.aa;
}
}
public class A {
public
int i, j;
public
A(int i,int j) {
this.i
= i;
this.j
= j;
}
}
==================================================================================================
我在update里写,按下P键事件源就发出事件,对这个事件注册监听的观察者就会对其处理。
接下来是观察者
===============================TestTongXing.cs====================================================
using UnityEngine;
using System.Collections;
// 此教程通信类的测试,观察者
public class TestTongXing : MonoBehaviour {
private
A aa = null;
void
Start () {
//
注册,观察者,注册后才会接受消息,对消息进行对应的处理
NotificationCenter.DefaultCenter().AddObserver(this,
"printShow");
}
void
printShow(Notification note) {
Debug.Log(transform
+ "从," + note.sender + "," + "接收一个信息内容:" + note.data + ",通知名称为:" + note.name);
aa
= ((TestTongXing_source)(note.data)).getA();
Debug.Log("i
= " + aa.i + ", j = " + aa.j);
}
}
==================================================================================================
在start里注册监听事件,并写出了监听事件的实现函数,对其处理。注意我得到参数那里的类型转换,因为所有的参数都是以object类型传过去的,所有任何类型都可以传。
在场景里建了个CUBE和SPHERE,一个挂测试的事件源脚本,一个挂观察者脚本。
总结,这个脚本确实写的还是很不错的,1.写完这个脚本,对C#的事件实现能有更好的理解。肯定也有用到LIST和哈希表来搞定吧。2.手写实现了观察者模式,这样脚本和脚本之间没有了getComponent这样的紧耦合,而是观察者使用ADD函数注册监听,事件源可以不知道观察者的存在,只管POST发出事件。3.因为是用U3D
API的发消息函数,所以支持协程函数,这个我自己测试过了,而用C#内置的事件就不支持。不过缺点是U3D API的发消息函数是用反射来实现的,所以速度比较慢,C#内置的事件是用委托实现的,速度快。
第2种方法,大家可以看看这篇文章,http://zijan.iteye.com/blog/871207,讲的就挺好。在easy touch等这种触屏插件就是用的C#的事件机制来响应各种触屏的效果的。
相关文章推荐
- Unity3d优化
- 【Unity实用小方法】随机生成不重复的数字
- 【笨木头Unity】入门之旅007:Demo之四处找死(二)_主角移动和旋转
- 蒙皮的网格渲染器
- PrefabType 预置类型
- cardboard sdk for unity 下载地址
- Unity3D-单例模式
- Unity+NGUI性能优化方法总结
- 增强现实(AR)笔记2:Vuforia+Unity例程ObjectRecognition
- Unity3D-动态加载资源
- 在Unity中生成二维码
- 转:Oculus Unity Development Guide开发指南(2015-7-21更新)
- Unity3D-Terrain地形编辑
- Unity加载进度条
- Unity3D开发技巧
- Unity3D物体移动方式总结
- Unity3D让物体从规定时间内移动到某一位置
- Vector3 Lerp差值计算
- Unity修改自动生成的代码模板
- 如何防止Unity3D代码被反编译?