找回密码
 立即注册

Unity3D C#事件管理

已有 514 次阅读2012-11-29 15:05

多年的Flash开发,我非常欣赏Flash的事件系统。Uinty对象通信所使用的方法SendMessage在多数情况下是工作正常,但如果在一个具有无数引用其他对象的GameObject的大型项目进行反射,那问题就来了。

我用C#在Uinty中所写的第一个东西,就是管理抽象类的事件管理系统。究其核心,EventManager使用也是SendMessage,并 对游戏对象[gameObject]有直接引用,但若有事件发生,其便会对需求进行分解,不同的类间会有信息共享,这样事件对象就知道如何互相通信。

若有任何建议或修正,欢迎留言。

EventManager.cs

/*
Event Manager
Static manager for handling an event driven communication model in Unity.
This is similar to Adobe Flash's event listener model used in ActionScript.

Copyright © 2012 Dustin Andrew
dustin.andrew@gmail.com

http://www.dustinandrew.me/

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

http://www.gnu.org/licenses/

*/

/*
*  Setup:
*  Create an empty GameObject and add the EventManager script to it.
*  Create custom event classes that extend the CustomEvent.
*
*  Restrictions & Tips:
*  DO NOT add event listeners in the Awake() method!
*  This is used by the EventManager to initialize.
*  Change this class' Execution Order to before default time if you need to work around this.
*  Use the Start() method to setup your events.
*  Make event listener callback functions public.
*  Extend the CustomEvent class when creating your events.
*  Use custom variables in your custom events over the arguments hashtable to maintain class abstraction
*  Clean up and remove event listeners when objects are destroyed.
*  Events are not received if the listener gameObject.active is false.
*
*  Examples:
*
*  // setup event listeners
*  void Start() {
*      EventManager.instance.addEventListener(CustomEventObj.EVENT_TO_LISTEN_TO, gameObject, "OnSomethingHappened");
*  }
*
*  // remove event listeners
*  void OnDestroy() {
*      if (gameObject) {
*          // remove a single event
*          EventManager.instance.removeEventListener(CustomEventObj.EVENT_TO_LISTEN_TO, gameObject);
*          // remove all events
*          EventManager.instance.removeAllEventListeners(gameObject);
*      }
*  }
*
*  // get values passed by events
*  public void OnSomethingHappened(CustomEventObj evt) {
*      Debug.Log((datatype)evt.arguments["value"]);
*      // or if using custom vars instead of arguments hashtable
*      Debug.Log(evt.rockOn);
*  }
*
*  // dispatch events
*  void TriggerEvent() {
*      CustomEventObj evt = new CustomEventObj(CustomEventObj.EVENT_TO_TRIGGER);
*      evt.arguments.Add("value", 3);
*      EventManager.instance.dispatchEvent(evt);
*  }
*
*  // create custom events
*  using UnityEngine;
*  using System.Collections;
*
*  public class CustomEventObj : CustomEvent {
*
*      // event types
*      public static string MY_EVENT_1 = "my_event_1";
*      public static string MY_EVENT_2 = "my_event_2";
*
*      // optionally add custom variables instead of using the arguments hashtable
*      public int myCustomEventVar1 = 0;
*      public bool rockOn = true;
*
*      public CustomEventObj(string eventType = "") {
*         type = eventType;
*      }
*  }
*
*/

using UnityEngine;
using System.Collections;

// internal event listener model
internal class EventListener {
public string name;
public GameObject listener;
public string function;
}

// Custom event class, extend when creating custom events
public class CustomEvent {

private string _type;
private Hashtable _arguments = new Hashtable();

// constructor
public CustomEvent(string eventType = "") {
_type = eventType;
}

// the type of event
public string type {
get { return _type; }
set { _type = value; }
}

// the arguments to pass with the event
public Hashtable arguments {
get { return _arguments; }
set { _arguments = value; }
}
}

public class EventManager : MonoBehaviour {

// singleton instance
public static EventManager instance;

// settings
public bool allowSingleton = true; // EventManager class will transfer between scene changes.
public bool allowWarningOutputs = true;
public bool allowDebugOutputs = true;

private static bool _created = false;
private Hashtable _listeners = new Hashtable();

// setup singleton if allowed
public void Awake() {
if (!_created && allowSingleton) {
DontDestroyOnLoad(this);
instance = this;
_created = true;
Setup();
} else {
if (allowSingleton) {
if (EventManager.instance.allowWarningOutputs) {
Debug.LogWarning("Only a single instance of " + this.name + " should exists!");
}
Destroy(gameObject);
} else {
instance = this;
Setup();
}
}
}

// clear events on quit
public void OnApplicationQuit() {
_listeners.Clear();
}

// PUBLIC *******************************

// Add event listener
public bool addEventListener(string eventType, GameObject listener, string function) {
if (listener == null || eventType == null) {
if (allowWarningOutputs) {
Debug.LogWarning("Event Manager: AddListener failed due to no listener or event name specified.");
}
return false;
}
recordEvent(eventType);
return recordListener(eventType, listener, function);
}

// Remove event listener
public bool removeEventListener(string eventType, GameObject listener) {
if (!checkForEvent(eventType)) return false;

ArrayList listenerList = _listeners[eventType] as ArrayList;
foreach (EventListener callback in listenerList) {
if (callback.name == listener.GetInstanceID().ToString()) {
listenerList.Remove(callback);
return true;
}
}
return false;
}

// Remove all event listeners
public void removeAllEventListeners(GameObject listener) {
foreach (EventListener callback in _listeners) {
if (callback.listener.GetInstanceID().ToString() == listener.GetInstanceID().ToString()) {
_listeners.Remove(callback);
}
}
}

// Dispatch an event
public bool dispatchEvent(CustomEvent evt) {
string eventType = evt.type;
if (!checkForEvent(eventType)) {
if (allowWarningOutputs) {
Debug.LogWarning("Event Manager: Event \"" + eventType + "\" triggered has no listeners!");
}
return false;
}

ArrayList listenerList = _listeners[eventType] as ArrayList;
if (allowDebugOutputs) {
Debug.Log("Event Manager: Event " + eventType + " dispatched to " + listenerList.Count + ((listenerList.Count == 1) ? " listener." : " listeners."));
}
foreach (EventListener callback in listenerList) {
if (callback.listener && callback.listener.active) {
callback.listener.SendMessage(callback.function, evt, SendMessageOptions.DontRequireReceiver);
}
}
return false;
}

// PRIVATE *******************************

private void Setup() {
// TO DO: Self create GameObject if not already created
}

// see if event already exists
private bool checkForEvent(string eventType) {
if (_listeners.ContainsKey(eventType)) return true;
return false;
}

// record event, if it doesn't already exists
private bool recordEvent(string eventType) {
if (!checkForEvent(eventType)) {
_listeners.Add(eventType, new ArrayList());
}
return true;
}

// delete event, if not already removed
private bool deleteEvent(string eventType) {
if (!checkForEvent(eventType)) return false;
_listeners.Remove(eventType);
return true;
}

// check if listener exists
private bool checkForListener(string eventType, GameObject listener) {
if (!checkForEvent(eventType)) {
recordEvent(eventType);
}

ArrayList listenerList = _listeners[eventType] as ArrayList;
foreach (EventListener callback in listenerList) {
if (callback.name == listener.GetInstanceID().ToString()) return true;
}
return false;
}

// record listener, if not already recorded
private bool recordListener(string eventType, GameObject listener, string function) {
if (!checkForListener(eventType, listener)) {
ArrayList listenerList = _listeners[eventType] as ArrayList;
EventListener callback = new EventListener();
callback.name = listener.GetInstanceID().ToString();
callback.listener = listener;
callback.function = function;
listenerList.Add(callback);
return true;
} else {
if (allowWarningOutputs) {
Debug.LogWarning("Event Manager: Listener: " + listener.name + " is already in list for event: " + eventType);
}
return false;
}
}
}

原文作者:十旋转45度


路过

雷人

握手

鲜花

鸡蛋

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 立即注册

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-5-2 12:18 , Processed in 0.049798 second(s), 15 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

返回顶部