用ECMAScript4 ( ActionScript3) 實現Unity的熱更新 -- Demo分析

如何建立工程

  1. 下載最新的Unity發佈插件包
  2. 打開Unity,新建一個項目
  3. 將插件包導入

     

  4. 在菜單中點擊ASRuntime/Create ActionScript3 FlashDevelop HotFixProject

     

  5. 此時系統會自動建立工程,而且自動將經常使用的Unity函數生成可供範圍的API代碼。
  6. 熱更工程的目錄結構是這樣的

     

  7. 其中,bat/CreateUnityAPI.bat,能夠手動再次生成API。好比修改了須要導出的配置等,此時能夠執行這個bat從新生成
  8. bat/CompileCode.bat 能夠編譯字節碼併發布到Unity工程。若是沒有安裝IDE,則用記事本和這個批處理,一樣能夠進行熱更新開發
  9. 點擊FlashDevelop的編譯按鈕,便可編譯熱更新字節碼

     

  10. 默認配置中,將熱更新字節碼生成到Unity工程的    StreamingAssets\hotfix.cswc 中。實際狀況能夠按須要修改。

Demo詳解

這個Demo場景提供了一些元素,能夠概覽熱更項目的執行流程。git

 Unity工程部分

  • AS3Player   一個GameObject。它掛載了ActionScriptStartUp.cs 腳本。這個腳本承載了初始化腳本引擎的全部功能。
  • Canvas       下的元素,是UGUI的界面組件,包括一個按鈕,一個文本框,一個進度條。這些在Demo中演示瞭如何對這些物體交互。實際狀況,能夠定製

咱們來看ActionScriptStartUp.cs腳本,它是如何初始化的。github

  1. 在Start()函數中返回IEnumerator。通知Unity這個啓動過程是一個協程。能夠在多幀中完成
  2. 找到場景中的進度條UI元素。已提供加載的進度條指示
  3. 指示Unity,本GameObject不要在切換場景時卸載。它保存了腳本引擎。
  4. 建立腳本引擎實例
  5. 讀取腳本的字節碼。(Demo中從streamingAssetsPath中加載,實際狀況則能夠從網絡下載。如此即達到了熱更新的目的)
  6. 註冊Unity的API。  (Unity的API可能有數千個之多。這裏使用協程的目的就是能夠在這步提供進度條)
  7. 引擎加載字節碼,準備執行。
  8. 引擎建立字節碼中某個類型的實例(Demo中爲Main)
  9. 引擎獲取實例的某個方法 (Demo中爲update)
  10. ActionScriptStartUp的Update方法中,引擎驅動熱更類型的update方法,執行熱更邏輯。

其中,第9,10步不是必須的。由於熱更代碼中也能夠繼承Monobehaviour,只需在入口類型的構造函數或者包外代碼中,寫了相應邏輯,一樣能夠實現。網絡

一樣,UI進度條部分代碼也能夠剔除改爲本身的界面邏輯,或者,直接所有加載,不使用進度條也是可行的。併發

如今在Unity中點擊播放,可看到以下場景:app

 

熱更新腳本部分

 如今切換到熱更新工程,雙擊Main.as,打開熱更新腳本代碼:dom

  1 package
  2 {
  3     import unityengine.GameObject;
  4     import unityengine.MeshRenderer;
  5     import unityengine.PrimitiveType;
  6     import unityengine.Random;
  7     import unityengine.Time;
  8     import unityengine.UObject;
  9     import unityengine.Vector3;
 10     import unityengine.ui.Button;
 11     import unityengine.ui.Text;
 12     
 13     [Doc]
 14     /**
 15      * ...
 16      * @author 
 17      */
 18     public class Main
 19     {
 20         
 21         //使用 Vector.<>列表,保存全部的物體
 22         var cubes:Vector.<GameObject> = new Vector.<GameObject>();        
 23         //使用 Vector.<>列表,保存每一個物體的位移速度。
 24         var mvs:Vector.<Vector3> = new Vector.<Vector3>();
 25         
 26         public function Main() 
 27         {
 28             
 29             var cube:UObject = GameObject.find("Cube");
 30             //建立100個立方體。
 31             for (var i:int = 0; i < 100; i++) 
 32             {
 33                 //建立立方體
 34                 var c2:GameObject = GameObject.createPrimitive( PrimitiveType.Cube);
 35                 //給立方體設置材質
 36                 MeshRenderer( c2.getComponent(MeshRenderer)).material = MeshRenderer( GameObject( cube).getComponent(MeshRenderer)).material;
 37                 //設置立方體的初始位置
 38                 c2.transform.position = new Vector3( Random.range(-5,5),Random.range(0,5),Random.range(-5,5) );
 39                 //將立方體加入列表中
 40                 cubes.push(c2);
 41                 //初始化立方體的移動速度。
 42                 mvs.push( new Vector3(Random.range( -5, 5), Random.range(-5, 5), Random.range( -5, 5)) );
 43                 mvs[mvs.length - 1].normalize();
 44                 
 45             }    
 46             
 47             //查找UI界面的button。
 48             var btn:Button = Button( GameObject.find("Button").getComponent(Button));    
 49             //給Button加入事件。
 50             btn.onClick.addListener(            
 51                 onclick        //onclick是一個方法。能夠直接將方法穿遞給C#委託。    
 52             );
 53             
 54             
 55         }
 56         
 57         private function onclick()
 58         {
 59             isstop = !isstop;
 60             trace("isstop?" , isstop);
 61             //更新UI中Text的值
 62             Text( GameObject.find("Canvas/Text").getComponent(Text)).text = "isstop?" + isstop
 63             
 64             +"我在AS3中熱更"
 65             ;
 66             
 67         }
 68         
 69         private var isstop:Boolean = false;
 70         public function update():void
 71         {
 72             if (isstop)
 73                 return;
 74             
 75             for (var i:int = 0; i < 100; i++) 
 76             {
 77                 
 78                 var cube:GameObject = cubes[i];
 79                 var v:Vector3 = mvs[i];
 80                 
 81                 //更新每一個物體的位置。
 82                 //能夠看到使用了操做符重載,可使用   Vector3 * Number 來直接給位置賦值。
 83                 cube.transform.localPosition += v * Time.deltaTime;
 84                 
 85                 var p:Vector3 = cube.transform.localPosition;
 86                 if (p.x <-5 || p.y < -5 || p.z < -5 || p.x > 5 || p.y > 5 || p.z > 5)
 87                 {
 88                     //若是物體達到了邊界,則將速度反轉。
 89                     //能夠看到操做符重載。
 90                     mvs[i] =-mvs[i];
 91                 }
 92                 
 93             }
 94             
 95             //***其中Vector3是結構體。能夠在Unity Profiler中查看臨時內存開銷,能夠看到GC數爲0.也就是徹底沒有任何內存開銷
 96             
 97         }
 98         
 99     }
100     
101 }

能夠看到,構造函數中,構造了100個立方體,而且設置了它們的初始信息。函數

而後 update函數中,因爲每幀的調用,這些立方體動了起來。ui

使用Unity Profiler,能夠看到,每幀中的100次循環和Vector3操做,沒有產生任何的GC開銷spa

 

 如今咱們修改一下腳本:在建立立法體的地方,將立方體改成膠囊:插件

編譯後,Unity工程中便可看到效果。

相關文章
相關標籤/搜索