1. 程式人生 > >[Unity3D] GameObject and MonoBehaviour

[Unity3D] GameObject and MonoBehaviour

size 時間 程序 rip line 插件 成像 font 註意

遊戲對象 (GameObject)是所有其他組件 (Component) 的容器。遊戲中的所有對象本質上都是遊戲對象 (GameObject)。

Ref: http://blog.csdn.net/linuxheik/article/details/37956243

創建遊戲對象 (GameObject)

遊戲對象 (GameObject) 自身不會向遊戲添加任何特性。而是容納實現實際功能的組件 (Component) 的容器。

例如,光 (Light) 是一個附加到遊戲對象 (GameObject) 的組件 (Component)。

附加遊戲對象 (GameObject)組件 (Component)

# 註意先後順序

如果要從腳本創建組件 (Component),則應

  1. 創建空遊戲對象 (GameObject),
  2. 然後使用 gameObject.AddComponent(ClassName) 函數添加所需組件 (Component)。  

在腳本中,組件 (Component) 可以方便地通過消息發送或 GetComponent(TypeName) 函數相互通信。這使您可以編寫可重復使用的小腳本,這些腳本可以附加到多個遊戲對象 (GameObject) 並重復用於不同用途

除了作為組件 (Component) 的容器之外,遊戲對象 (GameObject) 還具有標記 (Tag)、層 (Layer) 和名稱 (Name)。

  • 標記 (Tag) 用於通過標記 (Tag) 名稱來快速查找對象。
  • 層 (Layer) 可用於僅對某些特定的對象組投射光線、渲染或應用光照。
  • 名稱 (Name)

標記 (Tag) 和層 (Layer) 可以使用標記管理器 (Tag Manager)(在編輯 (Edit) ->項目設置 (Project Settings) -> 標記 (Tags) 中)進行設置。

實例 ( GameObject and GetComponent )

-- Object --

套路:獲得object,頂層結構,然後再按照它本來的面貌GetComponent出來。  
//
獲取按鈕遊戲對象 GameObject btnObj = GameObject.Find ("Canvas/Button");
//獲取按鈕腳本組件 Button btn = (Button) btnObj.GetComponent<Button>();

-- MonoBehaviour --

using UnityEngine;
using UnityEngine.UI;
技術分享圖片  
public class Button_event_test : MonoBehaviour {

    public void Button_Click()
    {
        ...
    }
}

MonoBehaviour 與 GameObject 的關系

Ref: Unity 腳本基類 MonoBehaviour 與 GameObject 的關系

一、MonoBehaviour 生命周期

1.1. 內置函數列表

技術分享圖片
Awake:當一個腳本被實例化時,Awake 被調用。我們大多在這個類中完成成員變量的初始化。

Start:僅在 Update 函數第一次被調用前調用。因為它是在 Awake 之後被調用的,我們可以把一些需要依賴 Awake 的變量放在Start裏面初始化。 同時我們還大多在這個類中執行 StartCoroutine 進行一些協程的觸發。要註意在用C#寫腳本時,必須使用 StartCoroutine 開始一個協程,但是如果使用的是 JavaScript,則不需要這麽做。

Update:當開始播放遊戲幀時(此時,GameObject 已實例化完畢),其 Update 在 每一幀 被調用。

LateUpdate:LateUpdate 是在所有 Update 函數調用後被調用。

FixedUpdate:當 MonoBehaviour 啟用時,其 FixedUpdate 在每一固定幀被調用。

OnEnable:當對象變為可用或激活狀態時此函數被調用。

OnDisable:當對象變為不可用或非激活狀態時此函數被調用。

OnDestroy:當 MonoBehaviour 將被銷毀時,這個函數被調用。
View Code

詳見圖:生命周期示意圖

接下來,做出一下講解:

最先執行的方法是Awake,這是生命周期的開始,用於進行激活時的初始化代碼。

  一般可以在這個地方將當前腳本禁用:this.enable=false,如果這樣做了,則會直接跳轉到OnDisable方法執行一次,然後其它的任何方法,都將不再被執行。

如果當前腳本處於可用狀態,則正常的執行順序是繼續向下執行OnEnable

  當然我們可以在另外一個腳本中實現這個腳本組件的啟動:this.enable=true;

再向下執行,會進行一個判斷,如果Start方法還沒有被執行,則會被執行一次,如果已經被執行了,則不會再被執行。

  這是個什麽意思呢?我們可以在某個腳本中將組件禁用this.enable=false,再啟用時會轉到OnEnable處執行,這時繼續向下走,發現Start執行過了,將不再被執行。

  比如說:第一次啟用時,將怪物的初始位置定在了(0,0,0)點,然後怪物可能會發生了位置的變換,後來被禁用了,再次啟用時,不會讓怪物又回到初始的(0,0,0)位置。

繼續向後執行,就是Update了,然後是FixUpdate,再然後是LateUpdate,如果後面寫了Reset,則會又回到Update,在這4個事件間可以進行循環流動

再向後執行,就進入了渲染模塊(Rendering),非常重要的一個方法就是OnGUI,用於繪制圖形界面。【當然,如果你使用了NGUI,這個生命周期的事情你就不用考慮了】

首先我們說說GUI與NGUI的區別,

GUI是Unity自帶的繪制界面工具,它的成像原理是基於表層的,所以執行效率非常的低,並且沒有提供復雜的UI的接口,就算開發者硬著頭皮寫上去只能讓UI的執行效率更低。

NGUI 完全依賴於3D就好比在遊戲世界中的攝像機直直的照射在一個平面中,在平面之上再去繪制自己的UI,所以它的執行效率會非常高。

NGUI是一款收費的插件,在Asset Store中大家可以看到價格。在未購買正版的前提下我們可以通過兩種方法來使用NGUI,

  • 第一種:使用官方提供的免費版本,但是這個版本中有NGUI的水印,無法正式發布不過完全可以作為學習使用。
  • 第二種:使用別人購買過的正版插件,在互聯網中有朋友放出NGUI的插件。

再向後,就是卸載模塊(TearDown),這裏主要有兩個方法OnDisableOnDestroy。當被禁用(enable=false)時,會執行OnDisable方法,但是這個時候,腳本並不會被銷毀,在這個狀態下,可以重新回到OnEnable狀態(enable=true)。

當手動銷毀或附屬的遊戲對象被銷毀時,OnDestroy才會被執行,當前腳本的生命周期結束。

特別要強調的是:這裏雖然可以使用C#來寫代碼,但是這個類構造對象的生命周期,與MonoBehaviour的生命周期,是完全不同的。

二、MonoBehaviour 的那些坑

  • 私有(private)和保護(protected)變量只能在專家模式中顯示。屬性不被序列化或顯示在檢視面板。
  • 不要使用命名空間(namespace)
  • 記得使用 緩存組件查找, 即在MonoBehaviour的長遠方法中經常被訪問的組件最好在把它當作一個私有成員變量存儲起來
  • 在遊戲裏經常出現需要檢測敵人和我方距離的問題,這時如果要尋找所有的敵人,顯然要消耗的運算量太大了,
    • 所以最好的辦法是將攻擊範圍使用Collider表示,然後將Collider的isTrigger設置為True。
    • 最後使用OnTriggerEnter來做攻擊範圍內的距離檢測,這樣會極大提升程序性能。

三、Monobehaviour 常用方法

技術分享圖片
Update

當 MonoBehaviour 實例化完成之後,Update 在每一幀被調用。

LateUpdate

LateUpdate 是在所有 Update 函數調用後被調用。這可用於調整腳本執行順序。例如:當物體在Update裏移動時,跟隨物體的相機可以在LateUpdate裏實現。

FixedUpdate

處理 Rigidbody 時,需要用FixedUpdate代替Update。例如:給剛體加一個作用力時,你必須應用作用力在FixedUpdate裏的固定幀,而不是Update中的幀。(兩者幀長不同)

Awake

Awake 用於在遊戲開始之前初始化變量或遊戲狀態。在腳本整個生命周期內它僅被調用一次。Awake 在所有對象被初始化之後調用,所以你可以安全的與其他對象對話或用諸如 GameObject.FindWithTag 這樣的函數搜索它們。每個遊戲物體上的Awke以隨機的順序被調用。因此,你應該用Awake來設置腳本間的引用,並用Start來傳遞信息Awake總是在Start之前被調用。它不能用來執行協同程序。

C#和Boo用戶註意:Awake 不同於構造函數,物體被構造時並沒有定義組件的序列化狀態。Awake像構造函數一樣只被調用一次。

Start

Start在behaviour的生命周期中只被調用一次。它和 Awake 的不同是,Start 只在腳本實例被啟用時調用。你可以按需調整延遲初始化代碼。Awake 總是在Start之前執行。

OnMouseEnter /OnMouseOver / OnMouseExit / OnMouseDown / OnMouseUp / OnMouseDrag

當鼠標進入 / 懸浮 / 移出 / 點擊 / 釋放 / 拖拽GUIElement(GUI元素)或Collider(碰撞體)中時調用OnMouseEnter。

OnTriggerEnter / OnTriggerExit / OnTriggerStay

當Collider(碰撞體)進入 / 退出 / 停留在 trigger(觸發器)時調用OnTriggerEnter。OnTriggerStay 將會在每一幀被調用。

OnCollisionEnter / OnCollisionExit / OnCollisionStay

當此collider/rigidbody觸發另一個rigidbody/collider時,被調用。OnCollisionStay 將會在每一幀被調用。
可重寫函數 技術分享圖片
Invoke

function Invoke (methodName : string, time : float) : void 
在 time 秒之後,調用 methodName 方法;

InvokeRepeating

function InvokeRepeating (methodName : string, time : float, repeatRate : float) : void 
從第一次調用開始,每隔repeatRate時間調用一次.

CancelInvoke

function CancelInvoke () : void 
取消這個MonoBehaviour上的所有調用Invoke。

IsInvoking

function IsInvoking (methodName : string) : bool 
某指定函數是否在等候調用。

StartCoroutine

function StartCoroutine (routine : IEnumerator) : Coroutine 
一個協同程序在執行過程中,可以在任意位置使用 yield 語句。yield 的返回值控制何時恢復協同程序向下執行。協同程序在對象自有幀執行過程中堪稱優秀。協同程序在性能上沒有更多的開銷。StartCoroutine函數是立刻返回的,但是yield可以延遲結果。直到協同程序執行完畢。

StopCoroutine / StopAllCoroutines
不可重寫函數

四、腳本與GameObject的關系

* 實例化

被顯式添加到 Hierarchy 中的 GameObject 會被最先實例化,GameObject 被實例化的順序是從下往上。

GameObject 被實例化的同時,加載其組件 component 並實例化,

如果掛載了腳本組件,則實例化腳本組件時,將調用腳本的 Awake 方法,組件的實例化順序是也是從下往上。

在所有顯式的 GameObject 及其組件被實例化完成之前,遊戲不會開始播放幀

* 實例化後

當 GameObject 實例化工作完成之後,將開始播放遊戲幀。每個腳本的第一幀都是調用 Start 方法,其後每一幀調用 Update,而且每個腳本在每一幀中的調用順序是從下往上。

* 總結

被掛載到 GameObject 下面的腳本會被實例化成 GameObject 的一個成員

* 腳本與GameObject的關系

詳見鏈接內容

NB: Unity 編輯器裏面的拖拽綁定方式是 GameObject 級別的。


  

[Unity3D] GameObject and MonoBehaviour