untiy 学习讨论群 184386599
1:直接去官网下载 https://github.com/Tencent/xLua
下载解压文件
2:创建一个Unity空项目
3:选择 xlua-》Assets 下的plugins +xlua 文件 放到Unity工程Assets下
直接代码了:里面有全部的注释和遇到的一些问题,有些问题也还不知道原因,可能是版本不兼容先记录一下
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using XLua; //引入命名空间
public class Test : MonoBehaviour
{
LuaEnv luaEnv; //lua虚拟机 来运行lua 代码
// Start is called before the first frame update
void Start()
{
luaEnv = new LuaEnv();
//LoadLua_1();
//LoadLua_2();
//LoadLua_3();
//CSCallLua();
LuaCallCSharp();
}
/// <summary>
/// 第一种加载lua 代码方式 不建议使用
/// </summary>
public void LoadLua_1()
{
luaEnv.DoString("print('hello World Lua')"); //输出
//luaEnv.DoString("print('hello World Lua2222')"); //输出
}
/// <summary>
/// 第二种加载lua 代码方式 建议使用
/// 先创建一个 testlua.lua 文件
/// </summary>
public void LoadLua_2()
{
//Resources 根据文件类型自动加载文件后缀, 这个就变成了 testlua.txt 所以这样写会加载不出来
//所以要把这个文件区分是lua文件就要再加个后缀 testlua.lua.txt
//TextAsset textAsset = Resources.Load<TextAsset>("testlua.lua");
//luaEnv.DoString(textAsset.ToString());
//这种方式使用 mylua.lua.txt 必须是这个后缀 require 引入并执行文件里面的代码
//require实际上是调一个个的loader去加载,有一个成功就不再往下尝试,全失败则报文件找不到。
//目前xLua除了原生的loader外,还添加了从Resource加载的loader,需要注意的是因为Resource只支持有限的后缀
//放Resources下的lua文件得加上txt后缀
luaEnv.DoString("require 'myLua'");
//这个loader 只能从Resoruce 里面加载lua文件
}
/// <summary>
/// 加载lua文件 自定义loader
/// </summary>
public void LoadLua_3()
{
luaEnv.AddLoader(OurSetLoder); //添加加载lua 文件的loader
luaEnv.DoString("require 'test'");
}
/// <summary>
/// 自定义的 loader 当lua 虚拟机添加了自定义的loader 时会先执行这个自定义的loader
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
private byte[] OurSetLoder(ref string filePath)
{
Debug.Log("OurSetLoder--- fliePath = " + filePath);
//在这个地方就可以对自己的代码做加密解密的工作
//这是一段lua代码 需要转成byte 文件
//string str = "print('测试自定义loader')";
//return System.Text.Encoding.UTF8.GetBytes(str);
//通过自定义的文件目录来加载lua文件 lua存放路径
string luaPath = Application.dataPath + "/lua/"+ filePath+ ".lua.txt";
byte[] tempBytes = System.Text.Encoding.UTF8.GetBytes(File.ReadAllText(luaPath));
return tempBytes;
}
/// <summary>
/// 访问lua 文件定义的变量-------------------------------------------------------------------------------------------------
/// </summary>
public void CSCallLua()
{
//lua虚拟机编译lua 文件
LoadLua_3();
//CSCallLuaGlobalVal();
CSCallLuaTable();
}
/// <summary>
/// C#访问lua 全局变量
/// </summary>
public void CSCallLuaGlobalVal()
{
//注意 类型, 和变量名 要对应 lua number 对应 C# int float double
int hp = luaEnv.Global.Get<int>("hp");
float mp = luaEnv.Global.Get<float>("mp");
string name = luaEnv.Global.Get<string>("name");
bool canFly = luaEnv.Global.Get<bool>("canFly");
Debug.Log("hp = " + hp + " mp = " + mp + " name = " + name + " canFly = " + canFly);
}
//对应lua HeroTable 的类 属性也可不不读取完 但是必须对应 对应的属性name hp 必须是public
public class Hero
{
public string name;
public int hp ;
public Skills[] skills;
public void PrintSkills()
{
if (skills.Length == 0)
{
Debug.LogError("没有读取到数组");
return;
}
for (int i=0; i< skills.Length;i++)
{
Debug.Log("name = "+ skills[i].name + " hart" + skills[i].hart + " cd" + skills[i].cd);
}
}
public string GetName()
{
return name;
}
public int GetHp()
{
return hp;
}
}
//对应lua SkillTable 的类
public class Skills
{
public string name;
public int hart ;
public int cd ;
}
//使用接口 ---------------- 必须加这个[CSharpCallLua] untiy 2018不兼容 只有2017才行
[CSharpCallLua]
public interface IHero
{
string name { get; set; }
int hp { get; set;}
Skills[] skills { get; set; }
}
[CSharpCallLua]
public interface ISkills
{
string name { get; set; }
int hart { get; set; }
int cd { get; set; }
}
/// <summary>
/// C# 访问lua table
/// </summary>
public void CSCallLuaTable()
{
// 1、映射到普通class或struct 定义一个class,有对应于table的字段的public属性,而且有无参数构造函数都可以
//这种方式下xLua会帮你new一个实例,并把对应的字段赋值过去。
//table的属性可以多于或者少于class的属性。可以嵌套其它复杂类型。
//要注意的是,这个过程是值拷贝,如果class比较复杂代价会比较大。而且修改class的字段值不会同步到table,反过来也不会
//Hero hero = luaEnv.Global.Get<Hero>("Hero");
//Debug.Log("hero.name = " + hero.GetName() + " hero.hp = " + hero.GetHp());
//hero.PrintSkills();
//2、映射到一个interface 这种方式依赖于生成代码(如果没生成代码会抛InvalidCastException异常),-------------
//代码生成器会生成这个interface的实例,如果get一个属性,生成代码会get对应的table字段,
//如果set属性也会设置对应的字段。甚至可以通过interface的方法访问lua的函数
//接口是一个引用拷贝 在接口里面改变了 lua 变量 lua 变量原始值也会改变
//接口需要测试,2018 不兼容一直报错(需要清理然后重新生成一下代码) 推荐使用的事这种方式
//IHero hero = luaEnv.Global.Get<IHero>("Hero");
//Debug.Log("hero.name = " + hero.name + " hero.hp = " + hero.hp);
//if (hero.skills.Length == 0)
//{
// Debug.LogError("没有读取到数组");
// return;
//}
//for (int i = 0; i < hero.skills.Length; i++)
//{
// Debug.Log("IHero name = " + hero.skills[i].name + " IHerohart" + hero.skills[i].hart + " IHerocd" + hero.skills[i].cd);
//}
//3.通过Dictionary 来映射 只能拿到有 table 里面有key 的键值对 {3,4,5} 这种拿不到
//Dictionary<string, object> dic = luaEnv.Global.Get<Dictionary<string, object>>("Hero");
//foreach (string key in dic.Keys)
//{
// Debug.Log("key = " + key + " value = " + dic[key]);
//}
//4.通过list 来映射 list 只能映射{3,4,5}里面的值 不能映射table有key的值
//List<object> list = luaEnv.Global.Get<List<object>>("Hero");
//foreach (object obj in list)
//{
// Debug.Log("obj = " + obj);
//}
//5.通过luatable xlua自定义 好像也只能得到带key 值的数据
//LuaTable luaTab = luaEnv.Global.Get<LuaTable>("Hero");
//Debug.Log("name = "+ luaTab.Get<string>("name") + " hp= "+ luaTab.Get<string>("hp"));
//访问lua 里面的全局函数
//不带参数的函数
//Action act = luaEnv.Global.Get<Action>("CallLua");
//act();
//act = null; //这个被lua虚拟机引用 清空才能dipose lua虚拟机
带参数的函数 1 也需要生成代码
//Action<int,int> act1 = luaEnv.Global.Get<Action<int,int>>("CallLua");
//act1(1,2);
//act1 = null;
//通过定义委托类型
//CallLua callLua = luaEnv.Global.Get<CallLua>("CallLua");
//callLua(3, 4);
//callLua = null;
有返回值 这个总是报错也不知道咋回事 也重新生成代码了还是不行 ref 也可以
//CallLuaAdd callLuaAdd = luaEnv.Global.Get<CallLuaAdd>("CallLuaAdd");
//int num = callLuaAdd(3, 4);
//Debug.Log("num = " + num);
//callLuaAdd = null;
//多个返回值依次类推 这个总是报错也不知道咋回事
//CallLuaAdd1 callLuaAdd1 = luaEnv.Global.Get<CallLuaAdd1>("CallLuaAdd1");
//int resa;
//int resb;
//int num = callLuaAdd1(3, 4,out resa,out resb);
//Debug.Log("num = " + num+ "resa = " + resa + "resb = " + resb);
//callLuaAdd1 = null;
//通过luaFuntion 多参数返回 不建议使用 性能慢
LuaFunction luaFun = luaEnv.Global.Get<LuaFunction>("CallLuaAdd1");
object[] objs = luaFun.Call(6, 7);
foreach (object o in objs)
{
Debug.Log("xxxx-----o = "+ o);
}
}
//定义委托和 lua里面函数名一样 并且加上CSharpCallLua 标签
[CSharpCallLua]
delegate void CallLua(int a, int b);
//有返回值
[CSharpCallLua]
delegate int CallLuaAdd(int a, int b);
//多个返回参数
[CSharpCallLua]
delegate int CallLuaAdd1(int a, int b, out int resa, out int resb);
/// 访问lua 文件定义的变量-------------------------------------------------------------------------------------------------
/// <summary>
/// lua 调用C#
/// </summary>
public void LuaCallCSharp()
{
luaEnv.AddLoader(OurSetLoder); //添加加载lua 文件的loader
luaEnv.DoString("require 'luaCallCSharp'");
//local newObj = CS.UnityEngine.GameObject("Cube") CS开头
//静态属性通过类访问
// CS.UnityEngine.Time.deltaTime CS.UnityEngine.Time.timeScale = 0.5
//小技巧:如果需要经常访问的类,可以先用局部变量引用后访问,除了减少敲代码的时间,还能提高性能:
//local GameObject = CS.UnityEngine.GameObject
//GameObject.Find('helloworld')
//访问C#成员属性,方法
//直接 Gameobjec.name
//.funcName(类对象,参数) 第一个参数默认对象本身 :funcName(参数)
}
/// <summary>
///
/// </summary>
private void OnDestroy()
{
luaEnv.Dispose(); //释放虚拟机 GC 等
}
}
对应的lua 文件 自定义文件夹的文件 test.lua.txt
print("通过lua文件加载test--------- hello world xLua");
hp = 1000
mp = 100.5
name = "哪吒"
canFly = true
print("C#读取lua的table")
Hero ={
name = "孙悟空",
hp = 200000,
skills =
{
{
name = "寒冰掌",
hart = 100,
cd = 3
},
{
name = "火云拳",
hart = 110,
cd = 4
}
},
1,2
}
function CallLua()
print("Hero :CallLua")
end
function CallLua(a,b)
print("Hero :CallLua"..a .." b= "..b);
end
function CallLuaAdd(a,b)
return a+b;
end
function CallLuaAdd1(a,b)
return a+b,a,b;
end
--默认带一个self参数代表当前表
function Hero:Talk(str)
print("Hero :Talk str= "..str)
end
--第一个参数要传递表
function Hero:TalkOne(self,str)
print("Hero .TalkOne str= " .. str)
end
luaCallCSharp.lua.txt 这个文件里面只有一句代码其他可以自己随便添加: local newObj = CS.UnityEngine.GameObject("Cube")
Resources 文件夹下的lua文件 只有一句输出
untiy 学习讨论群 184386599