Unity3D 學習筆記

不是什麼技術文章,純粹是我我的學習是遇到一些以爲須要注意的要點,當成筆記。php

 

1.關於調試,在Android下沒法斷點,Debug也沒法查看,已修正參考第37
查看日誌方法能夠啓動adb的log功能,或者本身寫個GUI控件直接在屏幕上顯示Info 參考30html

 

2.全部自定義的編輯器擴展插件腳本必須放在Editor文件夾裏,否則會致使編譯程序時出錯,
放到Editor文件下,編譯成遊戲時纔會忽略這些腳本node

 

3.打包資源時,假設是在移動設備上使用,打包方式務必選擇成:BuildTarget.Android
BuildPipeline.BuildAssetBundle(obj, null, targetPath, BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets | BuildAssetBundleOptions.DeterministicAssetBundle, BuildTarget.Android)
不然到安卓上會讀不出資源。PC則無此問題。android

 

4.從新打包資源後,加入在LoadAssetBunldes時沒給指定讀取新版本,例如原來爲:LoadFromCacheOrDownload(path, 1);
如今仍然爲LoadFromCacheOrDownload(path, 1);那麼是沒法讀取到新包的。由於系統會先從緩存檢查有沒有版本爲1的同名bundle,若是有,則直接使用緩存的,
若是沒有,則讀取這個新的包。所以,從新打包文件後,應該給文件包升1級,讀取的同時也多讀一級。這樣纔會讀出來。ios

 

5.若是在測試的時候爲了不頻繁打包頻繁換級形成麻煩,則能夠在每次加載時或者打包時選擇手動清空緩存:Caching.CleanCache();這樣就會強制讀取最新的包。
但千萬不要在正式版使用,由於這樣是清空所有數據,頻繁的讀取會形成性能消耗。PC就無所謂了。小程序

 

6.想要控制磁盤緩存不超標. 只要設置Caching.maximumAvailableDiskSpace 的值爲你預期的容量大小就能夠(byte爲單位)例如, 想要限定200M的緩存空間能夠這樣:Caching.maximumAvailableDiskSpace = 200*1024*1024;c#

 

7.畫線能夠用LineRenderer,或者直接GL畫,或者更方便的能夠Debug.DrawLine,甚至能夠將物理射線畫出Debug.DrawRay,可是Debug畫出的線只能在調試模緩存

式看獲得,編譯成遊戲後將再也不出現。參見:http://www.cnblogs.com/jeason1997/p/4805825.html服務器

 

8.判斷遊戲是否聯網網絡

Application.internetReachability == NetworkReachability.NotReachable
NotReachable  網絡不可達
ReachableViaCarrierDataNetwork  網絡經過運營商數據網絡是可達的。
ReachableViaLocalAreaNetwork   網絡經過WiFi或有線網絡是可達的。 

 

9.UGUI作在人物頭上血條的HUD的製做方法

public Transform follow;
Vector2 position = Camera.main.WorldToScreenPoint(follow.position);
img.rectTransform.position = position;//位置
img.rectTransform.localScale = new Vector2(2,2);//大小

 

10.動態改變相機的Culling Mask

http://answers.unity3d.com/questions/348974/edit-camera-culling-mask.html

 

11.安卓調式時,鏈接上手機,而後打開epclise就能夠看到locat輸出Debug內容了。

 

12.AssetBundle依賴關係

若是一個公共對象被多個對象依賴,咱們打包的時候,能夠有兩種選取。一種是比較省事的,就是將這個公共對象打包到每一個對象中。這樣會有不少弊端:內存被浪費了;加入公共對象改變了,每一個依賴對象都得從新打包。AssetBundle提供了依賴關係打包。

//啓用交叉引用,用於全部跟隨的資源包文件,直到咱們調用PopAssetDependencies
    BuildPipeline.PushAssetDependencies();

    var options =
        BuildAssetBundleOptions.CollectDependencies |
        BuildAssetBundleOptions.CompleteAssets;


    //全部後續資源將共享這一資源包中的內容,由你來確保共享的資源包是否在其餘資源載入以前載入
    BuildPipeline.BuildAssetBundle(
        AssetDatabase.LoadMainAssetAtPath("assets/artwork/lerpzuv.tif"),
        null, "Shared.unity3d", options);


        //這個文件將共享這些資源,可是後續的資源包將沒法繼續共享它
    BuildPipeline.PushAssetDependencies();
    BuildPipeline.BuildAssetBundle(
        AssetDatabase.LoadMainAssetAtPath("Assets/Artwork/Lerpz.fbx"),
        null, "Lerpz.unity3d", options);
    BuildPipeline.PopAssetDependencies();


    這個文件將共享這些資源,可是後續的資源包將沒法繼續共享它
    BuildPipeline.PushAssetDependencies();
    BuildPipeline.BuildAssetBundle(
        AssetDatabase.LoadMainAssetAtPath("Assets/Artwork/explosive guitex.prefab"),
        null, "explosive.unity3d", options);
    BuildPipeline.PopAssetDependencies();


    BuildPipeline.PopAssetDependencies();

 

13.非MonooBehavior腳本實現協程:

通常要實現多線程功能(即協程)時,通常都是在MonoBehavior腳本里StartCoroutine一個返回值爲IEnumerator的函數,

但有些時候,須要在非繼承自MonoBehaviro的腳本(例如單例等)裏也實現多線程效果,就沒法經過自身實現了,我採起這樣的方法:

public class CoroutineProvider : MonoBehaviour
{
    private static CoroutineProvider instance = null;

    public static CoroutineProvider GetInstance()
    {
        if (instance == null)
        {
            GameObject go = new GameObject();
            go.name = "CoroutineProvider";
            instance = go.AddComponent<CoroutineProvider>();
        }
        return instance;
    }
}

建立一個繼承自MonoBehavior的協程提供者,該提供者初始時並不存在,但有地方須要使用到協程時,就經過:

CoroutineProvider.GetInstance().StartCoroutine(Fuction());

這個時候就會在Scene裏實例化一個GameObject,以它做爲協程提供者的身份出現。

 

14.建立HTTP服務器並添加自定義格式文件下載支持:

爲了讓遊戲可以自動更新,需每次登錄遊戲時都向服務器下載版本文件驗證遊戲版本,若發現版本不一樣,

則下載文件更新列表,根據列表下載最新的資源,但默認狀況下HTTP只能下載一些默認資源,例如:rar,txt,xml等,

像「.assetbundle」這類的的自定義格式默認狀況下HTTP服務器是沒法下載的,若是提交請求,例如:http://127.0.0.1/Aseet/Resource.assetbundle,

則結果是404。爲了可以下載自定義格式文件,須要配置服務器,好比IIS的作法就是:

打開管理器->點擊根節點->在右邊找到IIS列表->找到MIME類型->打開並添加自定義格式擴展名

 

15.尋找遊戲中的某個對象

爲了下降耦合,儘可能避免對象腳本間經過「public value」拖動對象進行互相引用。

但有時候有必須某個對象引用另外一個對象,能夠經過在腳本中查找對象。

經常使用的查找方法有:GameObject.Find / FindWithTag 等一系列,這種方法尋找對象雖然最簡單,

可是效率卻比較低,儘可能避免在Update中使用,最好就是在Start和Awake中使用

還有一種高效的作法,就是將特定對象歸類,並集中放到一個List中,使用時查找就快速多了。

 

16.獲取擁有某種類型組件的子gameobject,後面的參數的意思是運行獲取不活躍的對象,即active = false

gameObject.GetComponentsInChildren<Component> (true);

 

17.只刪除gameobject 腳本組件會殘留

完全刪除方法以下:

GameObject go = new GameObject();

Component c = go.GetComponent<Component >();

MonoBehaviour.DestroyImmediate(c);
MonoBehaviour.DestroyImmediate(go);

 

18.單例模式慎用,若是一個GameObject對象爲單例對象,請當心在其餘的GameObject的OnDestory裏引用該單例

由於在程序關閉前會執行全部GameObject的OnDestory,可是執行的前後順序不定。

若是GameObject_1在OnDestory時引用GameObject_2(單例對象),假設GO2的OnDestory先運行,這時候它的

Instance爲null,被GO1引用時它會再建立一次。

而若是在OnDestory裏建立任何對象,該對象都將不會被UnityEngine釋放,一直保留下來

 

19.Unity3D 優化技術(3D圖形方面)

① http://blog.csdn.net/candycat1992/article/details/42127811

② http://blog.csdn.net/leonwei/article/details/18042603

③ 儘可能不要動態的instantiate和destroy object,使用object pool代替,前者的開銷很大。

具體參見:利用緩存池解決Instantiate慢的問題用

 

20.Unity中的.meta文件

每一個資源文件(外部導入和內部建立的)對應一個.meta文件。這個.meta文件中的guid就惟一標識這個資源。

內部建立的資源會使用外部導入的資源,好比 內部資源材質Material使用貼圖Textures(預製體、場景中使用了更多的資源)。

材質怎麼知道本身使用了那些資源呢? 就在本身的文件中記錄着其它資源的GUID。

並且每一個meta裏的標識都是隨機產生的,並且同一文件屢次生成的meta文件裏的標識一不一樣。

在多人合做項目中,若是你上傳資源時沒有同步上傳.meta文件,那麼別人的機器就會爲這個文件生成一個,但標識可能和你不一樣,

致使的結果就是Prefab引用的各類組件丟失。

 

21.Editor運行時從Scene視圖觀察對象

在Hierarchy選擇要觀察的GameObject,鼠標聯繫點擊4下,

這樣的話,Scene視圖就會將焦點集中在該GameObject身上,

就跟綁定一個攝影機同樣,調式的時候很是方便。

 

22.Profiler分析器

分析器平時只檢測關鍵代碼,若是要檢測全部代碼,
就必須深度檢測,但深度檢測又很是消耗性能。因此有時候只想檢測某一小段代碼的時候,
能夠設置檢測段:
Profiler.BeginSample ("標籤");
// 要檢測性能的代碼
Profiler.EndSample ();
而後就能夠在分析器中找到相應的標籤了:

 

23.Unity 5.3 C# 部分源碼

https://bitbucket.org/xuanyusong/unity-decompiled/src/779abf10e556?at=master

備份地址

 

24.調節腳本執行順序

Unity的不一樣腳本間的執行順序通常是沒有規矩的,不一樣腳本的同一函數,例如Start,啓動的順序也不一樣。

所以不多在U3D的腳本里的同一函數作前後順序依賴。例如在腳本A的Start裏調用腳本B的某個屬性,而該

屬性又在腳本B的Start函數裏初始化,因爲不知道二者的Start的前後順序,所以通常改成,在腳本B的Awake裏

初始化該屬性,而不是Start。

但要強制改變腳本的執行順序也能夠:

在這裏調節腳本執行順序,數值越小,越先執行

 edit->projectseeting->script execution order 

 

25.經過命令行在控制檯編譯U3D項目

官方Manual教程

示例:

(Unity.exe Path) -batchmode -projectPath (Project Path) -executeMethod MyEditorScript.MyBuildMethod -quit -logFile (Log Path)

UnityPath : Windows: C:\program files\Unity\Editor\Unity.exe

UnityPath : Mac OS: /Applications/Unity/Unity.app/Contents/MacOS/Unity

 

26.C# 以及 Uniyt3D 添加全局預編譯指令

#define DEBUG

#if DEBUG

  dosome;

#endif

吶,這就是預編譯指令拉,要注意,這不叫宏,跟C/C++的宏仍是有必定差距的。

至於如何定義,在代碼裏定義的話,當疼的C#只能在每一個文件的文件頭定義才生效,也就是說,你在test1.cs裏定義#define DEBUG的話,

那麼你也必須在test2.cs裏的頭部定義一個才能在test2裏生效。若是有一百個文件要使用這個預編譯調節,那麼你就要手動定義100次。

還好微軟留了下後路,其實全局預編譯指令能夠在項目裏的*.CSharp.csproj裏設置,

右鍵項目,在屬性裏設置便可,或者乾脆直接用文本文件打開項目路徑下的該文件,直接編輯。

Unity也給咱們留了解決方案,不過藏得比較深:

Editor->ProjectSetting->Player->Other->如圖紅圈處

須要注意的是,Unity裏設置的全局預編譯,是按平臺分開的,

也就是說,你在安卓平臺下設置的指令,在PC平臺是無法使用的,除非複製過去。

這裏有個插件能夠方便地設置預編譯指令:

源代碼:

下載後把中文部分去掉,扔到「Editor」文件夾下,而後打開使用即是

 

27.Unity3D自定義Debug

Unity的Debug功能比較有限,有時候要自定義一些特殊的Debug,好比封裝一個Logger,在Editor平臺時打印日誌

到控制檯,而在其餘平臺,則打印信息到屏幕或輸出到Log文件。功能倒挺容易實現,問題就是,這個封裝的Logger底層

部分也是經過Debug實現,在調試的時候要實現Unity控制檯那種雙擊日誌就跳到日誌輸出的地方的功能,就比較麻煩了。

由於就是Logger封裝了Debug,雙擊的時候也不會跳到Logger.Log的地方,而是跳到內部用Debug實現的地方,致使調式

不方便。

解決方法就是,將Logger編譯成dll,而後再在Unity內部引用,這時候Debug輸出控制檯的時候,雙擊日誌就會直接跳到Logger.Log。

雨鬆也是這麼作的:http://www.xuanyusong.com/archives/2782 

 

28.Unity3D裏的特殊文件夾以及腳本編譯順序

第一階段: Standard Assets, Pro Standard Assets 和Plugins文件夾以內的腳本,編譯好後爲:Assembly-CSharp-firstpass.dll(C#)

第二階段: 在第一階段那些文件夾裏任何名字爲'Editor'的文件夾裏的腳本,例如'Plugins/Editor'

第三階段: 全部其餘不在'Editor'文件夾裏的腳本,編譯好後爲:Assembly-CSharp.dll(C#)

第四階段: 其餘剩餘腳本,例如'Editor'文件夾裏的腳本(注,不是第二階段那些在特殊文件夾裏的Editor),編譯好後爲:Assembly-CSharp-Editor.dll(C#)

在U3D裏,注意腳本的編譯順序有時候極其重要,例如:

要在C#腳本里引用UnityScprite腳本時,或者反過來,那麼被引用的那些腳本,就必須在前一階段先編譯,否則會出現‘找不到腳本’的編譯錯誤。

參考官方連接

 

29.Unity AssetBundle打包資源的一個坑:

就是Shader不會被打包進去,若是在對象身上掛有Shader,那麼加載AB後,會出現Shader丟失的狀況。

解決方法就是對經過AB動態加載的對象在Awake時作個斷定,看看自身的Shader列表是否爲空,若是爲空,

則手動從本地加載。

 

30.經過Application.RegisterLogCallback來捕獲Debug輸出:

該方法能夠監聽到unity中全部的log消息,而後你能夠選擇保存到文件中或者顯示到gui上作調試來用。

經過LogType來判斷處理哪些類型的消息須要被保存或顯示。

LogType以下:

Error

LogType used for Errors.

Assert

LogType used for Asserts. (These indicate an error inside Unity itself.)

Warning

LogType used for Warnings.

Log

LogType used for regular log messages.

Exception

LogType used for Exceptions.

 

using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
    public string output = "";
    public string stack = "";
    void OnEnable() {
        Application.RegisterLogCallback(HandleLog);
    }
    void OnDisable() {
        Application.RegisterLogCallback(null);
    }
    void HandleLog(string logString, string stackTrace, LogType type) {
        output = logString;
        stack = stackTrace;
    }
}

 

31.物理射線檢測之BoxCast

在Physics下的RayCast已經很熟悉了,今天發現有一個BoxCast,起初覺得它的意思就是檢測給定立方體內的物體,

若是物體在該Box內,則返回true:

如圖,但實際使用起來老是檢測失敗,仔細看下BoxCast的參數:

第一二個參數很好理解,立方體的中心,立方體的大小,第三個參數就讓我有點疑惑了,居然都已經決定好Box的大小了,爲什麼還有方向這個概念,

直接檢測是否在Box裏不就好,知道去Google了下網上的用法才知道:

原來這個BoxCast的意思是,在給定的center處,創建一個給定大小的Box,而後往給定的方向一直往前拖/射

出這個Box,一直拉長,而後檢測這條路上的全部障礙物,大概效果如圖(中間的空隙是我加上便於理解的,實際中檢測是無縫的)

2D版

 

using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    public Vector2 pos;
    public Vector2 Size;
    public float angle;
    public Vector2 dir;
    public float dis;

    void Update()
    {
        var hit = Physics2D.BoxCast(pos, Size, angle, dir, dis);
        if (hit.collider != null)
        {
            Debug.Log(hit.point);
        }
    }

    private void OnDrawGizmos()
    {
        Gizmos.color = new Color(1, 0, 0, 0.3f);

        Quaternion rot = new Quaternion();
        rot.eulerAngles = new Vector3(0, 0, angle);
        // 變換矩陣
        Matrix4x4 trs = Matrix4x4.TRS(pos, rot, Vector2.one);
        Gizmos.matrix = trs;
        // 在該Transform的Vector3.zero處繪製一個位置、角度、縮放均與該Transform同樣的方塊,大小爲size
        Gizmos.DrawCube(Vector3.zero, Size);
        // 復位Gizmos設置
        Gizmos.matrix = Matrix4x4.identity;
    }
}

 

32.U3D中的Time

通常Time中有兩個比較重要的參數:

Time.realTime: 表示現實中的時間

Time.time: 表示遊戲中的時間(受TimeScale影響)

而咱們遊戲中的Time.fixedTime,Time.deltaTime都是與遊戲時間對應,而不是與現實時間對應。

好比咱們的fixedTime設置爲0.2,那就代表遊戲中每0.2「秒」會調用一次FixedUpdate,而這個0.2秒並非現實中的0.2秒,

也就是說,FixedUpdate不能保證現實時間中每0.2秒調用一次,他的實際調用還會受到TimeScale等的影響。

若是咱們在一個FixedUpdate裏作太多的內容,那麼,現實中每個FixedUpdate的時長就會拉長,可是在遊戲中,兩個FixedUpdate

的間隔仍然是0.2秒(能夠理解爲TimeScale變化了,但實際上不是),形成的結果就是,咱們看到的遊戲比較卡,幀數降低。

結論:

FixedUpdate與Update都不能保證在現實中多久調用一次,只能保證在遊戲時間中FixedUpdate固定調用,而Update會受渲染影響

一樣的遊戲,當FixedUpdate裏處理的內容不多時

FixedUpdate處理的內容較多,能夠明星地看到卡了

可是這兩個例子,Time.fixedTime都是0.2s

同理, deltaTime表示的是遊戲中每兩個Update中的間隔時間,即完成最後一幀的時間,

因此若是你要讓一個物體勻速移動,你應該在Update裏與Time.deltaTime相乘。當你乘以Time.deltaTime實際表示:每秒移動物體10米,而不是每幀10米。若是是每幀10米,遊戲卡頓會形成物體移動變成非勻速。

 

33.物理中的Collider性能對比

首先,這是一個有700多顆樹的場景,每棵樹都掛有一個Rigibody組件

沒有任何Collider時:

Box: 可見大概漲了1ms

Shpere: 漲幅巨大,大概是Box的6-7倍

Capsule:雖然也漲幅比較大,但沒Sphere嚴重

因而可知,性能上Box >> Capsule > Shpere,

分別耗時:1ms 7.4ms 5ms,

網上有篇試驗教程,是09年的,結果跟我徹底反過來,不知道是否是這幾年來U3D物理進行了大優化

http://forum.unity3d.com/threads/capsule-vs-box-colliders.34254/#post-222443

 

另外,以上是基於動態Collider(所謂動態Collider,即該Collider掛載在一個非靜止的物體的上,即有Rigibody且不爲IsKinematic)

若是是在IsKinematic條件下,則性能消耗會進一步降低,好比以上狀況,Box的狀況爲:

若是把Rigibody去掉,那麼狀況也差很少,主要消耗性能的部分是動態Collider

 

34. Unity裏的Transform在SetPos或者SetRot時會形成很大的性能開銷的緣由:

這種狀況通常是由於該Transform的GameObject上掛有太多的Collider,Collider分爲靜態與動態部分,

靜態的碰撞體,物理系統會批優化處理,他們基本不佔多少資源。但若是這個Collider是動態運行的,好比一直在

改變位置或者旋轉,那麼物理系統會不斷從新計算他,若是你的GameObject上掛有太多的Collider,那麼在

改變Transform時就會形成額外的巨大開銷。

解決方法就是儘可能減小運動的Collider,若是一個物體身上的Collider太多,能夠嘗試使用MeshCollider的方式來優化,

在運動的狀況下,一個MeshCollider的開銷比許多個小BoxCollider要小得多。

 

35.物理各類射線檢測性能對比

參考:Unity中各種物理投射性能橫向比較

 

36.精簡縮小程序集

若想縮減移動端的遊戲包大小,能夠經過在打包選項裏作手腳:

Api Compatibility Level 設置爲 .NET 2.0 Subset的話,就會只將.NET的子集導出,僅有部分經常使用功能

Stripping Level的話也差很少,設置不一樣級別能精簡導出不一樣的程序集,越精簡的話,導出的函數越少,這樣雖然包小了,

但若用到的部分功能被剔除的話,說不定程序會crash,所以若要用這功能,先去Unity官方的列表裏查哪些函數是包含在哪一個級別裏的:

https://docs.unity3d.com/410/Documentation/ScriptReference/MonoCompatibility.html

好比SetAccessControl這條函數,就只有在.NET 2.0原版的程序集中能用,其餘的都不行。

縮減的效果很明顯(上爲.NET 2.0 Subset,下位.NET 2.0):

 

 

37.經過WIFI調試安卓上的Unity項目

1.首先在手機上開啓USB調試功能,並安裝驅動(這一步不少手機助手均可以完成)。
2.用USB電纜鏈接手機和電腦。
3.確保手機和電腦在一個局域網內,簡單的說就是電腦和手機共用一個路由器,網段同樣。
4.打開電腦上CMD窗口,輸入如下命令:
adb tcpip 5555(該命令打開手機adb網絡調試功能)
正常狀況下輸入命令後控制檯會出現回顯
restarting in TCP mode port: 5555
打開手機查看手機的IP地址(不會請百度)假設手機的地址是192.168.1.x輸入命令
adb connect 192.168.1.x
若是一切正常控制檯會回顯如下內容
connected to 192.168.1.x:5555
若是你想查看是否鏈接成功請輸入如下內容
adb devices
控制檯會回顯鏈接的設備

5.若是一切鏈接成功,請拔掉USB電纜,選擇File->Build&Run,在編譯以前要勾選上Development Build 和Script Debugging這兩項(在build setting裏面勾選不要忘記不然是不能調試的)電腦會自動編譯文件並將APK推送至手機,在手機上贊成並安裝。

6.當程序運行後再Monodevelop裏面打開Run->Attach to process 會發現你手機的選項,選擇手機,在腳本里面添加斷點,你發現能夠調試了,那叫一個爽!出現問題不再用去瞎猜,或者添加Debuglog了。

7.同時UnityEditor的Profiler也能夠用了(要記得在上面輸入IP)

8.若想打印安卓的log,則能夠在CMD裏輸入adb logcat -s Unity -d > xxx.txt,「xxx.txt」爲具體路徑,其中Unity是過濾用的tag,unity中的全部輸出都是「Unity」

:除了第5步要用USB才能裝好,其餘的都在WIFI環境下測試成功,並且貌似遠程調試不能用USB,只能用WIFI?

 

38.安卓遊戲拆包

有時候在玩一些外國廠商作的比較大型的手遊的時候,常常會發現一個狀況,就是安裝包下來很小,通常也就20來M,而後還要下載一個很大的obb文件放到/SDcard/Android/obb/packName裏,

那是由於一些平臺限制上傳的apk容量,因此開發者無奈只能將遊戲的資源分包出來,而後再在遊戲運行時下載下來。用壓縮文件打開obb,會發現它其實也就是一個壓縮文件,像U3D的遊戲,裏面存放

的通常是/assets/data/裏的一些資源,其實咱們手動將obb裏的資源解壓後放入apk裏,而後從新回編譯apk,會發現也能夠直接玩。

U3D拆包的作法:

勾上最後一項「Split Application Binary」就會將數據包和apk分離,而後在打開apk以後,進入選擇下載或直接下載界面,將你的.obb文件從服務器或者其餘地方下載下來

先把apk安裝到Android設備,而後將對應obb文件更名爲:main.<Bundle Version Code>.<包名>.obb

並拷貝到Android設備的「/android/obb/<包名>/ 」路徑下。

如在Unity3D編輯中,你能夠在工程設置的如圖位置處,看到「Bundle Version Code」和包名(即「Bundle Identifier」).

假設「Bundle Version Code」值爲2,包名爲「com.Demo.ABC」:

- 首先,在Android設備上安裝ABC.apk;- 接着,將ABC.obb更名爲「main.2.com.Demo.ABC.obb」;

- 而後,將文件「main.2.com.Demo.ABC.obb」拷貝到Android設備的「/android/obb/com. Demo.ABC/」路徑下;

- 啓動App,你會發現新安裝的APP已經能夠正常使用了。

如何安裝分包app安裝包(apk+obb)
 
 

39.Smcs.rsp文件

能夠在Unity Assets目錄下建立smcs.rsp文件,並向其中添加預編譯命令,其會在unity啓動時執行,好比新建一個smcs.rsp文件,向其中添加內容:

-define:MYDEF

而後就能夠在腳本中加入宏判斷:

#if MYDEF
....
#endif

其原理是啓動Unity時會執行unity目錄下的smcs.exe文件並添加預編譯命令,也能夠經過cmd運行smcs.exe逐個添加預編譯命令。
另外還有能夠建立gmcs.rsp文件,對應Editor腳本中的預編譯命令。

好比若是想要在C#語言中使用指針,必須標記爲unsafe的,默認狀況下unity中使用unsafe標記會報錯,能夠在項目中添加smcs.rsp文件並加入-unsafe預編譯命令,就能夠編譯經過。

注:Unity5.6貌似將smcs.rsp改爲smc.rsp

 

40.Unity代碼的編譯運行流程

早期:

  安卓:c# -> IL -> mono jit -> 機器碼

  蘋果:c# -> mono aot -> 機器碼

如今

  安卓:c# -> IL -> mono jit -> 機器碼

     c# -> IL2CPP -> 機器碼

  蘋果:c# -> IL2CPP -> 機器碼

將來?

  安卓:c# -> IL -> LLVM jit -> 機器碼

  蘋果:c# -> IL -> LLVM aot -> 機器碼

mono jit:在運行時,CLR動態將IL代碼解釋成機器碼,而後運行

mono aot:在編譯時,將IL代碼解釋成機器碼,運行時直接執行機器碼

il2cpp:在編譯時,將IL代碼轉成C++代碼,再將C++代碼編譯成機器碼

llvm(一種中間件,mono跟.net core都有對應的實現):http://www.mono-project.com/docs/advanced/runtime/docs/llvm-backend/

之因此早期蘋果用aot而如今換成il2cpp,是由於Unity的mono2.6只支持32位aot,而蘋果已經限制32位應用了

將來頗有可能用微軟的.net core方案,而後用llvm實現對ios平臺的支持

 

41.Unity編輯器監聽腳本重載事件

[InitializeOnLoad]
public class UnityScriptCompiling:AssetPostprocessor
{
    [UnityEditor.Callbacks.DidReloadScripts]
    static void AllScriptsReloaded()
    {
    }
}

 除此以外,編輯器還能監聽其餘時間,例如監聽資源文件被打開:

 

42.Unity的RuntimeInitializeOnLoadMethod屬性

Unity 5.0開始增長了RuntimeInitializeOnLoadMethodAttribute,這樣就很方便在遊戲初始化以前作一些額外的初始化工做,好比:Bulgy參數設置、SDK初始等工做。

用此屬性修飾某個靜態方法,則這個方法就會被Unity註冊到系統中,遊戲啓動的時候,會自動檢測並運行該方法,就算打包了遊戲,依然會生效

注意:該方法是Unity註冊的,也就是說,一個已經編譯好的遊戲,就算你反編譯dll,並加入本身的靜態方法並用上該屬性,也不會生效

(註冊方式,估計是經過名字,寫在資源文件裏了,看能不能找到是註冊在哪一個文件裏頭的)

using UnityEngine;

public class Test
{
    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
    static void OnBeforeSceneLoadRuntimeMethod ()
    {
        Debug.Log("Before scene loaded");
    }

    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
    static void OnAfterSceneLoadRuntimeMethod()
    {
        Debug.Log("After scene loaded");
    }

    [RuntimeInitializeOnLoadMethod]
    static void OnRuntimeMethodLoad()
    {
        Debug.Log("RuntimeMethodLoad: After scene loaded");
    }
}

 

43.Unity中提供的Attribute有不少,若是本身寫程序擴展編輯器的功能,就須要瞭解這些屬性。經常使用的有:

一、AddComponentMenu 導航欄菜單

二、ContextMenu 右鍵菜單

三、HeaderAttribute

四、HideInInspector 可讓public變量在Inspector上隱藏,沒法在Editor中進行編輯

五、MultilineAttribute 支持輸入多行文本

六、RangeAttribute 限定輸入值的範圍

七、RequireComponent 組件依賴,使用該組件後自動添加依賴組件

八、RuntimeInitializeOnLoadMethodAttribute

九、SerializeField 強制對變量進行序列化,即便變量是private

十、SpaceAttribute 增長空位

十一、TooltipAttribute 提示信息,當鼠標移到Inspector上時顯示相應的提示

十二、InitializeOnLoadAttribute 在啓動Unity編輯器並打開項目的時候運行編輯器腳本

1三、InitializeOnLoadMethodAttribute

1四、MenuItem 導航欄的菜單項

 

44.Unity層級結構Hierarchy優化

Hierarchy Structure Guidelines

  • If something moves every frame, make sure all its children care about position. Only rendering, physics, audio, or core systems like that should be there.
  • When dynamically creating game objects at runtime, if they do not need to be children of the spawner for the above reasons, spawn things at the root of the scene.
  • You can easily register everything you spawn and pass along the ActiveInHeirarchy state of the spawner using OnEnable and OnDisable.
  • Try to group your moving transforms such that you have around 50 or so GameObjects per root. This lets the underlying system group your TransformChangeDispatch jobs into a fairly optimal amount of work per thread. Not so few that the thread overhead dominates; not so many that you are waiting on thread execution.
相關文章
相關標籤/搜索