1. 程式人生 > >用ECMAScript4 ( ActionScript3) 實現Unity的熱更新 -- 使用原型鏈和EventTrigger

用ECMAScript4 ( ActionScript3) 實現Unity的熱更新 -- 使用原型鏈和EventTrigger

rip sta untiy poi lib stat package 匿名 對象

原型鏈是JS的必備,作為ECMAScript4,原型鏈也是支持的。

特別說明,ActionScript3是支持完整的面向對象繼承支持的,原型鏈只在某些非常特殊的情況下使用。

本文旨在介紹如何使用原型鏈。

任意對象類型都有一個prototype屬性,包括導入的Unity的API也有。我們可以和JS一樣的對這個prototype進行操作,比如動態的添加成員,添加方法等。

  1. 如果您決定使用原型鏈,那麽必須舍棄編譯時類型檢查。如果使用強類型,則編譯器會認為動態添加的成員不存在,而提示編譯錯誤。解決辦法為去掉變量的類型說明,或者將變量強制轉換成Object。
  2. 和JS引擎一樣,原型鏈必須在運行時順著prototype鏈查找。因此會影響性能。

本文說明,如何在腳本中,動態監聽 EventTrigger。我們將這篇文章中介紹的使用不可熱更的C#代碼做的監聽,改寫為ActionScript3實現。

工程說明

  1. 新建一個Untiy工程,並且創建AS3熱更新項目。如果不會創建,請參考這裏
  2. 在HotFixDemoScene1上添加一個Image。技術分享圖片
  3. 本次代碼需要使用 RectTransformUtility 這個類。如果是Unity2017.2版本以後,由於這個類型被分拆到了其他dll (UnityEngine.UIModule.dll),因此需要將它加入到配置表裏。
  4. 打開熱更新工程的genapi.config.xml ,將如下配置加入配置節中:
    <!--
    Configure DLLs to export--> <buildassemblys> <assembly value="D:\Program Files\Unity\Editor\Data\Mono\lib\mono\2.0\System.dll"></assembly> <assembly value="D:\Program Files\Unity\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll"></assembly> <
    assembly value="D:\Program Files\Unity\Editor\Data\Managed\UnityEngine\UnityEngine.UIModule.dll"></assembly> <assembly value="D:\Program Files\Unity\Editor\Data\UnityExtensions\Unity\GUISystem\UnityEngine.UI.dll"></assembly> <assembly value="F:/ASTool_UnityTest/HotFix_EventTrigger\Library\ScriptAssemblies\Assembly-CSharp.dll"></assembly> </buildassemblys>
  5. 打開熱更新項目的Main.as文件,將內容改為如下代碼:
    package
    {
        
        [Doc]
        /**
         * ...
         * @author 
         */
        public class Main
        {
            
            
            public function Main() 
            {    
            }
    
            public function update():void
            {    
            }
            
        }
        
    }
    import as3runtime.RefOutStore;
    import system.collections.generic.List_Of_EventTrigger_Entry;
    import unityengine.GameObject;
    import unityengine.MonoBehaviour;
    import unityengine.RectTransform;
    import unityengine.RectTransformUtility;
    import unityengine.Vector3;
    import unityengine.events.UnityAction_Of_BaseEventData;
    import unityengine.eventsystems.BaseEventData;
    import unityengine.eventsystems.EventTrigger;
    import unityengine.eventsystems.EventTriggerType;
    import unityengine.eventsystems.EventTrigger_Entry;
    import unityengine.eventsystems.PointerEventData;
    
    
    class UGUIEventTriggerTool
    {
        /**
         * 靜態方法。檢查某個GameObject上是否包含EventTrigger組件。如果有則返回它,否則創建一個並返回。
         * @param    go 輸入的GameObject
         * @return  返回EventTrigger
         */
        public static function Get(go:GameObject):EventTrigger 
        {  
            var trigger:EventTrigger = go.getComponent(EventTrigger) as EventTrigger;  
            if (null == trigger)
            {  
                trigger = EventTrigger(go.addComponent(EventTrigger));  
            }  
            return trigger;  
        }  
    }
    
    /* *
     *  在EventTrigger的原型鏈上定義AddEventListener方法。
     *  EventTrigger類型沒有公開構造函數,因此API導出時,不會為他創建在腳本中繼承的接口。
     *  這裏我們可以用原型鏈來對它進行擴展。
     *  包外代碼只會執行一次。所以只會在原型鏈上定義一次AddEventListener方法。
     * */
    EventTrigger.prototype.AddEventListener =    
        function (eventTriggerType:EventTriggerType,  action:UnityAction_Of_BaseEventData):void
        {
            /**
             * EventTrigger有一個嵌套內部類 UnityEngine.EventSystems.EventTrigger.Entry。
             * 由於ActionScript3並不支持嵌套類,因此它被導出成為EventTrigger_Entry。
             */        
            var entry:EventTrigger_Entry = new EventTrigger_Entry();  
            entry.eventID = eventTriggerType;  
            entry.callback.addListener(action);  
            
            this.triggers.add(entry);
            
        }  
    
    /**
     * 擴展MonoBehaviour,讓Image組件可以被拖拽。
     */
    class UGUIEventTriggerTest extends MonoBehaviour
    {
        function Start()
        {
            /**
             * 此處使用 * 類型來代表任意類型。
             * 這樣即可跳過編譯時類型檢查,使用原型鏈。
             * 否則將會提示編譯錯誤。
             */
            var t:* = UGUIEventTriggerTool.Get(gameObject);
            /**
             * 調用在原型鏈上定義的方法,給Drag事件添加處理函數。
             *  我們可以直接使用匿名函數來作為處理函數。
             */
            t.AddEventListener(EventTriggerType.Drag, 
            
                    function (baseData:BaseEventData):void
                    {
                        var data:PointerEventData = baseData as PointerEventData;
                        var rt:RectTransform = data.pointerPress.getComponent(RectTransform) as RectTransform;
                        var globalMousePos:Vector3;
                        
                        /**
                         * RectTransformUtility.screenPointToWorldPointInRectangle的參數
                         * worldPoint : (Out)UnityEngine.Vector3
                         * 是一個Ref Out參數。ActionScript3是沒有ref和out關鍵字的,
                         * 因此這裏使用RefOutStore來接收返回的參數。
                         */
                        var store:RefOutStore = new RefOutStore();                    
                        if (RectTransformUtility.screenPointToWorldPointInRectangle(rt, data.position, data.pressEventCamera, globalMousePos,store))
                        {
                            //傳入形參名,來提取值。
                            globalMousePos = store.getValue("worldPoint") as Vector3;
                            rt.position = globalMousePos;
                        }
                    }
                    
            
            );
        }
    
        
    }
    //將腳本掛載到Image上。
    GameObject.find("Image").addComponent(UGUIEventTriggerTest);
  6. 點擊編譯,然後在Unity中點擊播放。我們現在即可拖動這個Image。

技術分享圖片

用ECMAScript4 ( ActionScript3) 實現Unity的熱更新 -- 使用原型鏈和EventTrigger