Unity XLua学习笔记(一):创建脚本,完成准备工作

在进行XLua编程前,需要做好XLua的环境配置
Unity XLua环境配置

在Unity中创建Lua文件

新建一个Lua文件夹,创建一个txt文本文件
在这里插入图片描述
然后将它的后缀名改为.lua
在这里插入图片描述
回到编辑器双击该文件,就可用VSCode打开
在这里插入图片描述
在这里插入图片描述

首先,创建一个Unity脚本,挂载在Unity场景上

这个脚本用于使用Xlua调用Lua脚本

在这里插入图片描述
可以通过VSCode中的:文件----->打开文件夹,在弹出的文件选择窗口中选择工程文件的Aseets文件夹,就可在VSCode中查看Unity中Assets目录下的所有文件,这样创建lua文件直接在VSCode中创建就行,不需要再到文件目录中创建txt文件再改后缀名了
在这里插入图片描述
在这里插入图片描述
在我们的Main.cs脚本中输入如下代码

//初始化Lua解析器
LuaEnv env=new LuaEnv();
//env.DoString("要执行的lua代码")
env.DoString("print('hello world')");

注意需要引用XLua命名空间
在这里插入图片描述
回到Unity点击运行,控制台打印hello world
在这里插入图片描述

再创建一个主lua脚本作为lua脚本的入口

想要在Unity中运行Lua代码,需要有一个主lua脚本,在Unity通过Xlua调用这个脚本
右键,新建文件
在这里插入图片描述
注意后缀名,要加上.lua
在这里插入图片描述
通过require(“LuaTest”)调用我们的LuaTest脚本
在这里插入图片描述
在LuaTest中打印一句话,用来确认LuaTest脚本被调用
在这里插入图片描述
回到Unity中,现在运行是会报错的,XLua默认会去Resource文件夹中寻找我们的Lua脚本(而且后缀必须为txt或bytes等),将我们的LuaTest.lua文件和Main.lua文件加一个.txt的文件后缀名,即:
LuaTest.lua.txt
Main.lua.txt
在这里插入图片描述
把它们拖入Resources文件夹中
在这里插入图片描述
这时候点击运行
在这里插入图片描述
最后在Main.cs脚本中补充两行代码
Lua并不像C#那样能够自动进行垃圾回收,我们需要手动进行垃圾回收

//清除Lua中没有手动释放的对象 进行垃圾回收
//帧更新中定时执行 或者 切场景时执行
env.Tick();
//销毁Lua解析器
env.Dispose();

编写AB包管理器脚本

单例基类1

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 泛型基类,无需挂载在游戏对象上
/// </summary>
/// <typeparam name="T"></typeparam>
public class SingletonBase<T> where T:new()
{
    private static T instance;

    public static T GetInstance()
    {
        if (instance == null)
            instance = new T();
        return instance;
    }
}


单例基类2

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 用于需要继承MonoBehaviour的单例基类,无需挂载在游戏对象上
/// </summary>
public class SingletonAutoMono<T> : MonoBehaviour where T:MonoBehaviour
{
    private static T instance;

    public static T GetInstance()
    {
        if( instance == null )
        {
            GameObject obj = new GameObject();
            //设置对象的名w为脚本名
            obj.name = typeof(T).ToString();
            //防止切换场景被移除
            DontDestroyOnLoad(obj);
            //返回脚本对象
            instance = obj.AddComponent<T>();
        }
        return instance;
    }

}

AB包管理器脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

public class ABMgr : SingletonAutoMono<ABMgr>
{
    //主包
    private AssetBundle mainAB = null;

    //依赖包获取用的配置文件
    private AssetBundleManifest manifest = null;

    //字典 用字典来存储 加载过的AB包 防止重复加载报错
    private Dictionary<string, AssetBundle> abDic = new Dictionary<string, AssetBundle>();

    /// <summary>
    /// AB包存放路径 方便修改
    /// </summary>
    private string PathUrl
    {
        get
        {
            return Application.streamingAssetsPath + "/";
        }
    }
    /// <summary>
    /// 主包名 在打包前要注意命名
    /// 例如:StanderdedWindows要改为PC
    /// </summary>
    private string MainABName
    {
        get
        {
#if UNITY_IOS
            return "IOS";
#elif UNITY_ANDROID
            return "Android";
#else
            return "PC";
#endif
        }
    }
    /// <summary>
    /// 加载AB包
    /// </summary>
    /// <param name="abName"></param>
    public void LoadAB( string abName )
    {
        //加载AB包
        if (mainAB == null)
        {
            mainAB = AssetBundle.LoadFromFile(PathUrl + MainABName);
            manifest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
        }
        //我们获取依赖包相关信息
        AssetBundle ab = null;
        string[] strs = manifest.GetAllDependencies(abName);
        for (int i = 0; i < strs.Length; i++)
        {
            //判断包是否加载过
            if (!abDic.ContainsKey(strs[i]))
            {
                ab = AssetBundle.LoadFromFile(PathUrl + strs[i]);
                abDic.Add(strs[i], ab);
            }
        }
        //加载资源来源包
        //判断字典中是否包含 如果没有加载过 再加载
        if (!abDic.ContainsKey(abName))
        {
            ab = AssetBundle.LoadFromFile(PathUrl + abName);
            abDic.Add(abName, ab);
        }
    }
    //同步加载 不指定类型 默认直接实例化
    public Object LoadRes(string abName, string resName,bool isInstantiate=true)
    {
        //加载AB包
        LoadAB(abName);
        //判断资源是不是GameObject
        //如果是 直接实例化返回给外部
        Object obj = abDic[abName].LoadAsset(resName);
        if(isInstantiate)
        {
            if (obj is GameObject)
            return Instantiate(obj);
        else
            return obj;
        }
        else
        {
            return obj;
        }
        
    }
    //同步加载 根据泛型指定类型 默认直接实例化
    public T LoadRes<T>(string abName, string resName,bool isInstantiate=true) where T:Object
    {
        //加载AB包
        LoadAB(abName);
        //为了外面方便 在加载资源时 判断一下 资源是不是GameObject
        //如果是 直接实例化了 再返回给外部
        T obj = abDic[abName].LoadAsset<T>(resName);
        if(isInstantiate)
        {
            if (obj is GameObject)
                return Instantiate(obj);
            else
                return obj;
        }
        else
        {
            return obj;     
        }
        
    }
    //所有包的卸载
    public void ClearAB()
    {
        AssetBundle.UnloadAllAssetBundles(false);
        abDic.Clear();
        mainAB = null;
        manifest = null;
    }
}

Lua脚本文件加载重定向

接下来需要进行Lua脚本文件加载重定向,我们既然要进行热更新,肯定不能只从Resources文件夹内加载Lua脚本
env.AddLoader(重定向方法)可以通过传入一个方法来重定向Lua脚本的加载地址,比如可以设置为streamingAssets文件夹下,或者沙盒目录
顺序为:优先执行我们自定义的路径,最后再去默认路径中找(也就是Resources文件夹下找)
传入的方法需要符合:
在这里插入图片描述

//文件加载重定向方法
env.AddLoader(CustomLoader);

用于编辑器加载的重定向方法,加载编辑器下Lua文件夹内的Lua脚本

/// <summary>
    /// 编辑器Lua文件加载重定向
    /// </summary>
    /// <param name="filePath">传入的是require的lua脚本名</param>
    /// <returns></returns>
    private byte[] CustomLoader_Editor(ref string filePath)
    {
        //设置Lua文件所在路径,设置为Lua文件夹下的Lua脚本
        string path=Application.dataPath+"/Lua/"+filePath+".lua";
        if(File.Exists(path))
        {
            //文件存在,返回byte[]
            return File.ReadAllBytes(path);
        }
        else
        {
            //文件不存在,打印文件路径
            Debug.LogError("编辑器Lua文件重定向失败,文件名为:"+filePath);
        }
        return null;
    }

用于StreamingAssets文件夹下的AB包中的Lua脚本加载的重定向方法

 	/// <summary>
    /// StreamingAssets文件加载重定向,打AB包后
    /// </summary>
    /// <param name="filePath"></param>
    /// <returns></returns>
    private byte[] CustomLoader_StreamingAssets(ref string filePath)
    {
        TextAsset lua = ABMgr.GetInstance().LoadRes<TextAsset>("lua", filePath + ".lua");
        if (lua != null)
            return lua.bytes;
        else
            Debug.Log("StreamingAssets文件夹AB包Lua文件重定向失败,文件名为:" + filePath);
        return null;
    }

在Main.cs中添加重定向函数

        //文件加载重定向
        env.AddLoader(CustomLoader_Editor);
        env.AddLoader(CustomLoader_StreamingAssets);

Main.cs全部代码:

using System;
using System.Net;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using XLua;

public class Main : MonoBehaviour
{

    void Start()
    {
        //初始化Lua解析器
        LuaEnv env=new LuaEnv();
        

        //文件加载重定向
        //env.AddLoader(CustomLoader_Editor);
        env.AddLoader(CustomLoader_StreamingAssets);

        //env.DoString("要执行的lua代码")
        env.DoString("require('Main')");

        //清除Lua中没有手动释放的对象 进行垃圾回收
        //帧更新中定时执行 或者 切场景时执行
        env.Tick();
        //销毁Lua解析器
        env.Dispose();

    }
    /// <summary>
    /// 编辑器Lua文件加载重定向
    /// </summary>
    /// <param name="filePath">传入的是require的lua脚本名</param>
    /// <returns></returns>
    private byte[] CustomLoader_Editor(ref string filePath)
    {
        //设置Lua文件所在路径,设置为Lua文件夹下的Lua脚本
        string path=Application.dataPath+"/Lua/"+filePath+".lua";

        if(File.Exists(path))
        {
            Debug.Log(filePath+"文件存在");
            //文件存在,返回byte[]
            return File.ReadAllBytes(path);
        }
        else
        {
            //文件不存在,打印文件路径
            Debug.LogError("编辑器Lua文件重定向失败,文件名为:"+filePath);
        }
        return null;
    }
    /// <summary>
    /// StreamingAssets文件加载重定向,打AB包后
    /// </summary>
    /// <param name="filePath"></param>
    /// <returns></returns>
    private byte[] CustomLoader_StreamingAssets(ref string filePath)
    {
        TextAsset lua = ABMgr.GetInstance().LoadRes<TextAsset>("lua", filePath + ".lua");
        if (lua != null)
            return lua.bytes;
        else
            Debug.Log("StreamingAssets文件夹AB包Lua文件重定向失败,文件名为:" + filePath);
        return null;
    }
}


编写Lua脚本打包工具

因为AB包并不能直接打包lua文件,因此所有的Lua脚本必须添加.txt文件才能进行打包
一旦后面我们的Lua脚本多了,一个一个改文件后缀并设置AB包包名很麻烦,因此写一个编辑器工具

using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

public class LuaAddTxtSuffixEditor : Editor
{
    [MenuItem("XLua/生成txt后缀的Lua文本")]
    public static void CopyLuaToTxt()
    {
        //设置要拷贝的所有Lua文件的路经
        string path=Application.dataPath+"/Lua/";

        //判断路径是否存在
        if(!Directory.Exists(path))
            return;

        //获取路径下后缀为.lua的文件
        string[] strs= Directory.GetFiles(path,"*.lua");
        
        //把Lua文件拷贝到一个新的文件夹中
        //声明一个新路径
        string newPath=Application.dataPath+"/LuaToAB/";

        //判断新路径文件夹 是否存在,不存在则创建路径
        if(!Directory.Exists(newPath))
            Directory.CreateDirectory(newPath);
        else
        {
            //得到该路径中 所有后缀.txt的文件 
            string[] oldFileStrs=Directory.GetFiles(newPath,"*.txt");
            for(int i=0;i<oldFileStrs.Length;i++)
            {
                //删除找到的.txt文件
                File.Delete(oldFileStrs[i]);
            }
        }
        
        List<string> newFileNames=new List<string>();
        string fileName;
        for(int i=0;i<strs.Length;i++)
        {
            //得到新的文件路径 用于拷贝
            fileName=newPath+strs[i].Substring(strs[i].LastIndexOf("/")+1)+".txt";
            newFileNames.Add(fileName);
            File.Copy(strs[i],fileName);
        }
        AssetDatabase.Refresh();
        //刷新过后再来该指定包
        for(int i=0;i<newFileNames.Count;i++)
        {
            //该API传入的路径 必须是 相对Assets文件夹的 Assets/.../....
            AssetImporter importer=AssetImporter.GetAtPath(newFileNames[i].Substring(newFileNames[i].IndexOf("Assets")));
            if(importer!=null)
                importer.assetBundleName="lua";
        }
        Debug.Log("生成完毕");
    }
}


将该脚本放在Editor文件下
在这里插入图片描述
找到XLua菜单下我们新添加的选项,点击它生成相应的AB包文件(生成文件在LuaToAB文件夹下)
在这里插入图片描述
先不进行打包,测试编辑器中的重定向方法是否被调用,将加载StreamingAssets文件夹下的重定向方法注释掉
在这里插入图片描述

Resources文件夹下现在没有文件
在这里插入图片描述
运行,为了清楚显示我在返回文件前加了一行打印信息
在这里插入图片描述
在这里插入图片描述
之后进行AB包打包
在这里插入图片描述
直接打包会报错,需要先执行XLua----->Clear generate Code,之后再进行打包就没问题了
在这里插入图片描述
在这里插入图片描述
再将编辑器的重定向方法注释
在这里插入图片描述
运行,执行了LuaTest脚本中的内容
在这里插入图片描述
以上,准备工作完成

最后,优化一下代码,编写XLua管理器

XLua脚本管理器

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using XLua;
public class XLuaMgr :SingletonBase<XLuaMgr>
{
    //lua解析器
    private LuaEnv luaEnv;

    /// <summary>
    /// 获取Lua中的_G
    /// </summary>
    /// <value></value>
    public LuaTable Global
    {
        get
        {
            return luaEnv.Global;
        }
    }
    public void Init()
    {
        //已经初始化了 别初始化 直接返回
        if (luaEnv != null)
            return;
        //初始化
        luaEnv = new LuaEnv();
        //加载Lua脚本,重定向
        luaEnv.AddLoader(CustomLoader_Editor);
        luaEnv.AddLoader(CustomLoader_StreamingAssets);
    }
    /// <summary>
    /// 编辑器Lua文件加载重定向
    /// </summary>
    /// <param name="filePath">传入的是require的lua脚本名</param>
    /// <returns></returns>
    private byte[] CustomLoader_Editor(ref string filePath)
    {
        //设置Lua文件所在路径,设置为Lua文件夹下的Lua脚本
        string path=Application.dataPath+"/Lua/"+filePath+".lua";

        if(File.Exists(path))
        {
            Debug.Log(filePath+"文件存在");
            //文件存在,返回byte[]
            return File.ReadAllBytes(path);
        }
        else
        {
            //文件不存在,打印文件路径
            Debug.LogError("编辑器Lua文件重定向失败,文件名为:"+filePath);
        }
        return null;
    }
    /// <summary>
    /// StreamingAssets文件加载重定向,打AB包后
    /// </summary>
    /// <param name="filePath"></param>
    /// <returns></returns>
    private byte[] CustomLoader_StreamingAssets(ref string filePath)
    {
        TextAsset lua = ABMgr.GetInstance().LoadRes<TextAsset>("lua", filePath + ".lua");
        if (lua != null)
            return lua.bytes;
        else
            Debug.Log("StreamingAssets文件夹AB包Lua文件重定向失败,文件名为:" + filePath);
        return null;
    }
    /// <summary>
    /// 传入文件名 执行lua脚本
    /// </summary>
    /// <param name="fileName"></param>
    public void DoLuaFile(string fileName)
    {
        string str = string.Format("require('{0}')", fileName);
        DoString(str);
    }
    /// <summary>
    /// 执行lua脚本
    /// </summary>
    /// <param name="str"></param>
     public void DoString(string str)
    {
        if(luaEnv==null)
        {
            Debug.Log("解析器未初始化");
            return;
        }
        luaEnv.DoString(str);
    }
    /// <summary>
    /// 垃圾清除
    /// </summary>
    public void Tick()
    {
        luaEnv.Tick();
    }
    /// <summary>
    /// 销毁解析器
    /// </summary>
    public void  Dispose()
    {
        luaEnv.Dispose();
        luaEnv = null;
    }
}

使用方法

using System;
using System.Net;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using XLua;

public class Main : MonoBehaviour
{

    void Start()
    {
        XLuaMgr.GetInstance().Init();
        XLuaMgr.GetInstance().DoLuaFile("Main");

    }
   
}

在这里插入图片描述
下一篇文章
Unity XLua学习笔记(二):C#调用Lua

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值