找回密码
 立即注册
查看: 282|回复: 0

Unity + XLua 简单框架搭建

[复制链接]
发表于 2023-4-10 13:29 | 显示全部楼层 |阅读模式
Unity + XLua 简单框架结构

Xlua环境搭建教程入口.
一.unity内创建lua脚本
  1. 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(){
  2.         ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0,
  3.         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)){
  4.             path = AssetDatabase.GetAssetPath(obj);if(!string.IsNullOrEmpty(path)&& File.Exists(path)){
  5.                 path = Path.GetDirectoryName(path);break;}}return path;}}classMyDoCreateScriptAsset:EndNameEditAction{publicoverridevoidAction(int instanceId,string pathName,string resourceFile){UnityEngine.Object o =CreateScriptAssetFromTemplate(pathName, resourceFile);
  6.         ProjectWindowUtil.ShowCreatedAsset(o);}internalstaticUnityEngine.ObjectCreateScriptAssetFromTemplate(string pathName,string resourceFile){string fullPath = Path.GetFullPath(pathName);StreamReader streamReader =newStreamReader(resourceFile);string text = streamReader.ReadToEnd();
  7.         streamReader.Close();string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(pathName);
  8.         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);
  9.         streamWriter.Write(text);
  10.         streamWriter.Close();
  11.         AssetDatabase.ImportAsset(pathName);return AssetDatabase.LoadAssetAtPath(pathName,typeof(UnityEngine.Object));}}
复制代码
代码转载自雨松MoMo
将此段代码放入unity的Editor目录下,然后在相应目录下创建NewLua.txt模板,即可像创建C#脚本那样创建lua脚本
NewLua.txt 模板
  1. 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脚本。代码如下
  1. publicclassST_LuaMannager:MonoBehaviour{privatestaticreadonlyobject padlock =newobject();privatestaticST_LuaMannager instance;//统一管理UpdatepubliceventAction luaUpdates;//单例类publicstaticST_LuaMannager Instance
  2.     {get{if(instance ==null){lock(padlock){if(instance ==null){GameObject go =newGameObject("LuaManager");DontDestroyOnLoad(go);
  3.                         instance = go.AddComponent<ST_LuaMannager>();}}}return instance;}}LuaEnv luaEnv;float lastGcTime =0;//luaGC回收时间见隔constfloat GCInterval =1;//全局唯一lua环境publicLuaEnv MyLuaEnv
  4.     {get{if(luaEnv ==null){
  5.                 luaEnv =newLuaEnv();
  6.                 luaEnv.AddLoader(LuaLoader);//加载lua全局变量
  7.                 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);
  8.         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){
  9.             MyLuaEnv.Tick();
  10.             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
  1. TestValue =2functionAdd(a,b)return a + b
  2. end
复制代码
Tests.lua
  1. print(Add(TestValue,12))
复制代码
TestEnv.cs
  1. publicclassTestEnv:MonoBehaviour{// Start is called before the first frame updatevoidStart(){
  2.         ST_LuaMannager.Instance.Dostring("require 'Tests'");}}
复制代码
创建空节点,运行Unity,结果如下



三.Lua面向对象

让Lua脚本具有面向对象特性可以使我们编程更加方便,在ST_LuaEnv里面添加面向对象方法代码如下
  1. functionclone(object)local lookup_table ={}localfunctioncopyObj(object)iftype(object)~="table"thenreturn object
  2.         elseif lookup_table[object]thenreturn lookup_table[object]endlocal new_table ={}
  3.         lookup_table[object]= new_table
  4.         for key, value inpairs(object)do
  5.             new_table[copyObj(key)]=copyObj(value)endreturnsetmetatable(new_table,getmetatable(object))endreturncopyObj(object)endlocal _class ={}--[[
  6.     @desc: class
  7.     author:{}
  8.     time:2022-01-24 17:47:45
  9.     --@super: 父类
  10.     @return:返回一个类
  11. ]]functionclass(super)local class_type ={}
  12.     class_type.Ctor =false
  13.     class_type.super = super
  14.     class_type.New =function(...)local obj ={}dolocal create
  15.             create =function(c,...)if c.super thencreate(c.super,...)endif c.Ctor then
  16.                     c.Ctor(obj,...)endendcreate(class_type,...)end--setmetatable(obj,{ __index=_class[class_type] })(原)setmetatable(obj,{__index =clone(_class[class_type])})return obj
  17.     endlocal vtbl ={}
  18.     _class[class_type]= vtbl
  19.     setmetatable(class_type,{
  20.         __newindex =function(t, k, v)
  21.             vtbl[k]= v
  22.         end})if super thensetmetatable(vtbl,{
  23.             __index =function(t, k)local ret = _class[super][k]
  24.                 vtbl[k]= ret
  25.                 return ret
  26.             end})endreturn class_type
  27. end
复制代码
这里的面向对象方法引用自云风的个人空间 并对代码做了一定的修改,满足我们的要求,测试代码如下
  1. local TestClass =class()-- 自定义数据
  2. TestClass.ta ={x =1}local a1 = TestClass.New();local s = a1.ta;print(a1.ta.x)
  3. s.x =55local a2 = TestClass.New();print(a2.ta.x)
复制代码
原代码输出如下(可以看到,修改a1实列的ta.x值后基类的ta.x值也一并修改了)


修改后



四.GameObject绑定lua脚本

创建ST_LuaBehaviours.cs 代码如下:
  1. 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){
  2.             Debug.LogError("Luafile need return local table");return;}
  3.         luaTable = kRet[0]asLuaTable;//设置绑定的对象foreach(var injection in injections){
  4.             luaTable.Set(injection.name, injection.value);}//设置luaCom
  5.         luaTable.Set("luaCom",this);//设置gameObject
  6.         luaTable.Set("gameObject", gameObject);//设置transform
  7.         luaTable.Set("transform", transform);Action luaAwake = luaTable.Get<Action>("awake");//自动调用方法
  8.         luaTable.Get("Start",out luaStart);
  9.         luaTable.Get("Update",out luaUpdate);
  10.         luaTable.Get("OnDestroy",out luaOnDestroy);//调用luaAwake方法if(luaAwake !=null){luaAwake();}}//脚本生效时注册UpdateprivatevoidOnEnable(){if(luaUpdate !=null){
  11.             luaUpadteDe =()=>{luaUpdate(luaTable);};
  12.             ST_LuaMannager.Instance.luaUpdates += luaUpadteDe;}}//脚本失效时注销UpdateprivatevoidOnDisable(){if(luaUpadteDe !=null){
  13.             ST_LuaMannager.Instance.luaUpdates -= luaUpadteDe;}}voidStart(){//执行luaStartif(luaStart !=null){luaStart(luaTable);}}//对象销毁时privatevoidOnDestroy(){//调用luaOnDestroy方法if(luaOnDestroy !=null){luaOnDestroy(luaTable);}
  14.         luaOnDestroy =null;
  15.         luaUpdate =null;
  16.         luaStart =null;
  17.         injections =null;
  18.         luaUpadteDe =null;}}[Serializable]publicclassInjection{publicstring name;publicGameObjectvalue;}
复制代码
测试
创建TestMono.lua文件
  1. local TestMono =class()-- 自定义数据-- 构造函数function TestMono:Ctor(params)end-- 开始函数function TestMono:Start()endfunction TestMono:Update()
  2.     self.transform:Rotate(CS.UnityEngine.Vector3(0,1,0));
  3.     self.capsule.transform:Rotate(CS.UnityEngine.Vector3(1,0,0))endreturn TestMono
复制代码
在场景中创建一个Cube,和一个Capsule,并将ST_LuaBehaviours挂到Cube上,如图:



运行游戏,可以看到Cube,和Capsule旋转,那么测试通过。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-23 08:10 , Processed in 0.091155 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表