LUA调用C#文件
C# 给Lua注入一个变量
c#脚本中
LuaTable global = XLuaMgr.Instance.LuaEnv.Global; //C# 给Lua注入一个变量 global.Set 向Global的表中注入一个变量 //默认执行lua时,会索引到Global表 global.Set("gameObject", gameObject);
lua脚本可以直接打印该变量
-- 当前ReviewC#脚本所挂的游戏物体的名字打印 print("Review ... ...: " .. gameObject.name)
LuaEnv.DoString()方法的第二个参数作用
c#脚本
//第二参数报错时: 提示作用 XLuaMgr.Instance.LuaEnv.DoString("require('Review')", "Lua.Review");
LUA调用含有out、ref的方法
LuaOutRefFunction.lua
print("Lua Out Ref Function ... ...") OutRefClass = CS.OutRefClass local a = 1 -- C#的方法中的out参数,在lua中是以返回值的形式传出 -- 当方法本身有返回值时,out参数作为第二个及其之后的返回值传出 -- Lua调用C#带有out参数的方法时,out参数不需要传递参数,可以跳过,直接传递下一个 result, a = OutRefClass.Function(9,5) print("result:", result) print("a", a) -- C#的方法中有ref参数,在lua中是以返回值的形式传出 -- 当方法本身有返回值时,ref参数作为第二个及其之后的返回值传出 -- Lua调用C#带有ref参数的方法时,ref参数需要传递参数的 local b = 1 result, b = OutRefClass.Function1(b, 6) print("result:", result) print("b:", b) -- 可变参数的方法, xLua是支持的
LuaOutRefFunction.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public class LuaOutRefFunction : MonoBehaviour { void Start () { XLuaMgr.Instance.LuaEnv.DoString("require('LuaOutRefFunction')"); } } [XLua.LuaCallCSharp] public class OutRefClass { public static string Function(int c, out int a, int b) { a = 10; Debug.Log("c:" + c); Debug.Log("b:" + b); return "str"; } public static string Function1(ref int a, int b) { a = 10; Debug.Log("Function1 b:" + b); return "Function1"; } }
lua调用c#的枚举enum
LuaCallEnum.lua
print("Lua Call Enum ......") -- C# HeroType.Warrior -- Lua调用C#的枚举值 CS.命名空间.枚举类型.枚举值 -- C#的枚举的定义中,枚举值不要使用中文 local hType = CS.HeroType.Warrior -- xLua提供了, 数字与字符串转换成枚举的方法 -- CS.命名空间.枚举类型.__CastFrom(数字或字符串) -- 数字 2 转换成枚举, 不存在的int值,转换不会报错 hType = CS.HeroType.__CastFrom(2) -- 字符串转换 Mage 转换成枚举, c#枚举项中不能有中文,如果有中文,调用时会出错 hType = CS.HeroType.__CastFrom("巫师") --此处不会报错 可以赋值给hType,但是调用时会报错 -- 字符串转换 Mage 转换成枚举, 不存在的字符串, 转换会报错 hType = CS.HeroType.__CastFrom("Mage") print(hType) if hType == CS.HeroType.Warrior then print("战士") elseif hType == CS.HeroType.Mage then print("法师") elseif hType == CS.HeroType.Warlock then print("术士") -- elseif hType == CS.HeroType.巫师 then --CS.HeroType.巫师 会报错 -- print("巫师") end
LuaCallEnum.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; [XLua.LuaCallCSharp] public enum HeroType { /// <summary> /// 战士, 0 /// </summary> Warrior, /// <summary> /// 法师, 1 /// </summary> Mage, /// <summary> /// 术士, 2 /// </summary> Warlock, 巫师, } public class LuaCallEnum : MonoBehaviour { void Start () { XLuaMgr.Instance.LuaEnv.DoString("require('LuaCallEnum')"); } }
Lua不支持typeof()方法, 但是XLua支持typeof()方法
LuaTypeof.lua
print("Lua Typeof") GameObject = CS.UnityEngine.GameObject Image = CS.UnityEngine.UI.Image Color = CS.UnityEngine.Color local obj = GameObject.Find("Canvas/Image") --在xlua中是支持typeof关键字, 获取类型 local image = obj:GetComponent(typeof(Image)) --image.color = Color.red image.color = Color(1,1,1, 0.5)
LuaTypeof.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class LuaTypeof : MonoBehaviour { // Use this for initialization void Start () { XLuaMgr.Instance.LuaEnv.DoString("require('LuaTypeof')"); //GameObject obj = GameObject.Find("Canvas/Image"); //Image image = (Image)obj.GetComponent(typeof(Image)); //image.color = Color.red; } // Update is called once per frame void Update () { } }
xlua调用c#委托
注意:xlua调用静态和非静态委托格式是一致的 都是CS.(命名空间.)类名.委托变量名()
LuaCallDelegate.lua
print("Lua Call Delegate ......") function Func1() print("执行Lua Func1方法") end function Func2() print("执行Lua Func2方法") end -- 静态委托变量 非静态委托变量调用都是使用点的形式一样 -- Lua给C#的委托变量添加方法 CS.CallDelegate.action = Func1 -- Lua中没有 += 的复合赋值运算符,如果要 += 需要写出 a = a + b -- 当委托变量为空时,只能直接赋值,不能使用 a = a + b的形式添加方法 CS.CallDelegate.action = CS.CallDelegate.action + Func2 -- Lua将委托变量设置为空的 CS.CallDelegate.action = nil -- 直接赋值一个匿名字方法 CS.CallDelegate.action = function() print("执行Lua 匿名方法1111") end -- 叠加匿名字方法 CS.CallDelegate.action = CS.CallDelegate.action + function() print("执行Lua 匿名方法2222") end -- 调用委托, 调用委托时要注意判断是否是空的 if CS.CallDelegate.action then CS.CallDelegate.action() end -- C#调用泛型委托 function Func3(str) print("执行Lua Func3方法",type(str), str) end CS.CallDelegate.action1 = Func3 if CS.CallDelegate.action1 then CS.CallDelegate.action1("你好") end CS.CallDelegate.action2 = Func3 if CS.CallDelegate.action2 then CS.CallDelegate.action2(1.2) end
LuaCallDelegate.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; public class LuaCallDelegate : MonoBehaviour { void Start () { XLuaMgr.Instance.LuaEnv.DoString("require('LuaCallDelegate')"); } } [XLua.LuaCallCSharp] public class CallDelegate { public static Action action; public Action unStaticAction; public static Action<string> action1; //lua调用Action<float>的时候会报错 //需要在Action<float>的类前加[CSharpCallLua]特性 //但是Action<T> 是c#系统提供的类方法,不是自定义的 无法加[CSharpCallLua]特性 //此时需要写一个列表,用来配置系统提供的方法加[CSharpCallLua]特性 public static Action<float> action2; }
配置方法给系统类方法加[CSharpCallLuA]特性,因为是文件生成的时候激活下,放在Editor文件夹下
XLuaConfigList.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public static class XLuaConfigList { //创建一个Type类型的静态的List //通过这种方式,对cs_call_lua_list列表中的类型添加XLua.CSharpCallLua特性 //使xLua能识别到要对其生成配置代码 //当想要对系统C#的类, 或Unity的相关类添加给特性时,就可以使用这种方式 [XLua.CSharpCallLua] public static List<System.Type> cs_call_lua_list = new List<System.Type>() { typeof(System.Action<float>), typeof(GameObject) }; }
xlua调用c#事件
注意:xlua调用静态和非静态事件格式是不一致的
静态以“.”点的方式:CS.(命名空间.)类名.委托变量名()
非静态需要实例化对象,然后以“:”冒号的方式:对象:委托变量名()
LuaCallEvent.lua
print("Lua Call Event ......") function Func1() print("执行Lua Func1的方法") end function Func2() print("执行Lua Func2的方法") end -- Lua对事件进行添加方法与委托不一样 -- CS.类名.事件名("+", 要添加的方法名) -- 不表示调用事件,而是对事件添加方法 CS.CallEvent.action("+", Func1) CS.CallEvent.action("+", Func1) CS.CallEvent.action("+", Func2) -- 删除事件 CS.类名.事件名("-", 要添加的方法名) CS.CallEvent.action("-", Func2) -- 通过调用C#的执行事件的方法判断是否添加成功 CS.CallEvent.ExcuteStaticAction() -- Lua对非静态事件添加方法 function Func3() print("执行Lua Func3的方法") end local ce = CS.CallEvent() -- Lua添加非静态事件 对象:事件名("+", 要添加的方法名) -- 对象:事件名("-", 要添加的方法名) ce:unStaticAction("+", Func3) ce:ExcuteUnStaticAction()
LuaCallEvent.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public class LuaCallEvent : MonoBehaviour { void Start () { XLuaMgr.Instance.LuaEnv.DoString("require('LuaCallEvent')"); } } [XLua.LuaCallCSharp] public class CallEvent { //类外部只能赋值,不能调用 public static event System.Action action; public static void ExcuteStaticAction() { if (action != null) { action(); } } public event System.Action unStaticAction; public void ExcuteUnStaticAction() { if (unStaticAction != null) { unStaticAction(); } } }
LuaBehaviors.cs配置
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; using XLua; public class LuaBehaviour : MonoBehaviour { //执行的Lua文件的名字 public string luaFileName; private Action awake; private Action start; private Action update; private Action ondestroy; //定义提供了一个独立的存储区LuaTable, 用来存储当前的Lua执行时生成的变量和方法 //与Global全局做区分 private LuaTable scriptLua; private void Awake() { luaFileName = gameObject.name; //如果lua文件和物体的名字一直时可以这么写 string lua; //读取Lua文件的内容 if (!XLuaMgr.Instance.LoadLuaString(luaFileName, out lua)) { return; } //创建独立存储区表, 用来防止同名变量与全局Global出现冲突问题 scriptLua = XLuaMgr.Instance.LuaEnv.NewTable(); //当想要访问scriptLua表中某个变量或方法时,如果没有希望去Global中查找 //使用元表来实现 通过元方法 __index, 当访问表中不存在的索引时, 会执行元表中的__index元方法 //创建一个元表 LuaTable meta = XLuaMgr.Instance.LuaEnv.NewTable(); //在元表中添加元方法 __index meta.Set("__index", XLuaMgr.Instance.LuaEnv.Global); //设置scriptLua的元表是meta, xLua中很多对Lua语法的解析在Global中, //必须设置当前独立存储区的scriptLua的元表__index指向Global, 否则会造成Lua语言运行错误 scriptLua.SetMetaTable(meta); //释放元表的空间 meta.Dispose(); //将当前游戏物体注入到独立存储区scriptLua scriptLua.Set("gameObject", gameObject); scriptLua.Set("transform", transform); //执行当前Lua语言是, 将变量和方法注入到另外一个LuaTable中,不注入Global //将Lua语句中的变量与方法注入到scriptLua中 //需要直接运行Lua文件的内容,不能通过require方法加载文件,导致变量注入失败 XLuaMgr.Instance.LuaEnv.DoString(lua, luaFileName, scriptLua); //从当前独立存储区scriptLua获取Update方法 scriptLua.Get("Awake", out awake); scriptLua.Get("Start", out start); scriptLua.Get("Update", out update); scriptLua.Get("OnDestroy", out ondestroy); PlayerPrefs.DeleteKey if (awake != null) { awake(); } } private void Start() { if (start != null) { start(); } } private void Update() { if (update != null) { update(); } } private void OnDestroy() { if (ondestroy != null) { ondestroy(); } awake = null; start = null; update = null; ondestroy = null; scriptLua.Dispose(); } }
实例:登录页面
lua文件名和物体名一致,物体挂载luabehaviour配置
print("Login Panel ... ...") require("UnityAPI") local USERNAME_KEY = "Username" local PASSWORD_KEY = "Password" local userInput = nil local pwdInput = nil local tipText = nil local rememberMeToggle = nil -- 使用表来存储账号与密码, 键就是账号, 值就是密码 local userInfo = { admin = "666666", player = "250"} function Awake() -- 获取登录的按钮 local loginObj = transform:Find("Window/Login") local loginButton = loginObj:GetComponent(typeof(Button)) -- 对登录按钮添加事件 loginButton.onClick:AddListener(ClickLogin) -- 查找两个输入框 local userObj = transform:Find("Window/Username") userInput = userObj:GetComponent(typeof(InputField)) -- 对输入框添加事件 userInput.onValueChanged:AddListener ( function(value) tipText.text = "" end ) local pwdObj = transform:Find("Window/Password") pwdInput = pwdObj:GetComponent(typeof(InputField)) pwdInput.onValueChanged:AddListener ( function(value) tipText.text = "" end ) local tipObj = transform:Find("Window/TipText") -- 当输入框内容发生改变时, 提示框内容消失 tipText = tipObj:GetComponent(typeof(Text)) local rememberMeObj = transform:Find("Window/RememberMe") rememberMeToggle =rememberMeObj:GetComponent(typeof(Toggle)) end function Start() tipText.text = "" -- 每次进入要判断是否记录的上一次用户与密码 if PlayerPrefs.HasKey(USERNAME_KEY) then userInput.text = PlayerPrefs.GetString(USERNAME_KEY) end if PlayerPrefs.HasKey(PASSWORD_KEY) then pwdInput.text = PlayerPrefs.GetString(PASSWORD_KEY) end end function ClickLogin() print("点击登录按钮: " .. userInput.text .. " -- " .. pwdInput.text) if userInput.text == "" or pwdInput.text == "" then tipText.text = "请输入用户名与密码" return end --验证用户名 if userInfo[userInput.text] == nil then tipText.text = "用户名不存在" return end --验证密码 if userInfo[userInput.text] ~= pwdInput.text then tipText.text = "密码错误" return end --判断是否需要记录 if rememberMeToggle.isOn then -- print("记录用户名与密码") PlayerPrefs.SetString(USERNAME_KEY, userInput.text) PlayerPrefs.SetString(PASSWORD_KEY, pwdInput.text) else -- print("清楚记录的用户名与密码") PlayerPrefs.DeleteKey(USERNAME_KEY) PlayerPrefs.DeleteKey(PASSWORD_KEY) end --登录成功 GameObject.Destroy(gameObject) end