朱峰社區(qū)首頁(yè) 朱峰社區(qū)

搜索資源 注冊(cè)|登陸

等待

返回 展開(kāi)菜單

Unity3D將來(lái)時(shí):IL2CPP(下)

UDK基礎(chǔ)教程 觀看預(yù)覽

UDK基礎(chǔ)教程

包含15節(jié)視頻教程
關(guān)注21.6萬(wàn)

讓你全面了解和掌握udk虛幻編輯器的教程。包含次世代制作技術(shù)。各種腳本的應(yīng)用。各種操控器的詳細(xì)講解。讓你也可以獨(dú)立制作有趣的游戲場(chǎng)景!

關(guān)閉

Unity3D將來(lái)時(shí):IL2CPP(下)


版本準(zhǔn)備

前文詳細(xì)的介紹了IL2CPP的來(lái)龍去脈,這里用一個(gè)實(shí)際的例子來(lái)看看Unity3D里的IL2CPP都為我們做了哪些工作以及在使用的過(guò)程中會(huì)遇到哪些問(wèn)題。

IL2CPP應(yīng)用的第一個(gè)平臺(tái)是WebGL,為了讓游戲可以一鍵部署到基于WebGL的瀏覽器中,Unity3D Script工作組的大牛們找到了一個(gè)絕妙的解決方案:不僅解決了C#,Unity Script語(yǔ)言兼容問(wèn)題,還解決了客戶端源碼泄漏問(wèn)題。這個(gè)功能在Unity5.0 Beta版中提供了測(cè)試。

IL2CPP的第二個(gè)試用平臺(tái)是iOS 64位版。大家都知道蘋(píng)果已經(jīng)發(fā)了最后通牒,全新App必須在15年2月1日支持64位CPU,而已經(jīng)上架的游戲也必須在15年6月1日更新的時(shí)候支持64位。這個(gè)64位編譯就是交由IL2CPP完成的。具體到版本是 Unity 4.6.1 p5,Unity4.6.2和Unity 4.6.2 p1。本文后面都使用4.6.2 p1版本來(lái)進(jìn)行演示。

創(chuàng)建項(xiàng)目,加入代碼
創(chuàng)建一個(gè)空的項(xiàng)目,加入兩個(gè)cs文件,一個(gè)叫IL2CPPCompatible.cs,另外一個(gè)是IL2CPPStudy.cs。前者主要用來(lái)測(cè)試代碼在IL2CPP中的兼容性,后者用來(lái)產(chǎn)生C++代碼,用來(lái)做對(duì)比分析。

以下是兩個(gè)文件的詳細(xì)內(nèi)容:

IL2CPPCompatible.cs
這個(gè)文件中有兩個(gè)兼容性測(cè)試函數(shù)。一個(gè)函數(shù)使用ThreadPool.QueueUserWorkItem啟動(dòng)一個(gè)新的線程。另一個(gè)則是SSL認(rèn)證函數(shù):ssl.AuthenticateAsClient (hosturl); 之所以寫(xiě)這兩個(gè)函數(shù)是因?yàn)樯鲜?.6.x IL2CPP對(duì)他們支持的還不是很好,會(huì)產(chǎn)生問(wèn)題,這個(gè)我們?cè)诤竺鏁?huì)詳細(xì)講到。

IL2CPPStudy.cs

using UnityEngine;
using System.Collections;
using System.IO;
using System.Threading;

public class CoconutClassStudy
{
        public int inta;
        public int intb;

        public int Add()
        {
                return inta + intb;
        }

        public CoconutClassStudy(int a, int b)
        {
                inta = a;
                intb = b;
        }

        public void IOTest(string filename)
        {
                if (File.Exists (filename)) {
                        FileStream fs = File.Open(filename, FileMode.Create);
                        fs.Close();

                }
        }

        public void ThreadTest()
        {
                Thread a =new Thread(delegate(object state) {
                        Debug.Log ("Thread Started");
                });
               
                a.Start ();
        }
}

public class IL2CPPStudy : MonoBehaviour {

        // Use this for initialization
        void Start () {
                Debug.Log (CoconutFuncStudy (10 , 20));
                CoconutClassStudy cc = new CoconutClassStudy (50, 60);
                Debug.Log (cc.Add ());
                cc.IOTest("test.txt");
                cc.ThreadTest ();
                Debug.Log (cc.GetType ());
        }
        
        // Update is called once per frame
        void Update () {
        
        }

        int CoconutFuncStudy(int a, int b)
        {
                return a + b;
        }
}

這個(gè)文件里面的內(nèi)容就更簡(jiǎn)單了:一個(gè)CoconutClassStudy類,里面有一個(gè)構(gòu)造函數(shù),一個(gè)Add函數(shù)和一個(gè)IOTest函數(shù)。另外在MonoBehaviour的Start()中,創(chuàng)建這個(gè)類的實(shí)例,并調(diào)用這兩個(gè)函數(shù)。這個(gè)源碼可以讓我們研究以下幾個(gè)方面:
1.cs的類在經(jīng)過(guò)IL2CPP以后如何在CPP文件中表達(dá)
2.C#的IO操作經(jīng)過(guò)IL2CPP以后如何在CPP文件中表達(dá)
3.當(dāng)調(diào)用new關(guān)鍵字在堆里產(chǎn)生一個(gè)實(shí)例的時(shí)候CPP文件又是如何做的
4.開(kāi)啟一個(gè)線程的操作IL2CPP會(huì)如何翻譯
5.調(diào)用cc.GetType()的行為IL2CPP如何處理

有了這連個(gè)文件后我們要做的第一件事情是生成XCode項(xiàng)目:
選擇IL2CPP編譯模塊,然后Build,生成XCode項(xiàng)目。
打開(kāi)項(xiàng)目,在項(xiàng)目結(jié)構(gòu)中打開(kāi)Classes目錄,可以看到多了一個(gè)Native的子目錄
IL2CPP轉(zhuǎn)換出的所有文件都在其中。
我們寫(xiě)的邏輯代碼,都在Assembly-CSharp.cpp中,除了這個(gè)文件,Native文件夾中還有很多以Bulk開(kāi)頭的文件,這些其實(shí)是IL2CPP把一些必要C#庫(kù)翻譯到CPP形成的文件。
像Bulk_Generics_x.cpp和System.Collections.Generic有關(guān)。
Bulk_UnityEngine.UI_x.cpp則和Unity自帶的UI有關(guān)。

讓我們粗略的分析下在CPP文件中前面的5條都是如何實(shí)現(xiàn)的:
1.cs的類在經(jīng)過(guò)IL2CPP以后如何在CPP文件中表達(dá)


我們的CoconutClassStudy類在CPP文件中變成了一個(gè)Struct,繼承于Object_t4。那這個(gè)Object_t4又是什么呢?

聰明的你一看注釋就知道了吧,沒(méi)錯(cuò),這個(gè)就是C#中的萬(wàn)物之源,System.Object。

既然我們C#的類變成了Struct,那類里面的函數(shù)都去哪里了呢?帶著這個(gè)疑問(wèn),我們來(lái)看第二條。

2.C#的IO操作經(jīng)過(guò)IL2CPP以后如何在CPP文件中表達(dá)
在CoconutClassStudy類中有一個(gè)成員函數(shù):IOTest。在CPP中,我們看到了如下的實(shí)現(xiàn):

類中的函數(shù)變成了一般的全局函數(shù),函數(shù)名字是類名加上函數(shù)名,最后加上一個(gè)后綴而成。而原本C#中的File.Exists和File.Open函數(shù)都有了相應(yīng)的C++實(shí)現(xiàn)。

3.當(dāng)調(diào)用new關(guān)鍵字在堆里產(chǎn)生一個(gè)實(shí)例的時(shí)候CPP文件又是如何做的?
C#代碼中我們?cè)赟tart函數(shù)中有一個(gè)顯示的New,找到相應(yīng)C++代碼:

可以看到代碼調(diào)用了一個(gè)叫il2cpp_codegen_object_new的函數(shù)。而這個(gè)函數(shù)最終調(diào)用了IL2CPP VM中的New函數(shù),分配了屬于GC管理的內(nèi)存。

接下來(lái)第四條
4.開(kāi)啟一個(gè)線程的操作IL2CPP會(huì)如何翻譯

C#中的System.Thread,在C++中是一個(gè)Thread_t26相當(dāng)巨大的結(jié)構(gòu),在New出了這個(gè)結(jié)構(gòu)之后,設(shè)置線程入口函數(shù),最后調(diào)用Thread_Start_m47啟動(dòng)線程。這個(gè)函數(shù)就是對(duì)應(yīng)System.Threading.Thread.Start()


        我們看最后一條
5.調(diào)用cc.GetType()的行為IL2CPP如何處理。找到C++中的對(duì)應(yīng)Start函數(shù):

首先我們看到了對(duì)應(yīng)C#中的Type的C++實(shí)現(xiàn):Type_t28,其次是GetType()這個(gè)函數(shù)在C++中的實(shí)現(xiàn),最后發(fā)現(xiàn)是調(diào)到了IL2CPP的VM函數(shù):


在這些C++的實(shí)現(xiàn)中,細(xì)心的讀者可能會(huì)發(fā)現(xiàn)他們時(shí)時(shí)刻刻都在使用MethodInfo和TypeInfo這樣的信息。這個(gè)就是Unity Script項(xiàng)目組提到的Metadata。Metadata指的是非邏輯代碼,而是函數(shù),結(jié)構(gòu),變量以及類本省的一些信息。比如名字,類型等。這個(gè)Metadata提供C++代碼和后臺(tái)的IL2CPP VM運(yùn)行時(shí)必要的信息。

以上5條只是很簡(jiǎn)單的例子,大家如果對(duì)IL2CPP的轉(zhuǎn)換感興趣,可以自己寫(xiě)出想要了解的測(cè)試代碼,然后再對(duì)比CPP文件看其實(shí)現(xiàn)。

前方有坑,請(qǐng)小心
新的事物總是伴隨著問(wèn)題,特別是在軟件行業(yè),Bug是不可避免的。就目前階段而言,IL2CPP還有不少問(wèn)題。這個(gè)就是項(xiàng)目中IL2CPPCompatible.cs存在的意義:做兼容性測(cè)試。大家在實(shí)際的項(xiàng)目中如果遇到了問(wèn)題,可以在這個(gè)文件中追加測(cè)試代碼。下面的表格把我們遇到的已知問(wèn)題做一個(gè)列舉,供參考。


鏈接可執(zhí)行文件zlib報(bào)錯(cuò)
ThreadPool.QueueUserWorkItem運(yùn)行報(bào)錯(cuò)
SSL.AuthenticateAsClient運(yùn)行報(bào)錯(cuò)

Unity 4.6.1 p5
發(fā)生
發(fā)生
發(fā)生

Unity 4.6.2 f1
發(fā)生
發(fā)生
發(fā)生

Unity 4.6.2 p1
修正
修正
發(fā)生







IL2CPP總結(jié)以及我們的建議
IL2CPP是Unity核心進(jìn)行的很重要的進(jìn)化之一。就現(xiàn)在來(lái)看,好處有以下幾點(diǎn):

1.運(yùn)行速度加快,游戲安裝尺寸減小,內(nèi)存占用降低

2.除了可以Mono調(diào)試C#之外,我們又多了一種選擇:Native C++ 源碼級(jí)調(diào)試(不知道你們什么感覺(jué),我對(duì)Unity C#調(diào)試頗有意見(jiàn),經(jīng)常連不上調(diào)試器,而且調(diào)試過(guò)程中常常宕機(jī)。換成用原生IDE調(diào)試C++代碼,就爽很多啦)。

3.可以快速的支持新的平臺(tái),當(dāng)然這點(diǎn)對(duì)我們關(guān)系不大。

帶來(lái)的問(wèn)題:
1.由于原來(lái)由Mono VM的IL代碼全部變成了CPP,導(dǎo)致項(xiàng)目中多了很多CPP代碼,編譯時(shí)間會(huì)顯著增加。

2.IL2CPP還有各種Bug,可能會(huì)導(dǎo)致原來(lái)的代碼不能很好的編譯運(yùn)行。需要等待Unity版本迭代。

3.鑒于C++靜態(tài)語(yǔ)言的特性,我們不能使用諸如System.Reflection.Emit這樣的動(dòng)態(tài)代碼。(C# ATO方式編譯)

給使用Unity開(kāi)發(fā)者的建議:
IL2CPP是大勢(shì)所趨,加上蘋(píng)果強(qiáng)制使用64位支持,意味著到了6月1號(hào),所有用Unity開(kāi)發(fā)的游戲都要用到新的編譯方式。如果你的項(xiàng)目比較大,應(yīng)該立刻開(kāi)始嘗試IL2CPP,以便發(fā)現(xiàn)問(wèn)題,并開(kāi)始解決。

clarisse搭建3D天空之城拉普達(dá)全過(guò)程 clarisse搭建3D天空之城拉普達(dá)全過(guò)程

朱峰社區(qū)網(wǎng)頁(yè)版
朱峰社區(qū)網(wǎng)頁(yè)版(手機(jī)掃描-分享-添加到屏幕)


朱峰社區(qū)公眾號(hào)
朱峰社區(qū)微信公眾號(hào)(微信掃一掃-關(guān)注)

資源說(shuō)明圖文教程無(wú)法下載,只能觀看圖片和文字。
版權(quán)規(guī)則本站圖文皆來(lái)自互聯(lián)網(wǎng)共享資源,如涉及到版權(quán)請(qǐng)查看版權(quán)規(guī)則。本平臺(tái)提供圖文僅可用于個(gè)人學(xué)習(xí),如用于商業(yè)請(qǐng)購(gòu)買(mǎi)正版。您必須遵守的版權(quán)規(guī)則

未知用戶

未知用戶

2005-2025 朱峰社區(qū) 版權(quán)所有 遼ICP備2021001865號(hào)-1
2005-2025 ZhuFeng Community All Rights Reserved

VIP

朱峰社區(qū)微信公眾號(hào)

回頂部

1.復(fù)制文本發(fā)給您的QQ好友或群、微信等;好友點(diǎn)擊鏈接以后,轉(zhuǎn)發(fā)就成功了。 2.如朋友點(diǎn)擊您的鏈接,您需要需刷新一下才行;同一個(gè)好友僅能點(diǎn)擊一次。
購(gòu)買(mǎi)VIP,觀看所有收費(fèi)教程�。�