当前位置: 首页 > 工具软件 > EmmyLua > 使用案例 >

Unity中配合EmmyLua的Lua使用方案

杨彦君
2023-12-01

本文分享Unity中配合EmmyLua的Lua使用方案

现在很多大型项目使用Unity+Lua的开发模式, 大部分逻辑使用Lua编写.

由于Lua是非强制类型的语言, 写起来非常灵活, 我们可以将任何对象当做值来使用:

  • 可以将函数当做值进行赋值, 清除, 传参
  • 可以将本来接受数值类型的类型传递一个函数, 一个表
  • 可以将一个表当做函数使用
  • 可以在表里存储任何类型的值(nil除外)

我们可以随心所欲的写, 只要满足基本的语法.

当然, 灵活的意思就是限制较少, 后果也很明显: 代码难以维护, 无法在运行之前过滤一些基本的错误.

为了在利用Lua的灵活性的同时, 尽可能的降低代码的维护难度, 我们需要利用一些工具, 同时人为做一些限定.

EmmyLua插件

相信大部分使用Lua开发的同学都听说或者接触或者正在使用EmmyLua.

没使用过也不用担心, 这里简单介绍一下.

EmmyLua可以提供Lua的语法高亮和自动完成, 当然也提供断点调试.

重点是及其好用的前提下还免费, 还拥有大量的维护者, QQ群也比较活跃.

基本的介绍大家可以移步官方文档查询.

本文侧重介绍结构化自动完成的部分.

结构化和自动完成

我们在项目中会使用大量的结构, 可能是一个普通表, 也可能是自己抽象的类.

如果是自己抽象的类还好说, 基本结构和方法可以看出来, 对开发影响不大.

如果是一些普通的表, 特别是这些表会在不同的模块之间流转, 且在不同的情况有不同的值, 在流转的过程中还可能被改变.

这种表就会变得及其难以维护.

我们一般使用插件的注解(annotation)功能, 将这种够不上类, 但是也需要一定结构的表在插件的视野下变成一个类, 从而降低维护难度.

---@class Car
---@field color number @颜色
---@field shape string @形状
local t = {}

---@param car Car
function test(car)
    print(car.color)   
    print(car.shape)
end

在使用该表的地方声明表为指定的类型, 那么插件就可以自动完成需要的内容, 避免了记忆表的字段名称, 且不易出错.

我们可以单独使用一个文件来存放所有的结构定义, 这个文件也不需要放到包里出现在线上的代码中, 只要插件能够找到, 我们就可以使用结构.

当然, 我们自己抽象的类也可以使用注解.

-----------------------------------------------------
-- Object.lua
--- Object 所有类的基类
---@field name stirng @名称
local _M = class("Object")

-----------------------------------------------------
-- Car.lua

--- Car 车
---@class Car : Object
---@field color number @颜色
---@field shape string @形状
local _M = class("Car", require("Object"))

---@param otherCar Car
function _M:Clone(otherCar)
    print("Clone")
end
-----------------------------------------------------
-- Test.lua

---@type Car
local car = require("Car").new()
print(car.name) 
print(car.color)   
print(car.shape)

这样, 插件就能正确的提示和自动完成属于该类的属性和方法等内容.

将配置表和网络协议结构化

相信大家的项目中, 配置表和网络协议也是必不可少的内容, 将它们结构化后使用插件也能极大的提高开发效率.

我们一般将配置表或者协议读取到内存中后是以普通表的形式存在, 这个时候只需要结合上面的方案, 将内存中的那些表标记一个预先定义好的结构即可.

比如很多项目的协议使用的是ProtoBuff, 我们只需要写一个工具读取ProtoBuff的定义文件, 将其结构转化成插件支持的格式, 然后在对应的表上标记好类型, 就可以将其结构化使用.

配置表的处理也是一样的, 读取配置表生成结构文件, 在表上做好标记, 后面在Lua中正常使用即可.

-----------------------------------------------------
-- Account.proto
---message Account
---{
---	optional	string			account		= 1; //账号名
---	optional	string			passwd		= 2; //密码
---}

-----------------------------------------------------
-- protoDef.lua
---@class Account
---@field account string @账号名
---@field passwd string @密码
local struct = {}

-----------------------------------------------------
-- test.lua
---@type Account
local t = ProtoBuff.parseFromData(data)
print(t.account)
print(t.passwd)

文件"protoDef.lua"只是用来存放生成的结构, 不需要出现在正式的代码中.

总结

如果充分将插件使用起来, 同时加上一些代码的限制.

比如私有属性或者方法加下划线, 区别开公有的等, 一步步完善, 最终形成一个成熟的方案, 那时Lua就不再像是一匹脱缰的野马, 难以驾驭了.

当前作者的项目组已经在本文分享的基础上形成了一套成熟的方案, 极大的提高了开发效率.

更多的特性请大家自行探索, 希望对大家有所帮助.

 类似资料: