一、概述

NLua 是一个用于 .NET 平台的 Lua 脚本绑定库。它允许在 C# 代码中嵌入 Lua 脚本,并允许两者之间进行交互。NLua 的主要特点包括:

轻量级:NLua 是一个轻量级的库,易于集成到现有的 .NET 项目中。动态类型:Lua 是动态类型的语言,这意味着变量的类型可以在运行时改变。灵活的绑定:NLua 提供了灵活的绑定机制,使得 C# 和 Lua 之间的数据交互变得简单。丰富的 API:NLua 提供了丰富的 API,以便在 Lua 脚本中调用 .NET 的类和方法。调试支持:NLua 支持调试功能,方便开发者在 Lua 脚本中设置断点、单步执行等操作。社区支持:NLua 有一个活跃的社区,为开发者提供了一个交流和寻求帮助的平台。

使用 NLua,你可以在 .NET 应用中轻松地嵌入 Lua 脚本,从而实现动态逻辑、配置管理、插件系统等功能。通过 NLua,你可以利用 Lua 的灵活性和易用性,同时保持 .NET 的强大功能和性能。

NLua 支持 UWP、Windows、Linux、Mac、iOS、Android 平台。

NLua 源码和示例 Github 地址

GitHub - NLua/NLua: Bridge between Lua and the .NET.

二、创建项目

创建一个 .NET Framework  Winform 项目,这里我用的版本是 4.8.1,取名叫 NLuaDemo,在 NuGet 中安装 NLua 包。

winform 界面设计如下:

为了先看看 NLua 到底有没有效果,先做一个小案例,让你先熟悉一下 NLua 框架,在后面的案例中,会有完整的热更新方式展示。

需求:用 Lua 脚本来改变 Winform 界面中的抽奖人数,数量随意。

1.添加一个类 PublicData ,这个类用来保存公共数据(在第三节的案例中,这个类将不再使用)

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

public class PublicData

{

public static NLuaDemo.Form1 Form1s { get; set; }

}

我将 From1 保存在这里,主要是为了方便后面 Lua 调用。

2.将 Form1.Designer.cs 中的控件设置为 public,以便让 Lua 能直接调用 winform 控件。

3.将 Program 类改为如下(适用当前的 demo,在第三节的案例中,不再使用这种写法)

using System;

using System.Collections.Generic;

using System.Linq;

using System.Threading.Tasks;

using System.Windows.Forms;

namespace NLuaDemo

{

internal static class Program

{

///

/// 应用程序的主入口点。

///

[STAThread]

static void Main()

{

Application.EnableVisualStyles();

Application.SetCompatibleTextRenderingDefault(false);

PublicData.Form1s = new Form1();

Application.Run(PublicData.Form1s);

}

}

}

4.Form1 代码如下(第三节案例中,代码会不一样)

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.IO;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows.Forms;

using NLua;

namespace NLuaDemo

{

public partial class Form1 : Form

{

public Form1()

{

InitializeComponent();

}

private Lua Luas = new Lua();

//lua 脚本的地址

private string LuaPath;

private void Form1_Load(object sender, EventArgs e)

{

Luas.State.Encoding = Encoding.UTF8;

LuaPath = $"{Application.StartupPath}\\main.lua";

LoadLua();

}

private void Form1_FormClosing(object sender, FormClosingEventArgs e)

{

Luas.Close();

}

//热重载

private void Button_HotUpdate_Click(object sender, EventArgs e)

{

Luas.DoString("update()");

}

private void LoadLua()

{

if (File.Exists(LuaPath))

{

Luas.LoadCLRPackage();

Luas.DoFile(LuaPath);

Luas["form1s"] = PublicData.Form1s;

}

}

}

}

5.在项目的 Debug 目录中,新建一个 main.lua 文件,加入下面代码

form1s = {};

function update()

form1s.Label_RaffleNumber.Text = "抽奖人数:100" ;

end

完成了上面的工作,现在可以开始测试了

可以看到,Lua 脚本确实改变了 winform 界面的数据。

这里为什么不把逻辑直接写在 main.lua 中呢?

form1s = {};

form1s.Label_RaffleNumber.Text = "抽奖人数:100" ;

function update()

form1s.Label_RaffleNumber.Text = "抽奖人数:100" ;

end

因为运行后就会报错:

由于 Lua 脚本在运行后,会执行所有的代码,但是我们定义的 Lua 全局变量此时还没有赋值,直接运行当然报错了,于是我将热更新内容写入到 lua 脚本中的 update 方法中,等 C# 这边初始化完成后,调用 update 方法就不会有问题了。

另外还有一种方法,使用 LoadFile 方法,我试了一下,没有效果,可能是我用法不对

LuaFunction luaFunction = Luas.LoadFile("C:\\test.lua");

有兴趣的朋友可以去试试,有好的建议欢迎留言评论。

三、实现 Lua 热更新

在上面的案例中,我们是把 Form1 赋值给了 lua 脚本中的 form1s 这个变量(也可以叫表单),其实还可以这么写:

private void LoadLua()

{

if (File.Exists(LuaPath))

{

Luas.LoadCLRPackage();

Luas.DoFile(LuaPath);

Luas["this"] = this;

}

}

但是这种用法在 Lua 脚本用会有错误,在 Visual Studio Code 中搭建好 Lua 开发环境,就会看到提示:未定义的全局变量 “this”

这个不用管它,lua 脚本只要在 C# 项目中运行不报错就行了。

这里的写法改变后,上一个 demo 中代码也要改改了。

1.Program 类恢复默认的写法:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Threading.Tasks;

using System.Windows.Forms;

namespace NLuaDemo

{

internal static class Program

{

///

/// 应用程序的主入口点。

///

[STAThread]

static void Main()

{

Application.EnableVisualStyles();

Application.SetCompatibleTextRenderingDefault(false);

//PublicData.Form1s = new Form1();

//Application.Run(PublicData.Form1s);

Application.Run(new Form1());

}

}

}

2.PublicData 类可以删掉,或者注释所有的代码,现在用不上了。

另一个,Lua 调用 C# 方法,要用英文的冒号去调用方法,而不是像 C# 一样用点去调用,这个在 Unity3d 中 XLua 等热更新框架是同样的用法,具体用法可以参考下面 main.lua 代码。

--import("System")

--import('System.Windows.Forms')

--import("System.Threading");

--form1s = {};

--奖品

prize = {"手机", "电脑", "耳机", "鼠标", "键盘", "充电宝"}

--抽奖人

participant = {"张三", "李四", "老王", "狗蛋", "铁剩"}

--热重载

function update()

this:Print("抽奖人 长度是:" .. #participant)

this.Label_RaffleNumber.Text = "抽奖人数:" .. #participant

this.Label_PrizesNum.Text = "奖品数:" .. #prize

--奖品下拉框

this.ComboBox_Prize.Items:Clear()

for i,item in ipairs(prize) do

this.ComboBox_Prize.Items:Add(item)

end

this.ComboBox_Prize.SelectedIndex = 0

--抽奖人下拉框

this.ComboBox_LotteryGiver.Items:Clear();

for i,item in ipairs(participant) do

this.ComboBox_LotteryGiver.Items:Add(item);

end

this.ComboBox_LotteryGiver.SelectedIndex = 0

end

--抽奖按钮

function raffle()

--随机奖品

local prizeIndex = math.random(1, #prize)

local prize = prize[prizeIndex]

--随机抽奖人

local participantIndex = math.random(1, #participant)

local participant = participant[participantIndex]

local content = "抽奖人:"..participant..",获得奖品:"..prize

this:Print(content)

end

注意上面 lua 脚本中的 Label_RaffleNumber,Label_PrizesNum,ComboBox_Prize 等关键字,这都是 winform 的控件,如果你用的不是我的源码,winform 控件名和 lua 脚本中的也不一致,那么运行就会报错:

错误:

当前 demo 所有的控件名

winform 这个控制台不知道怎么回事,lua 中打印用的 print 方法打印出来全是乱码,但是 winform 控件使用 lua 脚本中的中文还是正常的。

后面我只能在 Form1 中添加一个 Print 方法,这样打印才是正常的。

Form1代码:

using NLua;

using System;

using System.IO;

using System.Text;

using System.Windows.Forms;

namespace NLuaDemo

{

public partial class Form1 : Form

{

public Form1()

{

InitializeComponent();

}

private Lua Luas = new Lua();

//lua 脚本的地址

private string LuaPath;

private void Form1_Load(object sender, EventArgs e)

{

Luas.State.Encoding = Encoding.UTF8;

LuaPath = $"{Application.StartupPath}\\main.lua";

}

private void Form1_FormClosing(object sender, FormClosingEventArgs e)

{

Luas.Close();

}

//热重载 点击事件

private void Button_HotUpdate_Click(object sender, EventArgs e)

{

LoadLua();

Luas.DoString("update()");

}

//抽奖 点击事件

private void Button_Raffle_Click(object sender, EventArgs e)

{

Luas.DoString("raffle()");

}

//加载 lua 脚本

private void LoadLua()

{

if (File.Exists(LuaPath))

{

Luas.LoadCLRPackage();

Luas.DoFile(LuaPath);

Luas["this"] = this;

}

}

//lua 打印用的

public void Print(string text)

{

Console.WriteLine(text);

}

}

}

运行后,点击 “热重载” 按钮,就会看到奖品和抽奖人都有那些内容,这些都是由 lua 进行赋值的。

点击 “抽奖” 按钮,就可以看到当前的中奖人和奖品

既然是热更新,那我在运行过程中改变代码可以么?当然可以!

我们把 lua 脚本中抽奖人和奖品表单删除一部分,改完后记得保存,如下:

--奖品

prize = {"手机", "电脑", "耳机", "鼠标"}

--抽奖人

participant = {"张三", "李四", "老王"}

再次点击 “热重载” 按钮,这时界面就发生了一些变化

抽奖人和奖品都少了

NLua 其实还有很多其他的用法,这里就没一一展示了。

上面的代码就是当前项目所有的源码了,创作不易,如果你觉得我的帖子对你有所帮助,也可以通过下载源码的方式来支持我,在此谢谢了。

源码:点击下载

结束

如果这个帖子对你有所帮助,欢迎 关注 + 点赞 + 留言

end

文章来源

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: