Unity-SendMessage


每一個對象都有SendMessage,BroadcastMessage,SendMessageUpwards 三個發送消息的方法!

1、功能:
執行某個對象中的某個方法!
 
2、實現原理
反射
 
3、參數
參數                       類型                                                  說明
methodName           string                                     The name of the method to call.    // 方法名稱
value                      object                                     An optional parameter value to pass to the called method.    //方法參數
options            SendMessageOptions                      Should an error be raised if the method doesn't exist on the target object?  //如果方法不存在 
                                                                          是否生成錯誤信息  dontRequireReceiver不生成錯誤信息,RequireReceiver 生成錯誤信息
4、三者區別
項目層次:Camera,Panel,Btn,label,sprite 這五個對象都附加上了腳本,腳本代碼分別如下:
Camera:
void Say(string name) {
        Debug.Log("camera " + name);
    }
Panel:
void Say(string name) {
        Debug.Log("panel " + name);
    }
label:
 void Say(string name) {
        Debug.Log("label " + name);
    }
sprite:
void Say(string name) {
        Debug.Log("sprite " + name);
    }
Btn:
    void Say(string name) {
        Debug.Log("btn " + name);
    }
1、如果btn按鈕的OnClick事件代碼用的是SendMessage:
void OnClick() {
        this.gameObject.SendMessage("Say", "zwh", SendMessageOptions.DontRequireReceiver);
    }
那么執行結果為:
2、如果btn按鈕的OnClick事件代碼用的是SendMessageUpwards:
void OnClick() {
        this.gameObject.SendMessageUpwards("Say", "zwh", SendMessageOptions.DontRequireReceiver);
    }
那么執行結果為:
3、如果btn按鈕的OnClick事件代碼用的是BroadcastMessage:
void OnClick() {
        this.gameObject.BroadcastMessage("Say", "zwh", SendMessageOptions.DontRequireReceiver);
    }
那么執行結果為:

4、總結

SendMessage 查找的方法是在自身當中去查找

SendMessageUpwards 查找的方法是在自身和父類中去查找,如果父類還有父類,繼續查找,直到找到根節點為止

BroadcastMessage 查找的方法是在自身和子類中去查找,如果子類還有子類,繼續查找,直到沒有任何子類

5、多個對象執行同一個方法

NGUITools類里面有一個重載的靜態方法:Broadcast (代碼如下),這個靜態方法的作用就是遍歷所有的對象,找到要執行的方法,然后執行對象的SendMessage方法!但是這個方法的效率不高,FindObjectsOfType這個方法肯定耗時間,因為我們項目中的對象肯定很多,這無疑是浪費時間,for循環更是耗時間,再說有可能遍歷到沒有此方法的對象,做無用功!我們最好的辦法就是只執行那些我們需要的某些對象去執行某一方法,而不是遍歷所有對象,卻不管他有沒有此方法,所以我們得尋求好的解決方法,請轉到 6

 1     static public void Broadcast (string funcName)
 2     {
 3         GameObject[] gos = GameObject.FindObjectsOfType(typeof(GameObject)) as GameObject[];
 4         for (int i = 0, imax = gos.Length; i < imax; ++i) gos[i].SendMessage(funcName, SendMessageOptions.DontRequireReceiver);
 5     }
 6 
 7     /// <summary>
 8     /// Call the specified function on all objects in the scene.
 9     /// </summary>
10 
11     static public void Broadcast (string funcName, object param)
12     {
13         GameObject[] gos = GameObject.FindObjectsOfType(typeof(GameObject)) as GameObject[];
14         for (int i = 0, imax = gos.Length; i < imax; ++i) gos[i].SendMessage(funcName, param, SendMessageOptions.DontRequireReceiver);
15     }
6、多個對象執行同一個方法優化
這個代碼主要意思就是把所有需要執行的對象加到一個集合中,然后遍歷此集合執行他們的方法,我想大家都能看懂,我就不詳細解釋了
 1 public class NotificationCenter : MonoBehaviour {
 2 
 3     static Hashtable notifications = new Hashtable();
 4 
 5     /// <summary>
 6     /// 增加對象
 7     /// </summary>
 8     /// <param name="gameobject">對象</param>
 9     /// <param name="methodname">方法名</param>
10     /// <param name="param">參數</param>
11     public static void AddGameObject(GameObject gameobject, String methodname, object param) {
12         if (string.IsNullOrEmpty(methodname)) {
13             Debug.Log("方法名為空");
14             return;
15         }
16         if (!notifications.ContainsKey(methodname)) {
17             Notification notification = new Notification(gameobject, param);
18             List<Notification> list = new List<Notification>();
19             list.Add(notification);
20             notifications[methodname] = list;
21         } else {
22             List<Notification> notifyList = (List<Notification>)notifications[methodname];
23             if (notifyList.Find(a => a.gameobject == gameobject) == null) {
24                 Notification notification = new Notification(gameobject, param);
25                 notifyList.Add(notification);
26                 notifications[methodname] = notifyList;
27             }
28         }
29     }
30     /// <summary>
31     /// 移除對象
32     /// </summary>
33     /// <param name="gameobject">對象</param>
34     /// <param name="methodname">方法名</param>
35     public static void RemoveGameObject(GameObject gameobject, String methodname) {
36         if (string.IsNullOrEmpty(methodname)) {
37             Debug.Log("方法名為空");
38             return;
39         }
40         List<Notification> notifyList = (List<Notification>)notifications[methodname];
41         if (notifyList != null) {
42             if (notifyList.Find(a => a.gameobject == gameobject) != null) {
43                 notifyList.RemoveAll(a => a.gameobject == gameobject);
44                 notifications[methodname] = notifyList;
45             }
46             if (notifyList.Count == 0) {
47                 notifications.Remove(methodname);
48             }
49         }
50     }
51     /// <summary>
52     /// 執行方法
53     /// </summary>
54     /// <param name="methodName">要執行的方法名稱</param>
55     public static void ExecuteMethod(string methodName) {
56         if (string.IsNullOrEmpty(methodName)) {
57             Debug.Log("方法名為空");
58             return;
59         }
60         List<Notification> notifyList = (List<Notification>)notifications[methodName];
61         if (notifyList == null) {
62             Debug.Log("對象不存在");
63             return;
64         }
65         foreach (Notification notification in notifyList) {
66             notification.gameobject.SendMessage(methodName, notification.param, SendMessageOptions.DontRequireReceiver);
67         }
68     }
69     public class Notification {
70         public GameObject gameobject;
71         public object param;
72         public Notification(GameObject gameobject, object param) {
73             this.gameobject = gameobject;
74             this.param = param;
75         }
76     }
77 }
7、多個對象同時執行他們的方法
6有幾個缺點:使用sendmessage,而sendmessage是利用反射原理實現的,我們知道使用反射在某些情況下效率是不高的,我們最好盡量避免使用反射,而且6傳的參數只能為一個,是因為sendmessage的緣故,他只允許傳一個參數,可擴展性不好!這里我們使用委托來解決這些問題,代碼如下,代碼也很簡單,我也就不說了,如有問題,可以留言。
 1 public class delegateNotificationCenter : MonoBehaviour {
 2 
 3     static Hashtable notifications = new Hashtable();
 4 
 5     public delegate void MyFunc(object[] obj);
 6     /// <summary>
 7     /// 增加對象
 8     /// </summary>
 9     /// <param name="gameobject"></param>
10     /// <param name="methodname"></param>
11     /// <param name="param"></param>
12     public static void AddGameObject(GameObject gameobject, String flag, MyFunc func, object[] param) {
13         if (string.IsNullOrEmpty(flag)) {
14             Debug.Log("不存在");
15             return;
16         }
17         if (!notifications.ContainsKey(flag)) {
18             Notification notification = new Notification(gameobject, func, param);
19             List<Notification> list = new List<Notification>();
20             list.Add(notification);
21             notifications[flag] = list;
22         } else {
23             List<Notification> notifyList = (List<Notification>)notifications[flag];
24             if (notifyList.Find(a => a.gameobject == gameobject) == null) {
25                 Notification notification = new Notification(gameobject, func, param);
26                 notifyList.Add(notification);
27                 notifications[flag] = notifyList;
28             }
29         }
30     }
31     /// <summary>
32     /// 移除對象
33     /// </summary>
34     /// <param name="gameobject"></param>
35     /// <param name="flag"></param>
36     public static void RemoveGameObject(GameObject gameobject, String flag) {
37         if (string.IsNullOrEmpty(flag)) {
38             Debug.Log("不存在");
39             return;
40         }
41         List<Notification> notifyList = (List<Notification>)notifications[flag];
42         if (notifyList != null) {
43             if (notifyList.Find(a => a.gameobject == gameobject) != null) {
44                 notifyList.RemoveAll(a => a.gameobject == gameobject);
45                 notifications[flag] = notifyList;
46             }
47             if (notifyList.Count == 0) {
48                 notifications.Remove(flag);
49             }
50         }
51     }
52     /// <summary>
53     /// 執行方法
54     /// </summary>
55     /// <param name="flag"></param>
56     public static void ExecuteMethod(string flag) {
57         if (string.IsNullOrEmpty(flag)) {
58             Debug.Log("不存在");
59             return;
60         }
61         List<Notification> notifyList = (List<Notification>)notifications[flag];
62         if (notifyList == null) {
63             Debug.Log("對象不存在");
64             return;
65         }
66         foreach (Notification notification in notifyList) {
67             notification.func(notification.param);
68         }
69     }
70     public class Notification {
71         public GameObject gameobject;
72         public MyFunc func;
73         public object[] param;
74         public Notification(GameObject gameobject, MyFunc func, object[] param) {
75             this.gameobject = gameobject;
76             this.func = func;
77             this.param = param;
78         }
79     }
80 }

以上是個人的總結,如有不當,希望大家多多批評指正!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM