lua_0">1. 导入xlua
首先导入xlua,这个不用多说
2. 编写C#和Lua交互脚本
基础版本,即xlua自带的版本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
using System;
using System.IO;
[Serializable]
public class Injection
{
public string name;
public GameObject value;
}
/// <summary>
/// XLua的原生版本
/// </summary>
public class LuaBehaviour : MonoBehaviour
{
public TextAsset luaScript;
public Injection[] injections;
/// <summary>
/// 虚拟机唯一
/// </summary>
internal static LuaEnv luaEnv = new LuaEnv();
/// <summary>
/// 上一次的GC时间
/// </summary>
internal static float lastGCTime = 0;
/// <summary>
/// GC间隔
/// </summary>
internal const float GCInterval = 1f;
private Action luaStart;
private Action luaUpdate;
private Action luaOnDestroy;
private LuaTable scriptScopeTable;
private void Awake()
{
SetPackagePath();
scriptScopeTable = luaEnv.NewTable();
//给scriptScopeTable设置__index元表,使其能够访问全局
using (LuaTable meta = luaEnv.NewTable())
{
meta.Set("__index", luaEnv.Global);
scriptScopeTable.SetMetaTable(meta);
}
scriptScopeTable.Set("self", this);
foreach (var injection in injections)
{
scriptScopeTable.Set(injection.name, injection.value);
}
//执行脚本
luaEnv.DoString(luaScript.text, luaScript.name, scriptScopeTable);
//获得生命周期绑定,这里直接使用scriptScopeTable,代表是使用这个脚本的全局去设置的
Action luaAwake = scriptScopeTable.Get<Action>("Awake");
scriptScopeTable.Get("Start", out luaStart);
scriptScopeTable.Get("Update", out luaUpdate);
scriptScopeTable.Get("OnDestroy", out luaOnDestroy);
if (luaAwake != null)
{
luaAwake();
}
}
private void Start()
{
if (luaStart != null)
{
luaStart();
}
}
private void Update()
{
if (luaUpdate != null)
{
luaUpdate();
}
if (Time.time - lastGCTime > GCInterval)
{
luaEnv.Tick();
lastGCTime = Time.time;
}
}
private void OnDestroy()
{
if (luaOnDestroy != null)
{
luaOnDestroy();
}
scriptScopeTable.Dispose();
luaStart = null;
luaUpdate = null;
luaOnDestroy = null;
injections = null;
}
/// <summary>
/// 设置xlua的加载路径
/// </summary>
private void SetPackagePath()
{
//在Unity项目的“Assets”文件夹(或指定的Application.dataPath路径)及其所有子目录中,查找名为“LuaScripts”的目录,并返回一个包含这些目录路径的字符串数组
foreach (string dir in Directory.GetDirectories(Application.dataPath,"LuaScripts", SearchOption.AllDirectories))
{
luaEnv.AddLoader(new FileLoader(dir, ".lua"));
luaEnv.AddLoader(new FileLoader(dir, ".lua.txt"));
}
}
}
Loxodon的版本
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
using System.IO;
using Object = UnityEngine.Object;
/// <summary>
/// Loxodon的版本
/// </summary>
[LuaCallCSharp]
public class LoxodonLuaBehaviour : MonoBehaviour
{
public ScriptReference script;
public VariableArray variables;
protected LuaTable scriptEnv;
protected LuaTable metatable;
protected Action<MonoBehaviour> onAwake;
protected Action<MonoBehaviour> onEnable;
protected Action<MonoBehaviour> onDisable;
protected Action<MonoBehaviour> onUpdate;
protected Action<MonoBehaviour> onDestroy;
protected Action<MonoBehaviour> onStart;
public LuaTable GetMetatable()
{
return metatable;
}
protected virtual void Initialize()
{
var luaEnv = LuaEnvironment.LuaEnv;
scriptEnv = luaEnv.NewTable();
LuaTable meta = luaEnv.NewTable();
meta.Set("__index", luaEnv.Global);
scriptEnv.SetMetaTable(meta);
meta.Dispose();
scriptEnv.Set("target", this);
SetPackagePath(luaEnv);
string scriptText = (script.Type == ScriptReferenceType.TextAsset)
? script.Text.text
: string.Format(
$"require(\"System\");local cls = require(\"{script.FileName}\");return extends(target,cls);");
object[] result = luaEnv.DoString(scriptText, string.Format("{0}({1})", "LuaBehaviour", this.name), scriptEnv);
if (result.Length != 1 || !(result[0] is LuaTable))
{
throw new Exception("");
}
metatable = (LuaTable)result[0]; //这里使用Lua脚本的返回值去设置,即脚本的返回值去绑定生命周期
if (variables != null && variables.Variables != null)
{
foreach (var variable in variables.Variables)
{
var name = variable.Name.Trim();
if (string.IsNullOrEmpty(name))
{
continue;
}
metatable.Set(name, variable.GetValue());
}
}
onAwake = metatable.Get<Action<MonoBehaviour>>("Awake");
onEnable = metatable.Get<Action<MonoBehaviour>>("Enable");
onDisable = metatable.Get<Action<MonoBehaviour>>("Disable");
onStart = metatable.Get<Action<MonoBehaviour>>("Start");
onUpdate = metatable.Get<Action<MonoBehaviour>>("Update");
onDestroy = metatable.Get<Action<MonoBehaviour>>("Destroy");
}
protected virtual void Awake()
{
this.Initialize();
if (this.onAwake != null)
{
this.onAwake(this);
}
}
protected virtual void OnEnable()
{
if (this.onEnable != null)
{
this.onEnable(this);
}
}
protected virtual void OnDisable()
{
if (this.onDisable != null)
{
this.onDisable(this);
}
}
protected virtual void Start()
{
if (onStart != null)
{
onStart(this);
}
}
protected virtual void Update()
{
if (onUpdate != null)
{
onUpdate(this);
}
}
protected virtual void OnDestroy()
{
if (this.onDestroy != null)
{
this.onDestroy(this);
}
onDestroy = null;
onUpdate = null;
onStart = null;
onEnable = null;
onDisable = null;
onAwake = null;
if (metatable != null)
{
metatable.Dispose();
metatable = null;
}
if (scriptEnv != null)
{
scriptEnv.Dispose();
scriptEnv = null;
}
}
/// <summary>
/// 修改lua的loader
/// </summary>
/// <param name="luaEnv"></param>
private void SetPackagePath(LuaEnv luaEnv)
{
//在Unity项目的“Assets”文件夹(或指定的Application.dataPath路径)及其所有子目录中,查找名为“LuaScripts”的目录,并返回一个包含这些目录路径的字符串数组
foreach (string dir in Directory.GetDirectories(Application.dataPath,"LuaScripts", SearchOption.AllDirectories))
{
luaEnv.AddLoader(new FileLoader(dir, ".lua"));
luaEnv.AddLoader(new FileLoader(dir, ".lua.txt"));
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
public class LuaEnvironment
{
private static float interval = 2;
private static WaitForSecondsRealtime wait;
private static LuaEnv luaEnv;
//private static IAsyncResult result;
public static float Interval
{
get => interval;
set
{
if (interval <= 0)
{
return;
}
interval = value;
wait = new WaitForSecondsRealtime(interval);
}
}
public static LuaEnv LuaEnv
{
get
{
if (luaEnv == null)
{
luaEnv = new LuaEnv();
// if (result != null)
// result.Cancel();
wait = new WaitForSecondsRealtime(interval);
//result = Executors.RunOnCoroutine(DoTick());
luaEnv.Tick();
}
return luaEnv;
}
}
public static void Dispose()
{
// if (result != null)
// {
// result.Cancel();
// result = null;
// }
if (luaEnv != null)
{
luaEnv.Dispose();
luaEnv = null;
}
wait = null;
}
private static IEnumerator DoTick()
{
while (true)
{
yield return wait;
try
{
luaEnv.Tick();
}
catch (Exception e)
{
Debug.LogError(e);
}
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using Object = UnityEngine.Object;
public enum ScriptReferenceType
{
TextAsset,
FileName
}
[Serializable]
public class ScriptReference : ISerializationCallbackReceiver
{
#if UNITY_EDITOR
[SerializeField]
private Object cachedAsset;
#endif
[SerializeField]
protected TextAsset text;
[SerializeField]
protected string fileName;
[SerializeField]
protected ScriptReferenceType type = ScriptReferenceType.TextAsset;
public virtual ScriptReferenceType Type => type;
public virtual TextAsset Text => text;
public virtual string FileName => fileName;
public void OnBeforeSerialize()
{
Clear();
}
public void OnAfterDeserialize()
{
Clear();
}
protected virtual void Clear()
{
#if !UNITY_EDITOR
switch (type)
{
case ScriptReferenceType.TextAsset:
this.fileName = null;
break;
case ScriptReferenceType.FileName:
this.text = null;
break;
}
#endif
}
}
具体区别可以看两种不同的LuaBehaviour生命周期绑定
然后注意这里的lua文件读取路径设置
具体可以看xlua中自定义lua文件加载的一种方式
3.自定义属性面板
4. Lua脚本部分
因为提前设置了Lua文件的读取路径,都在LuaScripts文件夹下
运行
Lua脚本执行了对应的逻辑,将text的值变为了“你好”,同时打印了协程的输出
注意使用前让xlua生成代码
项目链接