Unity之热更新:(三)XLua
1. XLua是什么?
Xlua是Lua在C#环境(.net)下的Lua解决方案,包括C#环境下的Lua代码解释器(Lua虚拟机)。
2. 基于XLua的纯Lua开发环境的基本原则?
- Unity场景里不放任务物体,通过代码创建和释放物体。这样避免冲突,方便维护(比如程序和美术都往场景里放了同一物体),可以通过搜索代码查看创建了哪些物体以及结构关系。
- 运行时只有一个场景,没有场景切换。地图、角色、特效、粒子...都被做成资源或预制体给代码使用。(这一步实现美术与程序分离)
- 不手动往节点上面挂脚本,而是通过代码AddComponent挂载。(方便维护,直接搜索组件名称就能找到哪里挂载了脚本)
- 纯AssetsBundle来做资源管理,代替Resources。这样方便更新,方便打空包。
- 制定一个纯Lua的组件化开发框架。方便写业务逻辑,减少Lua与C#相互调用。
- 调试模式加载Lua代码、资源。AssetDataBase来加载资源。发布模式,打AB包,更新。
3. 在Unity中使用XLUA
1)https://github.com/Tencent/xlua 下载xlua
2)复制Assets文件夹下四个文件到工程Assets文件夹
3)打开宏
4)任何代码的修改都要执行以下两个步骤才能运行:
5)下面开始写C#调用Lua的代码
写一个lua文件,命名后缀 .lua.txt
注意lua文件要放在C#脚本的同级Resources目录下。
下面是C#脚本,演示C#脚本里调用lua。
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 using XLua; 5 6 public class textCSharp : MonoBehaviour 7 { 8 LuaEnv env = new LuaEnv(); 9 10 private void OnGUI() 11 { 12 if (GUILayout.Button("C#调用Lua语句")) 13 env.DoString("print 'testlua'"); 14 15 if (GUILayout.Button("C#调用Lua文件")) 16 CSharpCallLuaFile(); 17 } 18 void CSharpCallLuaFile() 19 { 20 env.DoString("require 'luatest'"); 21 //调用lua全局变量 22 Debug.Log(env.Global.Get<string>("name")); 23 Debug.Log(env.Global.Get<int>("age")); 24 //调用lua表中数据 25 LuaTable table = env.Global.Get<LuaTable>("config"); 26 Debug.Log(table.Get<string>("name")); 27 Debug.Log(table.Get<string>("age")); 28 } 29 }
也可以直接映射成类
1 public class textCSharp : MonoBehaviour 2 { 3 LuaEnv env = new LuaEnv(); 4 5 private void OnGUI() 6 { 7 if (GUILayout.Button("C#调用Lua文件")) 8 CSharpCallLuaFile(); 9 } 10 void CSharpCallLuaFile() 11 { 12 env.DoString("require 'luatest'"); 13 14 Config config = env.Global.Get<Config>("config"); 15 Debug.Log(config.name); 16 Debug.Log(config.age); 17 } 18 public class Config 19 { 20 public string name; 21 public int age; 22 } 23 }
1 void CSharpCallLuaFile() 2 { 3 env.DoString("require 'luatest'"); 4 //调用lua函数并接收返回值 5 LuaFunction fun = env.Global.Get<LuaFunction>("printInfo"); 6 object[] objs = fun.Call(); //lua函数可以有1个或多个返回值 7 Debug.Log(objs[0]); 8 }
结果是:第一行输出的是Call()里面的内容
也可以使用委托来调用lua函数
1 public class textCSharp : MonoBehaviour 2 { 3 LuaEnv env = new LuaEnv(); 4 5 delegate int Fun(int num); 6 private void OnGUI() 7 { 8 if (GUILayout.Button("C#调用Lua文件")) 9 CSharpCallLuaFile(); 10 } 11 void CSharpCallLuaFile() 12 { 13 env.DoString("require 'luatest'"); 14 //调用lua函数并接收返回值 15 Fun f = env.Global.Get<Fun>("printInfo"); 16 Debug.Log(f(0)); 17 } 18 }
输出:
6)下面演示Lua调用C#
先写一个C#类
1 public class Hero 2 { 3 private int Hp; 4 private string Name; 5 6 public Hero(string name, int hp) 7 { 8 this.Name = name; 9 this.Hp = hp; 10 } 11 public void PrintInfo() 12 { 13 Debug.Log(Name + "的血量是:" + Hp); 14 } 15 public int AddHp(int _hp) 16 { 17 Debug.Log("lua传递来的参数:" + _hp); 18 Hp += _hp; 19 return Hp; 20 } 21 }
lua脚本
注意:Lua调用C#类,要加CS
Lua调用 MonoBehaviour 类要加 CS.UnityEngine
别忘了在C#里执行一下
1 public class textCSharp:MonoBehaviour 2 { 3 LuaEnv env = new LuaEnv(); 4 void OnGUI() 5 { 6 if (GUILayout.Button("Lua调用C#")) 7 { 8 LuaCallCSharp(); 9 } 10 } 11 void LuaCallCSharp() 12 { 13 env.DoString("require 'luatest'"); 14 } 15 }
结果如下:
--------------------------------------------------------------------------------------------------------------------------------------------------------------
XLUA配置三步:
1.打标签 :XLUA会自动生成适配代码,注意子类打了标签,父类也要打。
[LuaCallCSharp] Lua里适配的委托、接口也要在C#定义里打标签。
[CSharpCallLua]
[Hotfix]
2.静态列表
3.动态列表
加 static List<Type> 修饰
详细参考:https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/configure.md
===================================================================================
下面我们来搭一个XLUA使用框架
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 using XLua; 5 using System; 6 7 [LuaCallCSharp] 8 public class LuaEnvMgr 9 { 10 //单例 11 private static LuaEnvMgr instance; 12 public static LuaEnvMgr Instance 13 { 14 get { 15 if (instance == null) 16 instance = new LuaEnvMgr(); 17 return instance; 18 } 19 } 20 //封装Lua虚拟机 21 private LuaEnv env; 22 public LuaEnv Env 23 { 24 get { return env; } 25 } 26 //构造函数初始化Lua虚拟机 27 public LuaEnvMgr() 28 { 29 env = new LuaEnv(); 30 } 31 //获取Lua table 32 public LuaTable GetGlobalTable() 33 { 34 return env.Global; 35 } 36 //创建Lua table 37 public LuaTable CreateTable() 38 { 39 return env.NewTable(); 40 } 41 //释放 42 public void Dispose() 43 { 44 env.Dispose(); 45 } 46 } 47 48 [CSharpCallLua] 49 public delegate void OnCollisionDel(Collision2D collision); 50 51 [CSharpCallLua] 52 public delegate void OnTriggerDel(Collider2D collision); 53 /// <summary> 54 /// 方便Lua调用C#生命周期函数 55 /// </summary> 56 [LuaCallCSharp] 57 public class LuaCallBase : MonoBehaviour { 58 59 public TextAsset textAsset;//lua文件 60 61 protected LuaTable table;//存储lua文件数据的表 62 63 //常用更新生命周期 64 protected Action luaAwake; 65 protected Action luaStart; 66 protected Action luaUpdate; 67 protected Action luaDestory; 68 protected Action luaOnGUI; 69 70 //自定义委托生命周期 71 protected OnCollisionDel luaCollisionEnter; 72 protected OnTriggerDel luaTriggerEnter; 73 74 75 protected virtual void Awake() 76 { 77 table = LuaEnvMgr.Instance.CreateTable(); 78 LuaTable meta = LuaEnvMgr.Instance.CreateTable(); 79 meta.Set("__index", LuaEnvMgr.Instance.GetGlobalTable()); 80 table.SetMetaTable(meta); 81 meta.Dispose(); 82 83 LuaEnvMgr.Instance.Env.DoString(textAsset.text, this.GetType().Name, table); 84 85 86 SetLuaData(); 87 GetLuaData(); 88 if (luaAwake != null) 89 luaAwake(); 90 } 91 92 public object GetLuaData(string dataName) 93 { 94 object obj; 95 table.Get(dataName,out obj); 96 return obj; 97 } 98 99 protected virtual void SetLuaData() 100 { 101 table.Set("self", this); 102 } 103 104 protected virtual void GetLuaData() 105 { 106 table.Get("awake", out luaAwake); 107 table.Get("start", out luaStart); 108 table.Get("update", out luaUpdate); 109 table.Get("destroy", out luaDestory); 110 table.Get("ongui", out luaOnGUI); 111 112 table.Get("onCollisionEnter", out luaCollisionEnter); 113 table.Get("onTriggerEnter", out luaTriggerEnter); 114 } 115 116 private void Start() 117 { 118 if (luaStart != null) 119 luaStart(); 120 } 121 private void Update() 122 { 123 if (luaUpdate != null) 124 luaUpdate(); 125 } 126 private void OnGUI() 127 { 128 if (luaOnGUI != null) 129 luaOnGUI(); 130 } 131 private void OnDestroy() 132 { 133 if (luaDestory != null) 134 luaDestory(); 135 } 136 137 private void OnCollisionEnter2D(Collision2D collision) 138 { 139 if (luaCollisionEnter != null) 140 luaCollisionEnter(collision); 141 } 142 private void OnTriggerEnter2D(Collider2D collision) 143 { 144 if (luaTriggerEnter != null) 145 luaTriggerEnter(collision); 146 } 147 }
只需要继承这个框架类,把lua脚本拖上去,就会执行啦!跟C#在Unity里的操作一样,只是挂载的C#脚本里的功能都由Lua脚本来实现了。
如果嫌Lua每次调用C#方法都要加前缀麻烦。可以写一个Lua公共脚本,把这些前缀重新赋值,其他脚本只要 require "公共脚本名",就可以像写C#一样调用Unity方法啦!
System=CS.System Int=System.Int32 String=System.String Unity=CS.UnityEngine Debug=Unity.Debug GameObject=Unity.GameObject Transform=Unity.Transform Renderer=Unity.Renderer Color=Unity.Color Vector3=Unity.Vector3 Vector2=Unity.Vector2 Input=Unity.Input Resources=Unity.Resources Camera=Unity.Camera LineRenderer=Unity.LineRenderer EdgeCollider2D=Unity.EdgeCollider2D Time=Unity.Time Vector3List=CS.System.Collections.Generic.List(Vector3) Vector2List=CS.System.Collections.Generic.List(Vector2) function getLuaData(obj,script,data) local instance=obj:GetComponent(script) return instance:GetLuaData(data) end