|
Unity + XLua 简单框架结构
Xlua环境搭建教程入口.
一.unity内创建lua脚本
- usingSystem.Collections;usingSystem.Collections.Generic;usingSystem.IO;usingSystem.Text;usingSystem.Text.RegularExpressions;usingUnityEditor;usingUnityEditor.ProjectWindowCallback;usingUnityEngine;publicclassGenLua{[MenuItem("Assets/Create/Lua Script",false,80)]publicstaticvoidCreatNewLua(){
- ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0,
- ScriptableObject.CreateInstance<MyDoCreateScriptAsset>(),GetSelectedPathOrFallback()+"/New Lua.lua",null,"Assets/Editor/Template/NewLua.txt");}publicstaticstringGetSelectedPathOrFallback(){string path ="Assets";foreach(UnityEngine.Object obj in Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.Assets)){
- path = AssetDatabase.GetAssetPath(obj);if(!string.IsNullOrEmpty(path)&& File.Exists(path)){
- path = Path.GetDirectoryName(path);break;}}return path;}}classMyDoCreateScriptAsset:EndNameEditAction{publicoverridevoidAction(int instanceId,string pathName,string resourceFile){UnityEngine.Object o =CreateScriptAssetFromTemplate(pathName, resourceFile);
- ProjectWindowUtil.ShowCreatedAsset(o);}internalstaticUnityEngine.ObjectCreateScriptAssetFromTemplate(string pathName,string resourceFile){string fullPath = Path.GetFullPath(pathName);StreamReader streamReader =newStreamReader(resourceFile);string text = streamReader.ReadToEnd();
- streamReader.Close();string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(pathName);
- text = Regex.Replace(text,"#NAME#", fileNameWithoutExtension);bool encoderShouldEmitUTF8Identifier =true;bool throwOnInvalidBytes =false;UTF8Encoding encoding =newUTF8Encoding(encoderShouldEmitUTF8Identifier, throwOnInvalidBytes);bool append =false;StreamWriter streamWriter =newStreamWriter(fullPath, append, encoding);
- streamWriter.Write(text);
- streamWriter.Close();
- AssetDatabase.ImportAsset(pathName);return AssetDatabase.LoadAssetAtPath(pathName,typeof(UnityEngine.Object));}}
复制代码 代码转载自雨松MoMo
将此段代码放入unity的Editor目录下,然后在相应目录下创建NewLua.txt模板,即可像创建C#脚本那样创建lua脚本
NewLua.txt 模板
- local#NAME#=class()-- 自定义数据-- 构造函数function#NAME#:Ctor(params)end-- 开始函数function#NAME#:Start()endreturn#NAME#
复制代码 在unity中新建一个LuaScript文件夹,用于保存lua脚本
二.创建 LuaManager 脚本
可以创建lua脚本后,直接进入正题。在C#中执行Lua脚本,我们可以new一个LuaEnv环境变量来使用Dostring方法来执行lua脚本。LuaManager用于更方便的执行lua脚本。代码如下- publicclassST_LuaMannager:MonoBehaviour{privatestaticreadonlyobject padlock =newobject();privatestaticST_LuaMannager instance;//统一管理UpdatepubliceventAction luaUpdates;//单例类publicstaticST_LuaMannager Instance
- {get{if(instance ==null){lock(padlock){if(instance ==null){GameObject go =newGameObject("LuaManager");DontDestroyOnLoad(go);
- instance = go.AddComponent<ST_LuaMannager>();}}}return instance;}}LuaEnv luaEnv;float lastGcTime =0;//luaGC回收时间见隔constfloat GCInterval =1;//全局唯一lua环境publicLuaEnv MyLuaEnv
- {get{if(luaEnv ==null){
- luaEnv =newLuaEnv();
- luaEnv.AddLoader(LuaLoader);//加载lua全局变量
- luaEnv.DoString("require 'ST/ST_LuaEnv'");//luaEnv.DoString("require 'TestClass'");}return luaEnv;}}//自定义Loaderpublicstaticbyte[]LuaLoader(refstring filename){byte[] byArrayReturn =null;string luaPath = Application.dataPath +"/LuaScripts/"+ filename.Replace(".","/")+".lua";string strLuaConent = File.ReadAllText(luaPath);
- byArrayReturn = System.Text.Encoding.UTF8.GetBytes(strLuaConent);return byArrayReturn;}//封装dostring 方法publicobject[]Dostring(string str,string chunkName ="chunk"){var ret = MyLuaEnv.DoString(str, chunkName);return ret;}privatevoidUpdate(){//定时GCif(Time.time - lastGcTime > GCInterval){
- MyLuaEnv.Tick();
- lastGcTime = Time.time;}//管理luaUpdateif(luaUpdates !=null){luaUpdates();}}}
复制代码 这里采用自定义Loader的方法加载Lua,并使用全局唯一的lua环境,ST_LuaEnv 里面主要包含lua环境的公共变量和函数。Update方法里实现lua定时垃圾回收,执行绑定lua 脚本的Update方法。
测试
分别创建ST_LuaEnv.lua,Tests.lua,TestEnv.cs脚本
ST_LuaEnv- TestValue =2functionAdd(a,b)return a + b
- end
复制代码 Tests.luaTestEnv.cs- publicclassTestEnv:MonoBehaviour{// Start is called before the first frame updatevoidStart(){
- ST_LuaMannager.Instance.Dostring("require 'Tests'");}}
复制代码 创建空节点,运行Unity,结果如下
三.Lua面向对象
让Lua脚本具有面向对象特性可以使我们编程更加方便,在ST_LuaEnv里面添加面向对象方法代码如下- functionclone(object)local lookup_table ={}localfunctioncopyObj(object)iftype(object)~="table"thenreturn object
- elseif lookup_table[object]thenreturn lookup_table[object]endlocal new_table ={}
- lookup_table[object]= new_table
- for key, value inpairs(object)do
- new_table[copyObj(key)]=copyObj(value)endreturnsetmetatable(new_table,getmetatable(object))endreturncopyObj(object)endlocal _class ={}--[[
- @desc: class
- author:{}
- time:2022-01-24 17:47:45
- --@super: 父类
- @return:返回一个类
- ]]functionclass(super)local class_type ={}
- class_type.Ctor =false
- class_type.super = super
- class_type.New =function(...)local obj ={}dolocal create
- create =function(c,...)if c.super thencreate(c.super,...)endif c.Ctor then
- c.Ctor(obj,...)endendcreate(class_type,...)end--setmetatable(obj,{ __index=_class[class_type] })(原)setmetatable(obj,{__index =clone(_class[class_type])})return obj
- endlocal vtbl ={}
- _class[class_type]= vtbl
- setmetatable(class_type,{
- __newindex =function(t, k, v)
- vtbl[k]= v
- end})if super thensetmetatable(vtbl,{
- __index =function(t, k)local ret = _class[super][k]
- vtbl[k]= ret
- return ret
- end})endreturn class_type
- end
复制代码 这里的面向对象方法引用自云风的个人空间 并对代码做了一定的修改,满足我们的要求,测试代码如下- local TestClass =class()-- 自定义数据
- TestClass.ta ={x =1}local a1 = TestClass.New();local s = a1.ta;print(a1.ta.x)
- s.x =55local a2 = TestClass.New();print(a2.ta.x)
复制代码 原代码输出如下(可以看到,修改a1实列的ta.x值后基类的ta.x值也一并修改了)
修改后
四.GameObject绑定lua脚本
创建ST_LuaBehaviours.cs 代码如下:- usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;usingXLua;usingSystem;usingDG.Tweening;[LuaCallCSharp]publicclassST_LuaBehaviours:MonoBehaviour{//文件在LuaScript下的路径publicstring LuaFile;//需要绑定的对象数组publicInjection[] injections;//绑定的luaTableLuaTable luaTable;//Lua调C#方法privateAction<LuaTable> luaStart;privateAction<LuaTable> luaUpdate;privateAction<LuaTable> luaOnDestroy;//Update方法代理privateAction luaUpadteDe;privatevoidAwake(){object[] kRet = ST_LuaMannager.Instance.Dostring($"return require '{LuaFile}'.New()", LuaFile);if(null== kRet){
- Debug.LogError("Luafile need return local table");return;}
- luaTable = kRet[0]asLuaTable;//设置绑定的对象foreach(var injection in injections){
- luaTable.Set(injection.name, injection.value);}//设置luaCom
- luaTable.Set("luaCom",this);//设置gameObject
- luaTable.Set("gameObject", gameObject);//设置transform
- luaTable.Set("transform", transform);Action luaAwake = luaTable.Get<Action>("awake");//自动调用方法
- luaTable.Get("Start",out luaStart);
- luaTable.Get("Update",out luaUpdate);
- luaTable.Get("OnDestroy",out luaOnDestroy);//调用luaAwake方法if(luaAwake !=null){luaAwake();}}//脚本生效时注册UpdateprivatevoidOnEnable(){if(luaUpdate !=null){
- luaUpadteDe =()=>{luaUpdate(luaTable);};
- ST_LuaMannager.Instance.luaUpdates += luaUpadteDe;}}//脚本失效时注销UpdateprivatevoidOnDisable(){if(luaUpadteDe !=null){
- ST_LuaMannager.Instance.luaUpdates -= luaUpadteDe;}}voidStart(){//执行luaStartif(luaStart !=null){luaStart(luaTable);}}//对象销毁时privatevoidOnDestroy(){//调用luaOnDestroy方法if(luaOnDestroy !=null){luaOnDestroy(luaTable);}
- luaOnDestroy =null;
- luaUpdate =null;
- luaStart =null;
- injections =null;
- luaUpadteDe =null;}}[Serializable]publicclassInjection{publicstring name;publicGameObjectvalue;}
复制代码 测试
创建TestMono.lua文件- local TestMono =class()-- 自定义数据-- 构造函数function TestMono:Ctor(params)end-- 开始函数function TestMono:Start()endfunction TestMono:Update()
- self.transform:Rotate(CS.UnityEngine.Vector3(0,1,0));
- self.capsule.transform:Rotate(CS.UnityEngine.Vector3(1,0,0))endreturn TestMono
复制代码 在场景中创建一个Cube,和一个Capsule,并将ST_LuaBehaviours挂到Cube上,如图:
运行游戏,可以看到Cube,和Capsule旋转,那么测试通过。
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|