天天看點

Tolua使用筆記六:在lua中操作C#的委托事件與在lua中對Unity的GameObject的操作

案例十一:

該案例主要講解的是再Unity中對于C#中的委托的一些操作的方法

相比之前的一些例子,如果細心完整的看下來,會發現較開始的例子,這個例子算是比較複雜的了

核心代碼就不貼了,太長了,如果沒有經驗,直接看這個例子,可能你已經暈在這裡了,現在我就開始為大家細細的解析這樣一篇代碼

先從類TestEventListener開始說起,這是一個例子作者自己封裝的一個類,裡面包含了2種類型的委托和一些委托事件的變量和一些基礎的方法

public class TestEventListener : MonoBehaviour
{
    public delegate void VoidDelegate(GameObject go);
    public delegate void OnClick(GameObject go);    
    public OnClick onClick = delegate { };

    public event OnClick onClickEvent = delegate { };    
    
    public void SetOnFinished(OnClick click)
    {
        Debugger.Log("SetOnFinished OnClick");
    }
    
    public void SetOnFinished(VoidDelegate click)
    {
        Debugger.Log("SetOnFinished VoidDelegate");
    }

    [NoToLuaAttribute]
    public void OnClickEvent(GameObject go)
    {
        onClickEvent(go);
    }
}
           

這裡大家先留下一個概念,後面會用到這個類,然後大家回到腳本TestDelegate這邊來,這便是這個例子的入口類

按照慣例,作者一如既往的在Awake裡面就幾乎做完了所有的基本加載操作,我們都的時候也都是從這裡開始:

void Awake()
    {               
        state = new LuaState();
        state.Start();
        LuaBinder.Bind(state);   //加載基本的Warp檔案
        Bind(state);

        state.LogGC = true;
        state.DoString(script);
        GameObject go = new GameObject("TestGo");
        listener = (TestEventListener)go.AddComponent(typeof(TestEventListener));

        SetClick1 = state.GetFunction("SetClick1");
        AddClick1 = state.GetFunction("AddClick1");
        AddClick2 = state.GetFunction("AddClick2");
        RemoveClick1 = state.GetFunction("RemoveClick1");
        RemoveClick2 = state.GetFunction("RemoveClick2");
        TestOverride = state.GetFunction("TestOverride");
        AddEvent = state.GetFunction("AddEvent");
        RemoveEvent = state.GetFunction("RemoveEvent");        
    }
           

首先自然是建立lua虛拟機,然後調用 state.Start() 為虛拟機加載一些标準庫。

然後則是使用LuaBinder.Bind(LuaState  state) 為該虛拟機中加載一些基本的class類型,就是之前在CustomSetting中添加并Warp的類型

之後的Bind()函數則是為lua虛拟機加載一些該例子特有的類型,平時我們完全可以不通過該方法添加,直接在CustomSetting中添加即可。

然後就是編譯讀取下面的lua腳本

function DoClick1(go)                
                print('click1 gameObject is '..go.name)                    
            end

            function DoClick2(go)                
                print('click2 gameObject is '..go.name)                              
            end                       

            function AddClick1(listener)       --添加點選事件DoClick1
                if listener.onClick then
                    listener.onClick = listener.onClick + DoClick1                                                    
                else
                    listener.onClick = DoClick1    
                end                
            end
 
            function AddClick2(listener)       --添加點選事件DoClick2
                if listener.onClick then
                    listener.onClick = listener.onClick + DoClick2                      
                else
                    listener.onClick = DoClick2
                end                
            end

            function SetClick1(listener)       --設定點選事件
                if listener.onClick then
                    listener.onClick:Destroy()
                end

                listener.onClick = DoClick1         
            end

            function RemoveClick1(listener)    --移除點選事件DoClick1
                if listener.onClick then
                    listener.onClick = listener.onClick - DoClick1      
                else
                    print('empty delegate')
                end
            end

            function RemoveClick2(listener)    --移除點選事件DoClick2
                if listener.onClick then
                    listener.onClick = listener.onClick - DoClick2    
                else
                    print('empty delegate')                                
                end
            end

            --測試重載問題
            function TestOverride(listener)
                listener:SetOnFinished(TestEventListener.OnClick(DoClick1))
                listener:SetOnFinished(TestEventListener.VoidDelegate(DoClick2))
            end

            function TestEvent()     --測試事件
                print('this is a event')
            end

            function AddEvent(listener)    --添加事件
                listener.onClickEvent = listener.onClickEvent + TestEvent
            end

            function RemoveEvent(listener)   --移除事件
                listener.onClickEvent = listener.onClickEvent - TestEvent
            end
           

然後建立了一個遊戲物體,并為其綁定了一個最開始說到的那個TestEventListener元件;

在之後就是用Tolua#提供的luaFunction将之前讀取腳本中的lua方法取出。。。。方法的含義我已經在旁邊給出了注釋

接下來就看看OnGUI中的代碼,看看這裡是如何調用這些方法的

//UI面闆繪制方法
    void OnGUI()
    {
        if (GUI.Button(new Rect(10, 10, 120, 40), " = OnClick1"))
        {
            CallLuaFunction(SetClick1);
        }
        else if (GUI.Button(new Rect(10, 60, 120, 40), " + Click1"))
        {
            CallLuaFunction(AddClick1);
        }
        else if (GUI.Button(new Rect(10, 110, 120, 40), " + Click2"))
        {
            CallLuaFunction(AddClick2);
        }
        else if (GUI.Button(new Rect(10, 160, 120, 40), " - Click1"))
        {
            CallLuaFunction(RemoveClick1);
        }
        else if (GUI.Button(new Rect(10, 210, 120, 40), " - Click2"))
        {
            CallLuaFunction(RemoveClick2);
        }
        else if (GUI.Button(new Rect(10, 260, 120, 40), "+ Click1 in C#"))
        {
            LuaFunction func = state.GetFunction("DoClick1");
            TestEventListener.OnClick onClick = (TestEventListener.OnClick)DelegateFactory.CreateDelegate(typeof(TestEventListener.OnClick), func);
            listener.onClick += onClick;
        }        
        else if (GUI.Button(new Rect(10, 310, 120, 40), " - Click1 in C#"))
        {
            LuaFunction func = state.GetFunction("DoClick1");
            listener.onClick = (TestEventListener.OnClick)DelegateFactory.RemoveDelegate(listener.onClick, func);
            func.Dispose();
            func = null;
        }
        else if (GUI.Button(new Rect(10, 360, 120, 40), "OnClick"))
        {
            if (listener.onClick != null)
            {
                listener.onClick(gameObject);
            }
            else
            {
                Debug.Log("empty delegate!!");
            }
        }
        else if (GUI.Button(new Rect(10, 410, 120, 40), "Override"))
        {
            CallLuaFunction(TestOverride);
        }
        else if (GUI.Button(new Rect(10, 460, 120, 40), "Force GC"))
        {
            //自動gc log: collect lua reference name , id xxx in thread 
            state.LuaGC(LuaGCOptions.LUA_GCCOLLECT, 0);
            GC.Collect();
        }
        else if (GUI.Button(new Rect(10, 510, 120, 40), "event +"))
        {
            CallLuaFunction(AddEvent);
        }
        else if (GUI.Button(new Rect(10, 560, 120, 40), "event -"))
        {
            CallLuaFunction(RemoveEvent);
        }
        else if (GUI.Button(new Rect(10, 610, 120, 40), "event call"))
        {
            listener.OnClickEvent(gameObject);
        }
    }
           

這裡涉及到該例子中的一個方法CallLuaFunction()

void CallLuaFunction(LuaFunction func)
    {        
        func.BeginPCall();
        func.Push(listener);
        func.PCall();
        func.EndPCall();                
    }
           

其實就是對luaFunction的調用的一種封裝,使得其預設總是以之前的那個TestEventListener元件為參數來調用LuaFunction

·有了這些之後,我們就可以來很輕松的這些按鈕的作用了!!!

首先是按鈕" = OnClick1" ,該放啊對應的代碼其實就是直接以TestEventListener元件為參數來調用lua的方法 SetClick1(listener)

該lua方法的代碼如下:

function SetClick1(listener)       --設定點選事件
                if listener.onClick then
                    listener.onClick:Destroy()
                end

                listener.onClick = DoClick1         
            end
           

1:在這段代碼中我們可以看到 C#中的委托可以直接使用 if 語句判空 ,并且可以使用 Delegate:Destory()來銷毀該委托

2:對于C#中的委托的指派可以直接使用 lua中的方法以指派運算符指派 例如 : listener.onClick = DoClick1

然後是按鈕 " + Click1" 和 按鈕 " + Click2 " 這裡講解了如何為委托綁定額外的方法,相當于C#中的對于委托的+=操作

該部分lua方法的代碼如下:

function AddClick1(listener)       --添加點選事件DoClick1
                if listener.onClick then
                    listener.onClick = listener.onClick + DoClick1                                                    
                else
                    listener.onClick = DoClick1    
                end                
            end
 
            function AddClick2(listener)       --添加點選事件DoClick2
                if listener.onClick then
                    listener.onClick = listener.onClick + DoClick2                      
                else
                    listener.onClick = DoClick2
                end                
            end
           

由于lua中不支援+=運算符,是以,在這裡采用了後面的寫法替代: Delegate = Delegate + 方法

相對應的有綁定也自然有取消綁定功能,展現該功能的按鈕是分别是 " - Click1" 和 " - Click2 " ,

lua代碼如下:

function RemoveClick1(listener)    --移除點選事件DoClick1
                if listener.onClick then
                    listener.onClick = listener.onClick - DoClick1      
                else
                    print('empty delegate')
                end
            end

            function RemoveClick2(listener)    --移除點選事件DoClick2
                if listener.onClick then
                    listener.onClick = listener.onClick - DoClick2    
                else
                    print('empty delegate')                                
                end
            end
           

同樣的,lua之中也不支援-=運算符,是以使用這樣的寫法 : Delegate = Delegate - 方法

按鈕"OnClick" 就不用看了哈 ,就是最基本的C#的委托調用

然後是 按鈕 "Override" ,該按鈕主要是為了向大家證明在lua中重載函數的正常使用

Tolua#是完全相容重載函數的,同時還向大家展示了在lua中建立委托的寫法

直接 委托類型(參數清單) 即可在lua中建立一個新的委托變量~~~,是不是很友善

對應的代碼如下:

function TestOverride(listener)
                listener:SetOnFinished(TestEventListener.OnClick(DoClick1))
                listener:SetOnFinished(TestEventListener.VoidDelegate(DoClick2))
            end
           

剩下的按鈕 " + Click in C# " 和 " - Click in C#" 則是展示了如何在C#中删除綁定的lua方法

if (GUI.Button(new Rect(10, 260, 120, 40), "+ Click1 in C#"))
        {
            LuaFunction func = state.GetFunction("DoClick1");
            TestEventListener.OnClick onClick = (TestEventListener.OnClick)DelegateFactory.CreateDelegate(typeof(TestEventListener.OnClick), func);
            listener.onClick += onClick;
        }        
        else if (GUI.Button(new Rect(10, 310, 120, 40), " - Click1 in C#"))
        {
            LuaFunction func = state.GetFunction("DoClick1");
            listener.onClick = (TestEventListener.OnClick)DelegateFactory.RemoveDelegate(listener.onClick, func);
            func.Dispose();
            func = null;
        }
           

其實就是将lua方法取出到C#中,然後轉成LuaFunction ,然後直接使用

DelegateFactory.CreateDelegate 和 DelegateFactory.RemoveDelegate
           

進行添加和删除,順便友情提示, LuaFunction使用法之後要記得手動釋放喲,否則會有GC

最後是對于在lua中操作C#的事件,其操作手法和委托極其相似,大家其實看一看就可以學會了,,基本上就是這些了

最後這個例子中需要用到的委托類型也都是要單獨導出Warp的,操作手法其實就是将需要的委托類型添加到CustomSetting.cs的customDelegateList中

樣例寫法如下:

public static DelegateType[] customDelegateList =
    {        
        _DT(typeof(Action)),
        //_DT(typeof(Action)).SetAbrName("ActionGo"),
        _DT(typeof(UnityEngine.Events.UnityAction)),      
        
        _DT(typeof(TestEventListener.OnClick)),
        _DT(typeof(TestEventListener.VoidDelegate)),
    }; 
           

效果截圖比較長且和操作順序有關,這一部分就不截圖了嘎嘎嘎

案例12

這個例子相比之前的那個,看起來就舒服多了

核心代碼如下:

private string script =
        @"                                    
            local GameObject = UnityEngine.GameObject          
            local ParticleSystem = UnityEngine.ParticleSystem            

            local go = GameObject('go')
            go:AddComponent(typeof(ParticleSystem))
            local node = go.transform
            node.position = Vector3.one      
            print('gameObject is: '..tostring(go))    
            GameObject.Destroy(go, 2)                        
        ";

    LuaState lua = null;

    void Start()
    {        
        lua = new LuaState();
        lua.LogGC = true;
        lua.Start();
        LuaBinder.Bind(lua);
        lua.DoString(script);            
    }
           

主要的方法就是

GameObject:AddComponent(typeof(Component))  在lua中給遊戲物體添加元件

GameObject("遊戲物體名")  在lua中建立新的遊戲物體

GameObject.Destroy(遊戲對象, 延遲時間)  延時銷毀的指定的遊戲物體

非常簡單,大家随便看看就好了

效果截圖如下:

Tolua使用筆記六:在lua中操作C#的委托事件與在lua中對Unity的GameObject的操作

好了,今天就到這裡吧!大家下回再見

繼續閱讀