Unity3D中指令碼的執行順序和編譯順序,unity3d指令碼

來源:互聯網
上載者:User

Unity3D中指令碼的執行順序和編譯順序,unity3d指令碼

Unity3D中指令碼的執行順序和編譯順序


【狗刨學習網】

       在Unity中可以同時建立很多指令碼,並且可以分別綁定到不同的遊戲對象上,它們各自都在自己的生命週期中運行。與指令碼有關的也就是編譯和執行啦,本文就來研究一下Unity中指令碼的編譯和執行順序的問題。


事件函數的執行順序

先說一下執行順序吧。 官方給出的指令碼中事件函數的執行順序如:






我們可以做一個小實驗來測試一下: 
在Hierarchy視圖中建立三個遊戲對象,在Project視圖中建立三條指令碼,如所示,然後按照順序將指令碼綁定到對應的遊戲對象上:





三條指令碼的代碼完全一樣,只是做了一點名稱上的區分:

using UnityEngine;
using System.Collections;
public class Scring0 : MonoBehaviour
{
    void Awake()
    {
        Debug.Log("Script0 ======= Awake");
    }

    bool isUpdate = false;
    void Update()
    {
        if(!isUpdate)
        {
            Debug.Log("Script0 ======= Update");
            isUpdate = true;
        }
    }

    bool isLateUpdate = false;
    void LateUpdate()
    {
        if(!isLateUpdate)
        {
            Debug.Log("Script0 ======= LateUpdate");
            isLateUpdate = true;
        }
    }
}

播放遊戲,看看它們的執行順序。如所示,Awake、Update、LateUpdate,無論運行遊戲多少次,它們的執行順序是完全一樣的。






接著我們再做一個測試,把Script0的Update方法注釋掉!! 

using UnityEngine;
using System.Collections;
public class Script0 : MonoBehaviour 
{
  
    void Awake () 
    {
        Debug.Log("Script0 ========= Awake");
    }
  
//  bool isUpdate = false;
//  void Update () 
//  {
//      if(!isUpdate)
//      {
//          Debug.Log("Script0 ========= Update");
//          isUpdate = true;
//      }
//  }
  
    bool isLateUpdate = false;
    void LateUpdate()
    {
        if(!isLateUpdate)
        {
            Debug.Log("Script0 ========= LateUpdate");
            isLateUpdate = true;
        }
    }
}




再次運行遊戲,看看它的結果。指令碼的執行順序和以前完全一樣,Script0即便刪除掉了Update方法,但是它也不會直接執行LateUpdate方法,而是等待Script1和Script2中的Update方法都執行完畢以後,再去執行所有的LateUpdate方法。



 




通過這兩個例子,我們就可以很清楚地斷定,Unity後台是如何執行指令碼的了。每個指令碼的Awake、Start、Update、LateUpdate、FixedUpdate等等,所有的方法在後台都會被匯總到一起: 


背景Awake()
{
    // 這裡暫時按照中的指令碼執行順序,後面會談到其實可以自訂該順序的
    指令碼2中的Awake();
    指令碼1中的Awake();
    指令碼0中的Awake();
}


背景方法Awake、Update、LateUpdate等等,都是按照順序,等所有遊戲對象上指令碼中的Awake執行完畢之後,再去執行Start、Update、LateUpdate等方法的。 


背景Update()
{
    // 這裡暫時按照中的指令碼執行順序,後面會談到其實可以自訂該順序的
    指令碼2中的Update();
    指令碼1中的Update();
    指令碼0中的Update();
}



指令碼的執行順序然後我們來看看這樣一種情況:在指令碼0的Awake方法中建立一個立方體對象,然後在指令碼2的Awake方法中去擷取這個立方體對象。代碼如下: 

// Script0.cs
using UnityEngine;
using System.Collections;
public class Script0 : MonoBehaviour 
{
    void Awake ()
    {
        GameObject.CreatePrimitive(PrimitiveType.Cube);
    }
}

// Script2.cs
using UnityEngine;
using System.Collections;
public class Script2 : MonoBehaviour 
{
    void Awake () 
    {
        GameObject go = GameObject.Find("Cube");
        Debug.Log(go.name);
    }
}




如果指令碼的執行順序是先執行Script0,然後再執行Script2,那麼Script2中的Awake就可以正確地擷取到該立方體對象;可是如果指令碼的執行順序是先執行Script2,然後是Script0,那麼Script2肯定會報null 指標錯誤的。


那麼實際項目中的指令碼會非常多,它們的先後執行順序我們誰也不知道(有人說是按照棧結構來執行的,即後綁定到遊戲對象上的指令碼先執行。這一點可以從上面的例子中得到,但官方並沒有這麼說,還得進一步深入研究)。但一般的,建議在Awake方法中建立遊戲對象或


Resources.Load(Prefab)對象,然後在Start方法中去擷取遊戲對象或者組件,因為事件函數的執行順序是固定的,這樣就可以確保萬無一失了。 
另外,Unity也提供了一個方法來設定指令碼的執行順序,在Edit -> Project Settings -> Script Execution Order功能表項目中,可以在Inspector面板中看到如所示:




點擊右下角的"+"將彈出下拉視窗,包括遊戲中的所有指令碼。指令碼添加完畢後,可以用滑鼠拖動指令碼來為指令碼排序,指令碼名後面的數字也越小,指令碼越靠上,也就越先執行。其中的Default Time表示沒有設定指令碼的執行順序的那些指令碼的執行順序。





按照上面這張圖的設定,我們再來看一下控制台的輸出結果,來確認一下我們的設定是否起作用(注意:把Script0指令碼中的Update方法取消注釋):





指令碼的編譯順序

關於指令碼的編譯順序很是頭疼,官方的說法有點模糊,請看官方的解釋:




由於指令碼的編譯順序會涉及到特殊檔案夾,比如上面提到的Plugins、Editor還有Standard Assets等標準的資源檔夾,所以指令碼的置放位置就非常重要了。下面用一個例子來說明不同檔案夾中的指令碼的編譯順序:





實際上,如果你細心的話會發現,如果在你的項目中建立如所示的資料夾階層時,編譯項目之後會在專案檔夾中產生一些檔案名稱中包含Editor、firstpass這些字樣的專案檔。比如按照的檔案夾結構,我們開啟專案檔夾來看一下產生的專案檔是什麼樣的?





下面就來詳細探討一下這些個字樣是什麼意思?它們與指令碼的編譯順序有著怎樣的聯絡?


1、首先從指令碼語言類型來看,Unity3d支援3種指令碼語言,都會被編譯成CLI的DLL

如果項目中包含有C#指令碼,那麼Unity3d會產生以Assembly-CSharp為首碼的工程,名字中包含”vs”的是產生給Vistual Studio使用的,不包含”vs”的是產生給MonoDevelop使用的。 


項目中的指令碼語言 工程首碼 工程尾碼
C# Assembly-CSharp csproj
UnityScript Assembly-UnityScript unityproj
Boo Assembly-Boo booproj

如果項目中這三種指令碼都存在,那麼Unity將會產生3種首碼類型的工程。


2、對於每一種指令碼語言,根據指令碼放置的位置(其實也部分根據指令碼的作用,比如編輯器擴充指令碼,就必須放在Editor檔案夾下),Unity會產生4中尾碼的工程。其中的firstpass表示先編譯,Editor表示放在Editor檔案夾下的指令碼。

在上面的樣本中,我們得到了兩套項目工程檔案:分別被Virtual Studio和MonoDevelop使用(尾碼包不包含vs),為簡單起見,我們只分析vs項目。得到的檔案清單如下:


Assembly-CSharp-filepass-vs.csproj 
Assembly-CSharp-Editor-filepass-vs.csproj 
Assembly-CSharp-vs.csproj 
Assembly-CSharp-Editor-vs.csproj


根據官方的解釋,它們的編譯順序如下:


(1)所有在Standard Assets、Pro Standard Assets或者Plugins檔案夾中的指令碼會產生一個Assembly-CSharp-filepass-vs.csproj檔案,並且先編譯;


(2)所有在Standard Assets/Editor、Pro Standard Assets/Editor或者Plugins/Editor檔案夾中的指令碼產生Assembly-CSharp-Editor-filepass-vs.csproj工程檔案,接著編譯;


(3)所有在Assets/Editor外面的,並且不在(1),(2)中的指令檔(一般這些指令碼就是我們自己寫的非編輯器擴充指令碼)會產生Assembly-CSharp-vs.csproj工程檔案,被編譯;


(4)所有在Assets/Editor中的指令碼產生一個Assembly-CSharp-Editor-vs.csproj工程檔案,被編譯。


之所以按照這樣建立工程並按此順序編譯,也是因為DLL間存在的依賴關係所決定的。

好了,到此為止,我們可以很容易地判斷出上面舉的執行個體中,指令碼的編譯順序(實際上,我已經把順序寫在了指令碼的檔案名稱中了)


更多精彩內容:www.gopedu.com

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.