在这里我将展示如何结合使用委托、事件以及单例。这个教程针对Unity3D所写,然而,相似的代码可以使用到任何C#或.Net程序中。
为什么我想要知道这个? 作为一个自学编程的人,我发现自己在代码中使用了大量的布尔值来决定一些事件或者行为的发生。我监听协同程序(Coroutines)和其他方法来得到返回值。
最近我在试图提高自己的C#编程技能,发现自己对事件缺乏基本的了解。所以我阅读了很多MSDN的教程和其他博客,但我发现大多数都写的都十分繁琐并且包含了很多与核心内容不相干的代码。我不希望这些事也在你身上发生。
正如所说的,我将试图解释事件的基础以及如何将它们应用到项目中。
单例?
或许你不知道单例。单例是一个不能被实例化或者“复制”的脚本,也就是说它是“唯一的”。
我建议在那些在游戏中不需要被复制很多次的东西上使用单例。例如目录系统。通常,角色只需要一个目录,我们不想去调用它的实例。当调用它时,我们希望确保它没有被多次复制。
有很多方式创造单例,下面是一种常用的方法,因为它比较简单…
public class Clicker : MonoBehaviour
{
// Singleton
private static Clicker instance;
// Construct
private Clicker() {}
// Instance
public static Clicker Instance
{
get
{
if (instance == null)
instance = GameObject.FindObjectOfType(typeof(Clicker)) as Clicker;
return instance;
}
// Do something here, make sure this is public so we can access it through our Instance.
public void DoSomething() { }
这里,我创建了一个名为‘Clicker’的类,并将它链接到摄像机。这个类用来控制三维场景中所有基于射线的点击。
通过在其他脚本中访问‘DoSomething’方法进行简单调用,我只需要简单的调用…
这样就排除了需要创建大量静态方法和变量的情况,好处是只给了我们一个实例。
委托和事件? 委托可以想成是一个针对对象和方法的引用指针。当其被调用时,它会通知所有引用委托的方法。
所以,第一件事首先…
定义一个委托和调用时的相应方法…
public class Clicker : MonoBehaviour
{
// Event Handler
public delegate void OnClickEvent(GameObject g);
public event OnClickEvent OnClick;
例子中创建了一个名为‘OnClickEvent’的委托,它包含了一个‘GameObject’类型的参数来获取对象信息。之后,我们定义一个名为‘OnClick‘的事件,当委托被调用时它将得到消息。…
现在,在同一个脚本里,我们需要调用委托来传递给GameObject。我通过使用射线完成了这一步。
public class Clicker : MonoBehaviour
{
// Event Handler
public delegate void OnClickEvent(GameObject g);
public event OnClickEvent OnClick;
// Handle our Ray and Hit
void Update ()
{
// Ray
Ray ray = Camera.mainCamera.ScreenPointToRay(Input.mousePosition);
// Raycast Hit
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 100))
{
// If we click it
if (Input.GetMouseButtonUp(0))
{
// Notify of the event!
OnClick(hit.transform.gameObject);
}
}
}
}
正如你看到的,如果摄像在场景中接触到了物体,点击鼠标左键,我们调用了事件并且传递了GameObject。
最后要做的是在其他脚本中引用委托来监听调用。所以我创建了一个名为’GoldPile‘的类。
public class GoldPile : MonoBehaviour
{
// Awake
void Awake ()
{
// Start the event listener
Clicker.Instance.OnClick += OnClick;
}
// The event that gets called
void OnClick(GameObject g)
{
// If g is THIS gameObject
if (g == gameObject)
{
Debug.Log("Hide and give us money!");
// Hide
gameObject.active = false;
}
}
}
在Awake()方法中,我们定义了正在监听的事件并且分配了一个名为‘OnClick’的本地方法。‘OnClick’不需要和委托方法(命名)一致,但实际上可以。
注意:之前,我们已经在Clicker类中加入了单例。这允许我们使用Clicker.Instance。
正如你看到的,我们已经创建了OnClick()方法并将点击到的对象用作了参数。
注意:你必须使用 if (g == gameObject),否则它也将隐藏场景中的其他实例物体。这既是为什么我们需要为引用传递GameObject参数。
现在你可以自由地添加这个方法到你游戏中的其他脚本。不要忘记在Awake()中定义方法和委托。