日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

C# 事件和Unity3D

 阿修羅之獅猿授 2016-03-29
     翻譯自:
http://www./blog/index.php/2010/10/04/c-events-and-unity3d/

zijan譯

(括號內(nèi)是譯者自己對文章和技術(shù)的理解)
(Unity3D是現(xiàn)在越來越流行的3D游戲引擎,它支持JavaScript,c#和Boo語言。如果你是個Unity3D的愛好者,但只會JavaScript。這里有一篇文章關(guān)于處理事件和消息傳遞,也許更適合你。A Useful Messaging System

你知道C#有一個內(nèi)置的事件機(jī)制嗎?這個東東在Unity3D里也非常好用。下面舉一個例子。

為了響應(yīng)一個GameObject的事件分發(fā),你通常要建立一個腳本繼承MonoBehaviour并且實現(xiàn)你需要的方法。比如你想對鼠標(biāo)懸停作出反應(yīng),就要創(chuàng)建OnMouseOver方法。通常代碼會像這個樣子:

C#代碼  收藏代碼
  1. void OnMouseOver () {  
  2.   renderer.material.color = Color.red;  
  3. }  



這樣工作沒問題。但如果你想通知另外一個對象響應(yīng)這個事件(OnMouseOver事件)怎么辦?

第一種方式是保持另外對象的腳本引用,然后在你的OnMouseOver方法中調(diào)用它:

C#代碼  收藏代碼
  1. public MyScript myScript;  
  2. void OnMouseOver () {  
  3.   myScript.NotifyMouseOver();  
  4. }  



這樣做沒問題,但是不夠好。因為你需要一直保持另外一個對象的引用,如果想通知多個對象要保持多個引用。代碼會變得很亂。

Messages 消息

另一個辦法是用SendMessage或SendMessageUpwards方法??瓷先ミ@是解決問題的最好辦法,但是這些方法存在嚴(yán)重的缺陷,以我的觀點,你應(yīng)該盡量不去使用它們。

這些方法的語法并不靈活,你需要傳遞一個方法名字的字符串,這樣做很容易出錯。另外這些方法只能用在同一個對象的附屬關(guān)系中。換句話說你只能在下面幾種情況中調(diào)用SendMessage或SendMessageUpwards方法,這些方法的腳本被關(guān)聯(lián)到同一個GameObject中,或者被關(guān)聯(lián)到這個GameObject的祖先關(guān)系對象中。

Events 事件

幸運的是有一個更好的解決辦法,這就是C#內(nèi)置的事件機(jī)制。我不在這里過多的描述機(jī)制是如何工作的,你如果有興趣可以學(xué)習(xí)相關(guān)的知識,訪問MSDN手冊。(譯者推薦另外一篇文章,C# 中的委托和事件

現(xiàn)在讓我們看看如何在Unity3D中使用事件機(jī)制。

C#代碼  收藏代碼
  1. using UnityEngine;  
  2. public class EventDispatcher : MonoBehaviour {  
  3.   public delegate void EventHandler(GameObject e);  
  4.   public event EventHandler MouseOver;  
  5.   void OnMouseOver () {  
  6.     if (MouseOver != null)  
  7.         MouseOver (this.gameObject);  
  8.   }  
  9. }  


如果你不知道這段代碼到底干什么,先不要著急。重要的是一旦你把這段代碼關(guān)聯(lián)到一個GameObject,只要在整個項目的任何一個腳本中保持這個對象,你就可以像下面這樣處理事件:

C#代碼  收藏代碼
  1. private GameObject s;  
  2. [...]  
  3. s.GetComponent<EventDispatcher>().MouseOver += Listener;  
  4. [...]  
  5. void Listener(GameObject g) {  
  6.    // g is being hovered, do something...  
  7. }  


這種方式比用消息更靈活,因為它可以被用在任何一個腳本中,而不僅僅在同一個對象附屬關(guān)系中。如果在整個應(yīng)用中保持一個單例模式的對象,你就可以監(jiān)聽任何從這個對象分發(fā)出來的事件。

另外一個重要特點,同一個監(jiān)聽方法可以響應(yīng)不同對象的事件。通過傳遞事件源對象的引用作為參數(shù),你總會知道哪個對象分發(fā)了事件,就像我的代碼展示的那樣。(對于這句話可以這樣理解,假如游戲中扔一顆導(dǎo)彈炸死了一個小兵并導(dǎo)致坦克減血,小兵死亡和坦克減血這兩個事件都觸發(fā)了同一個監(jiān)聽方法-玩家得分,通過傳遞進(jìn)來的事件源對象,就能知道小兵還是坦克觸發(fā)了玩家得分這個監(jiān)聽方法。)

References, controllers and MVC

現(xiàn)在讓我們比較一下第一和第三種方式。在最開始的例子中(第一種方式保持另外對象的腳本引用),你需要在事件分發(fā)代碼中保持監(jiān)聽者的對象引用,我說了這不是一個好主意。在用內(nèi)置事件機(jī)制,改進(jìn)的版本中(第三種方式),你需要在監(jiān)聽者代碼中保持事件分發(fā)者的引用。你也許會問,為什么后者更好?

首先,分發(fā)者不需要知道自己事件的監(jiān)聽者是誰,不需要知道有多少監(jiān)聽者。它只負(fù)責(zé)事件的發(fā)送。在最開始的例子中(第一種方式),如果要告訴分發(fā)者停止通知監(jiān)聽者,你能想象這種程序判斷有多么笨重嗎?

事件機(jī)制中,是由監(jiān)聽者自己決定監(jiān)聽什么事件,什么時候開始監(jiān)聽,什么時候停止監(jiān)聽。像這樣的對象通常用于管理程序的狀態(tài)或者執(zhí)行某些游戲邏輯。這個就叫做控制器,借用MVC設(shè)計模式的概念。這樣我們的代碼會更清晰,不易出錯。(譯者認(rèn)為觀察者設(shè)計模式更符合)

最后一點,我喜歡重載“+=”操作符去添加監(jiān)聽方法?,F(xiàn)在你也許能夠猜到,如果想結(jié)束監(jiān)聽某個事件,可以這么寫:

C#代碼  收藏代碼
  1. s.GetComponent<EventDispatcher>().MouseOver -= Listener;  


當(dāng)然你可以創(chuàng)建一個通用的EventDispatcher類,實現(xiàn)所有GameObject能夠分發(fā)的事件??梢詤⒖聪旅娴拇a。另外在實現(xiàn)OnGUI事件時要特別小心,如果想知道為什么,讀讀這篇文章。

C#代碼  收藏代碼
  1. using UnityEngine;  
  2. using System.Collections;  
  3.   
  4. /**  
  5.  *  A simple event dispatcher - allows to listen to events in one GameObject from another GameObject 
  6.  * 
  7.  *  Author: Bartek Drozdz (bartek [at] everyday3d [dot] com) 
  8.  * 
  9.  *  Usage: 
  10.  *  Add this script to the object that is supposed to dispatch events.  
  11.  *  In another objects follow this pattern to register as listener at intercept events: 
  12.   
  13.     void Start () { 
  14.         EventDispatcher ev = GameObject.Find("someObject").GetComponent<EventDispatcher>(); 
  15.         ev.MouseDown += ListeningFunction; // Register the listener (and experience the beauty of overloaded operators!) 
  16.     } 
  17.  
  18.     void ListeningFunction (GameObject e) { 
  19.         e.transform.Rotate(20, 0, 0); // 'e' is the game object that dispatched the event 
  20.         e.GetComponent<EventDispatcher>().MouseDown -= ListeningFunction; // Remove the listener 
  21.     } 
  22.      
  23.  *  This class does not implement all standards events, nor does it allow dispatching custom events,  
  24.  *  but you shold have no problem adding all the other methods. 
  25.  */  
  26. public class EventDispatcher : MonoBehaviour  
  27. {  
  28.   
  29.     public delegate void EventHandler (GameObject e);  
  30.     public delegate void CollisionHandler (GameObject e, Collision c);  
  31.   
  32.     public event EventHandler MouseOver;  
  33.     void OnMouseOver ()  
  34.     {  
  35.         if (MouseOver != null)  
  36.             MouseOver (this.gameObject);  
  37.     }  
  38.   
  39.     public event EventHandler MouseDown;  
  40.     void OnMouseDown ()  
  41.     {  
  42.         if (MouseDown != null)  
  43.             MouseDown (this.gameObject);  
  44.     }  
  45.   
  46.     public event EventHandler MouseEnter;  
  47.     void OnMouseEnter ()  
  48.     {  
  49.         if (MouseEnter != null)  
  50.             MouseEnter (this.gameObject);  
  51.     }  
  52.   
  53.   
  54.     public event EventHandler MouseExit;  
  55.     void OnMouseExit ()  
  56.     {  
  57.         if (MouseExit != null)  
  58.             MouseExit (this.gameObject);  
  59.     }  
  60.   
  61.     public event EventHandler BecameVisible;  
  62.     void OnBecameVisible ()  
  63.     {  
  64.         if (BecameVisible != null)  
  65.             BecameVisible (this.gameObject);  
  66.     }  
  67.   
  68.     public event EventHandler BecameInvisible;  
  69.     void OnBecameInvisible ()  
  70.     {  
  71.         if (BecameInvisible != null)  
  72.             BecameInvisible (this.gameObject);  
  73.     }  
  74.   
  75.     public event CollisionHandler CollisionEnter;  
  76.     void OnCollisionEnter (Collision c)  
  77.     {  
  78.         if (CollisionEnter != null)  
  79.             CollisionEnter (this.gameObject, c);  
  80.     }  
  81.   
  82.     public event CollisionHandler CollisionExit;  
  83.     void OnCollisionExit (Collision c)  
  84.     {  
  85.         if (CollisionExit != null)  
  86.             CollisionExit (this.gameObject, c);  
  87.     }  
  88.       
  89. }  

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多