用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工程中便可看到效果。

相关文章
相关标签/搜索