Unity + XLua 简单框架搭建
Unity + XLua 简单框架结构Xlua环境搭建教程入口.
一.unity内创建lua脚本
usingSystem.Collections;usingSystem.Collections.Generic;usingSystem.IO;usingSystem.Text;usingSystem.Text.RegularExpressions;usingUnityEditor;usingUnityEditor.ProjectWindowCallback;usingUnityEngine;publicclassGenLua{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
endTests.lua
print(Add(TestValue,12))TestEnv.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_tablethenreturn lookup_tableendlocal new_table ={}
lookup_table= new_table
for key, value inpairs(object)do
new_table=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 })(原)setmetatable(obj,{__index =clone(_class)})return obj
endlocal vtbl ={}
_class= vtbl
setmetatable(class_type,{
__newindex =function(t, k, v)
vtbl= v
end})if super thensetmetatable(vtbl,{
__index =function(t, k)local ret = _class
vtbl= 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;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 = kRetasLuaTable;//设置绑定的对象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;}}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旋转,那么测试通过。
页:
[1]