最近因为项目,也因为一些其他事情而导致学习的停止,抽个空来记录下C#内置的事件在Unity3D中的使用。
我需要让一个物体对鼠标悬停做出事件的响应的情况下,我们通常会创建一个继承MonoBehaviour的脚本然后挂到该物体上,然后为该脚本创建OnMouseOver方法,例如我们需要悬停来改变物体颜色,可能会这样写。
using UnityEngine; using System.Collections; public class ChangeColor : MonoBehaviour { void OnMouseOver() { transform.GetComponent<Renderer>().material.color = Color.red; } }
这样就实现了我们需要的目的,但是,问题又来了,我们需要让另外的对象响应该事件呢?
解决办法是保持另外对象的脚本引用,然后在你的OnMouseOver方法中调用它。这样做没问题,但是不够好。因为你需要一直保持另外一个对象的引用,如果想通知多个对象要保持多个引用。代码会变得很乱。
还有一种方法是Messages 消息 。
使用SendMessage或SendMessageUpwards方法。看上去这是解决问题的最好办法,但是这些方法存在严重的缺陷,以我的观点,你应该尽量不去使用它们。
这些方法的语法并不灵活,你需要传递一个方法名字的字符串,这样做很容易出错。另外这些方法只能用在同一个对象的附属关系中。换句话说你只能在下面几种情况中调用SendMessage或SendMessageUpwards方法,这些方法的脚本被关联到同一个GameObject中,或者被关联到这个GameObject的祖先关系对象中。
幸运的是有一个更好的解决办法,这就是C#内置的事件机制。
我们先来看一下如何在Unity3D中使用事件机制。
public class ChangeColor : MonoBehaviour {
public delegate void EventHandler(GameObject e);
public event EventHandler MouseOver;
void OnMouseOver()
{
if (MouseOver != null)
MouseOver(this.gameObject);
}
}
我们把该脚本挂的物体A,然后新建一个脚本。
public class ChangeColor1 : MonoBehaviour { private GameObject _gameObject; // Use this for initialization void Start () { [...] _gameObject.GetComponent<ChangeColor>().MouseOver += Listener; [...] } void Listener(GameObject g) {
Debug.Log("响应事件的物体是 " + this.gameObject.name);
Debug.Log("触发事件的物体是 "+g.name);
}
}
这种方式比用消息更灵活,因为它可以被用在任何一个脚本中,而不仅仅在同一个对象附属关系中。如果在整个应用中保持一个单例模式的对象,你就可以监听任何从这个对象分发出来的事件。另外一个重要特点,同一个监听方法可以响应不同对象的事件。通过传递事件源对象的引用作为参数,你总会知道哪个对象分发了事件。