xLua热更新

1、作者教程:http://www.gad.qq.com/article/detail/24967

2、GitHub地址:https://github.com/Tencent/xLua       下载之后只需要把Plugins、XLua两个文件夹导入到Unity3D的Assets目录下就可以了。可以按照XLua文件夹下的XLua教程进行学习(如下图)

xLua热更新_第1张图片


001-利用XLua在控制台输出Hello world

/*
*Title:"XLua学习"项目开发
*/

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;				//引入xLua命名空间
public class HelloWorld : MonoBehaviour {
    private LuaEnv _luaenv;		//推荐全局唯一
    void Start () {
        _luaenv = new LuaEnv();		//Lua运行环境

        //_luaenv.DoString("print('Hello world')");			//执行字符串形式的Lua代码
        _luaenv.DoString("CS.UnityEngine.Debug.Log('Hello world')");	//调用C#的Api
    }
	
    private void OnDestroy()
    {
        _luaenv.Dispose();		//释放lua运行环境
    }
}

002-读取Lua文件的代码并运行

在Resources文件夹下新建一个Lua文件。如:HelloWorld.lua.txt(由于用Resources.Load()加载的是.txt类型的文件)

/*
*Title:"XLua学习"项目开发
*
*Description:
*	用于场景002
*   读取Lua文件来执行Lua代码
*Date:2017
*
*Version:0.1
*
*Modify Recoder:
*/

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
public class HelloWorldByFile : MonoBehaviour {
    LuaEnv _luaEnv;
	// Use this for initialization
	void Start () {
        _luaEnv = new LuaEnv();
        //方法1
        //TextAsset ta =  Resources.Load("HelloWorld.lua");//后缀自动添加.txt,因为是TextAsset类型
        //_luaEnv.DoString(ta.text); //读取文本的字符串并运行

        //方法2 用xLua自带的Loader加载和执行
        _luaEnv.DoString("require 'HelloWorld'"); //HelloWorld相当于HelloWorld.lua.txt,XLua的Loader会自动在Resources目录下加载
    }
    void OnDestroy()
    {
        _luaEnv.Dispose();
    }
}
003-自定义Loader,读取其他目录下的Lua文件

/*
*Title:"XLua学习"项目开发
*
*Description:
*	自定义Loader(加载器)
*
*Date:2017
*
*Version:0.1
*
*Modify Recoder:
*/

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
using System.IO;

public class DefineLoader : MonoBehaviour {
    private LuaEnv _luaEnv;
	// Use this for initialization
	void Start () {
        _luaEnv = new LuaEnv();
        _luaEnv.AddLoader(MyLoader); //增加一个Loader
        _luaEnv.DoString("require 'DefineLoaderTest'");
    }
	
    //通过require加载一个文件的时候,会访问每一个Loader(先访问自定义的Loader后内置Loader)直到返回的不为空
    private byte[] MyLoader(ref string filePath)
    {
        Debug.Log(filePath);            //这里filePath为DefineLoaderTest 
        string absPath = Application.streamingAssetsPath + "/" + filePath + ".lua.txt"; //获取文件所在目录
        //把lua文件里面的字符串转换成字节数组返回,lua文件如果有中文需要把编码改为UTF8
        return System.Text.Encoding.UTF8.GetBytes(File.ReadAllText(absPath));       
    }

    void OnDestroy()
    {
        _luaEnv.Dispose();
    }
}

004-通过C#调用Lua里面的全局变量、表(方法、变量)

CSharpCallLua(lua代码):

intA = 100
floB = 0.52
isRun = true
strName = 'Happy'


person = {
 name = 'Jackey',age = 20,3,4.5,true,"stringgg",
 eat = function(self,foodName) --self代表当前对象,比C#对应的对象多一个参数
  print("正在吃:"..foodName)
 end
}


--[其他方式
function person:eat(foodName) --用:的方式,会自动添加self
 print("正在吃:"..foodName)
end


function person.eat(self,foodName) --用.的方式,要自行添加
 print("正在吃:"..foodName)
end
--]


function add(a,b) --全局函数
 print(a+b)
 return a+b,a,b
end
C#代码:

/*
*Title:"XLua学习"项目开发
*
*Description:
*	C#访问Lua里面的全局变量
*
*Date:2017
*
*Version:0.1
*
*Modify Recoder:
*/


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
using System;
public class CSharpCallLua : MonoBehaviour {
    private LuaEnv _env; 
	// Use this for initialization
	void Start () {
        _env = new LuaEnv();
        _env.DoString("require 'CSharpCallLua'");               //加载并执行lua文件


        /*获取基本变量*/
        int intA = _env.Global.Get("intA");                //获取Lua里面Int类型的全局变量
        Debug.Log(intA);
        float floB = _env.Global.Get("floB");            //获取Lua里面float类型的全局变量
        Debug.Log(floB);
        bool isRun = _env.Global.Get("isRun");            //获取Lua里面bool类型的全局变量
        Debug.Log(isRun);
        string strName = _env.Global.Get("strName");    //获取Lua里面string类型的全局变量
        Debug.Log(strName);


        /*获取table的方式一,通过类Class(Struct)*/
        Person p = _env.Global.Get("person"); //值拷贝,C#修改数据并不会同步到Lua,Lua修改也不影响C#
        Debug.Log(p.name);
        Debug.Log(p.age);


        /*获取table的方式二,通过接口interface(推荐)*/
        IPerson ip = _env.Global.Get("person"); //传引用,在C#修改会影响Lua里面的变量
        Debug.Log(ip.name);
        Debug.Log(ip.age);
        ip.eat("鸡腿"); //相当于ip.eat(ip,"鸡腿");


        /*获取table的方式三,通过键值对Dictionary、集合List(推荐)*/
        //Dictionary--只能映射table里面有键的元素
        Dictionary dict = _env.Global.Get>("person");
        foreach (string key in dict.Keys)
        {
            Debug.Log(key + '-' + dict[key]);
        }
        //List--只能映射table里面没有键的元素
        List list = _env.Global.Get>("person");
        foreach (object item in list)
        {
            Debug.Log(item);
        }


        /*通过LuaTable类(不推荐,性能比较差)*/
        LuaTable tab = _env.Global.Get("person");
        print(tab.Get("name"));
        print(tab.Get("age"));
        print(tab.Length);




        /*访问Lua中的全局函数*/
        //方法一:映射到delegate
        Add act1 = _env.Global.Get("add");//属于命名空间System
        int resa, resb;
        print(act1(1,2,out resa,out resb));
        print(resa);
        print(resb);


        //方法二:映射到LuaFunction (不推荐)
        LuaFunction lf = _env.Global.Get("add");
        object[] os = lf.Call(3, 4);
        foreach (object item in os)
        {
            print(item);
        }


    }
    class Person
    {
        public string name;
        public int age;
    }


    [CSharpCallLua] //会为接口增加一些映射使用的代码
    interface IPerson
    {
        string name { get; set; }  //必须添加get set属性
        int age { get; set; }
        void eat(string foodName);
    }
    [CSharpCallLua]
    delegate int Add(int a, int b,out int resa,out int reab); //lua全剧函数里面的第一个返回值会给C#的返回值,第二个返回值会给第一个out,第三个返回值会给第二个out
    void OnDestroy()
    {
        _env.Dispose();
    }
} 
  

005-通过lua代码访问C#

LuaCallCSharp(lua代码):

CS.UnityEngine.GameObject("new by lua")				--创建游戏物体(new对象)

print(CS.UnityEngine.Time.deltaTime)				--访问C#静态属性

CS.UnityEngine.Time.timeScale = 0.5					--设置C#中的属性

local camera = CS.UnityEngine.GameObject.Find('Main Camera')	--用局部变量保存C#中的对象

camera.name = "update by lua"						--修改对象名称

local gameObject = CS.UnityEngine.GameObject		--用局部变量进行引用,可以节省性能,以及减少编码量
local light = gameObject.Find('Directional Light')
light.name = 'new light name'

local cameraCam = camera:GetComponent('Camera')    --获取Camera上的组件。推荐使用冒号调用成员函数,如果用点的话,第一个参数需要是当前对象        
gameObject.Destroy(cameraCam)                      --移除这个组件

C#代码:

/*
*Title:"XLua学习"项目开发
*
*Description:
*	在lua里访问C#
*
*Date:2017
*
*Version:0.1
*
*Modify Recoder:
*/

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;

public class LuaCallCSharp : MonoBehaviour {

    private LuaEnv _env;
    // Use this for initialization
    void Start()
    {
        _env = new LuaEnv();
        _env.DoString("require 'LuaCallCSharp'");               //加载并执行lua文件
    }

    void OnDestroy()
    {
        _env.Dispose();
    }
}

006-lua和C#中参数的对应(ref、out等关键字)

Lua调用侧的参数处理规则:C#普通参数算一个输入形参,ref修饰的算一个输入形参,out不算,然后从左往右对应lua调用侧的实参列表。

Lua调用侧的返回值处理规则:C#函数的返回值(如果有的话)算一个返回值,out 算一个返回值,ref算一个返回值,然后从左往右对应lua的多返回值。

007-特性[LuaCallCSharp]和[CSharpCallLua]

Lua获取或者调用C#的时候用[LuaCallCSharp]

在C#获取或者调用Lua的时候用[CSharpCallLua]

在枚举,委托,接口等前面加上[CSharpCallLua]或者[LuaCallCSharp]

008-lua中相当于C#中+=或-=的事件注册

例如testobj里有一个事件:public event Action TestEvent;

增加事件回调:testobj:TestEvent('+',lua_evnet_callback)

移除事件回调:testobj:TestEvent('-',lua_event_callback)


热更新大致流程

更新的东西有两部分:1、资源(Assetbundle) 2、lua代码    这两样东西放在服务器端,客户端连接服务器检查(MD5校验)是否有更新。服务器端使用一个文本文件存放所有Assetbundle和Lua的文件列表和对应的MD5值。客户端下载这个文本文件,客户端拿本地资源的MD5值对比服务器的MD5值,如果不一样则进行更新。这是其中一种方法。



你可能感兴趣的:(xLua热更新)