zoukankan      html  css  js  c++  java
  • 用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工程的    StreamingAssetshotfix.cswc 中。实际情况可以按需要修改。

    Demo详解

    这个Demo场景提供了一些元素,可以概览热更项目的执行流程。

     Unity工程部分

    • AS3Player   一个GameObject。它挂载了ActionScriptStartUp.cs 脚本。这个脚本承载了初始化脚本引擎的所有功能。
    • Canvas       下的元素,是UGUI的界面组件,包括一个按钮,一个文本框,一个进度条。这些在Demo中演示了如何对这些物体交互。实际情况,可以定制

    我们来看ActionScriptStartUp.cs脚本,它是如何初始化的。

    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中点击播放,可看到如下场景:

    热更新脚本部分

     现在切换到热更新工程,双击Main.as,打开热更新脚本代码:

      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函数中,由于每帧的调用,这些立方体动了起来。

    使用Unity Profiler,可以看到,每帧中的100次循环和Vector3操作,没有产生任何的GC开销

     现在我们修改一下脚本:在创建立法体的地方,将立方体改为胶囊:

    编译后,Unity工程中即可看到效果。

  • 相关阅读:
    js中的单例模式
    node.js
    vscode设置
    Array.from();Object.keys();Array.map()
    js题
    如何申请成为企业微信,并成为第三方服务商
    微信企业号第三方平台应用开发
    SQL Server 给表和字段添加说明
    sql 语句写的行列转换
    不同数据库之间复制表的数据的方法
  • 原文地址:https://www.cnblogs.com/ashei/p/8874618.html
Copyright © 2011-2022 走看看