话不多说,先上代码
using System.Collections;
using System.Collections.Generic;
using System.IO;
using GameFramework;
using UnityEngine;
using XLua;
public class XLuaManager : MonoBehaviour
{
LuaEnv luaEnv;
public void OnInit()
{
luaEnv = new LuaEnv();
//增加一个自定义loader
luaEnv.AddLoader(CustomLoader);
StartGame();
}
public void StartGame()
{
if (luaEnv != null)
{
LoadScript("GameMain");
luaEnv.DoString("GameMain.Start()");
}
}
void LoadScript(string scriptName)
{
SafeDoString(string.Format("require('{0}')", scriptName));
}
public void SafeDoString(string scriptContent)
{
if (luaEnv != null)
{
try
{
luaEnv.DoString(scriptContent);
}
catch (System.Exception ex)
{
string msg = string.Format("xLua exception : {0}\n {1}", ex.Message, ex.StackTrace);
Debug.LogError(msg, null);
}
}
}
public byte[] CustomLoader(ref string filepath)
{
if (filepath == "emmy_core") return null; // EmmyLua调试Dll,走dll方式加载
var loadPath = filepath.Replace(".", "/") + ".lua";
var bytes = LoadBytes(loadPath);
if (bytes == null) return null; // 加载文件失败,不修改filepath,尝试其它加载器
//修改filepath 标记成功加载(相对路径用"/") 作为 chunkName 触发EmmyLua调试
filepath = loadPath;
return bytes;
}
public static byte[] LoadBytes(string loadPath)
{
// 读取时文件路径转为小写
// 因为:
// 1、Windows、Mac 默认不分大小写
// 2、Git 默认不分大小写
// 2、File 判定和读取也不区分大小写
loadPath = loadPath.ToLower();
var file = Path.Combine(LuaScriptsPath, loadPath);
Debug.Log($"load lua file path:{file}");
if (File.Exists(file))
return File.ReadAllBytes(file);
Debug.LogError($"Not Exist lua file: {file}");
return null;
}
public static string LuaScriptsPath => Path.Combine(System.Environment.CurrentDirectory, "Assets/LuaScript");
}
lua代码如下
local UIManager = require("GameFramework/UIManager")
GameMain = {}
local function Start()
print('<color=#fff000>Hello Xlua</color>')
UIManager.onInit()
UIManager.showUI("loginUI")
require("GameFramework/Define")
local uiRoot = GameObject.Find("uiRoot")
local myObj = GameObject("hehe")
print(uiRoot.name)
print(GameUtils.GetAppVersion(),GameUtils.GetAssetsVersion())
print(GameUtils.GetDeviceId())
print(DataManager.getData("userName"),DataManager.getData("userLevel"))
local myPlayer = ShowPlayer()
myPlayer:Init()
end
GameMain.Start = Start
return GameMain
--这个是Define.lua
GameObject = CS.UnityEngine.GameObject
Transform = CS.UnityEngine.GameObject.Transfrom
GameUtils = CS.GameUtils
DataManager = CS.GameFramework.DataManager
ShowPlayer = CS.ShowPlayer
当然直接访问c#也是可以,属于反射的方式,比较耗性能
反射访问除了性能不佳之外,在il2cpp下还有可能因为代码剪裁而导致无法访问,后者可以通过下面介绍的ReflectionUse标签来避免。所以需要XLua.LuaCallCSharp
一个C#类型加了这个配置,xLua会生成这个类型的适配代码(包括构造该类型实例,访问其成员属性、方法,静态属性、方法),否则将会尝试用性能较低的反射方式来访问。
简单配置如下,创建一个脚本,放在unity工程的Editor下,这样就会生成对应wrap文件
using System;
using System.Collections;
using System.Collections.Generic;
using GameFramework;
using UnityEngine;
using XLua;
public static class GenConfig
{
[CSObjectWrapEditor.GenPath]
static string common_path = "Assets/XLua/Gen/";
[LuaCallCSharp]
public static List<Type> mymodule_lua_call_cs_list = new List<Type>()
{
typeof(GameObject),
typeof(GameUtils),
typeof(DataManager),
typeof(ShowPlayer),
};
}
对于c#的Struct还是少用,尽量封装静态方法
主要优化 减少gc + 减少lua与C#的交互。
-
为什么会产生gc?
原因是boxing(装箱)和unboxing(拆箱)。Vector3(栈)转为object类型需要boxing(堆内存中),object转回Vector3需要unboxing,使用后释放该object引用,这个堆内存被gc检测到已经没引用,释放该堆内存,产生一个gc内存。 -
如何优化gc?
值拷贝
简单的解决办法,可以采用tolua已经写好的代码,或许有问题或者有优化空间,自行处理
最后还有点疑问,如何在lua创建Button类,直接创建一个Button,大致就是c#中写框架,lua中写业务逻辑,看了一些相关的帖子,可以参考xlua-framework,git可以找到,但是要自己写一套该如何下手呢,有知道的大神请指教一下,谢谢