现在很多大型项目使用Unity+Lua的开发模式, 大部分逻辑使用Lua编写.
由于Lua是非强制类型的语言, 写起来非常灵活, 我们可以将任何对象当做值来使用:
我们可以随心所欲的写, 只要满足基本的语法.
当然, 灵活的意思就是限制较少, 后果也很明显: 代码难以维护, 无法在运行之前过滤一些基本的错误.
为了在利用Lua的灵活性的同时, 尽可能的降低代码的维护难度, 我们需要利用一些工具, 同时人为做一些限定.
相信大部分使用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就不再像是一匹脱缰的野马, 难以驾驭了.
当前作者的项目组已经在本文分享的基础上形成了一套成熟的方案, 极大的提高了开发效率.
更多的特性请大家自行探索, 希望对大家有所帮助.