發(fā)布時(shí)間:2024-04-08 09:23:19 瀏覽量:143次
如果你還沒有編程基礎(chǔ),建議你先學(xué)習(xí)一些編程基礎(chǔ)。本文不是完全菜鳥教程,主要針對(duì)有其他語言經(jīng)驗(yàn)的開發(fā)者,如果想看菜鳥教程,建議看菜鳥教程的 Lua教程。
先看一個(gè)簡單類的代碼
1 ---@class BsnsPack @Base class of business pack
2 local BsnsPack = {
3 -- class fields
4 maxSerialNo = 0,
5 }
6
7 BsnsPack.__index = BsnsPack
8
9 --- new()
10 ---@return BsnsPack
11 function BsnsPack.new()
12 local o = {}
13
14 -- member fields
15 o.serialNo = 0
16 o.mod = 0
17 o.cmd = 0
18 o.payload = nil
19
20 -- bind BsnsPack methods
21 setmetatable(o, BsnsPack)
22 return o
23 end
24
25 --- set serial No.
26 ---@param serialNo number
27 function BsnsPack:setSerialNo(serialNo)
28 self.serialNo = serialNo
29 end
30
31 --- get serial No.
32 ---@return number
33 function BsnsPack:getSerialNo()
34 return self.serialNo
35 end
36
37 --- set mod
38 ---@param mod number
39 function BsnsPack:setMod(mod)
40 self.mod = mod
41 end
42
43 --- get mod
44 ---@return number
45 function BsnsPack:getMod()
46 return self.mod
47 end
48
49 --- set cmd
50 ---@param cmd number
51 function BsnsPack:setCmd(cmd)
52 self.cmd = cmd
53 end
54
55 --- get cmd
56 ---@return number
57 function BsnsPack:getCmd()
58 return self.cmd
59 end
60
61 --- set payload
62 ---@param payload any
63 function BsnsPack:setPayload(payload)
64 self.payload = payload
65 end
66
67 --- get payload
68 ---@return any
69 function BsnsPack:getPayload()
70 return self.payload
71 end
72
73 function BsnsPack.test()
74 print(BsnsPack.serialNo)
75 end
76
77 --- testPrivate
78 ---@param self BsnsPack
79 local function testPrivate(self)
80 print(self.serialNo)
81 end
82
83 ---@alias Request BsnsPack @Request is BsnsPack
84 local Request = BsnsPack
85
86 ---@class Response : BsnsPack @Response class
87 local Response = {}
88 setmetatable(Response, BsnsPack) -- bind super methods
89 Response.__index = Response
90
91 --- new()
92 ---@return Response
93 function Response.new()
94 local o = BsnsPack.new()
95
96 -- member fields
97 o.code = 0
98
99 setmetatable(o, nil) -- remove original metatable
100 setmetatable(o, Response) -- bind Response methods
101 return o
102 end
103
104 --- get result code
105 ---@return number
106 function Response:getCode()
107 return self.code
108 end
109
110 local bsnsPack = {}
111 bsnsPack.BsnsPack = BsnsPack
112 bsnsPack.Request = Request
113 bsnsPack.Response = Response
114
115 return bsnsPack
1、第1行:這是一行注釋
Lua的行注釋以兩個(gè)減號(hào) -- 開頭,
class注解:---@class TYPE[: PARENT_TYPE {, PARENT_TYPE}] [@comment]
這樣有利于 VS Code 代碼提示,例如將鼠標(biāo)放到代碼中出現(xiàn) BsnsPack 的地方上,會(huì)有小彈窗提示這個(gè)table的key,以及key的類型。
用得比較多的注解有 ---@class,---@return,---@param
2、第2行,定義一個(gè)叫 BsnsPack 的class(通過table模擬)。
Lua里沒有類,Lua的結(jié)構(gòu)化數(shù)據(jù)類型叫table,基于key-value結(jié)構(gòu)。相對(duì)于其他語言的 map / dictionary。訪問一個(gè)table的key對(duì)應(yīng)的值,可以用點(diǎn) . 來訪問,也可以用中括號(hào)[]來訪問
Lua里沒有單獨(dú)的數(shù)組結(jié)構(gòu),也是基于table,數(shù)組下標(biāo)是key,數(shù)組元素是value,要注意的是,Lua里數(shù)組下標(biāo)是從1開始的。
創(chuàng)建table的最簡單方式就是花括號(hào) {},創(chuàng)建一個(gè)空table。
Lua是腳本語言,變量不需要指定類型,只需要給它賦值。所以 BsnsPack = {maxSerialNo = 0,} 相當(dāng)于定義了個(gè)變量 BsnsPack,它的值是一個(gè)table。
Lua的變量默認(rèn)是全局的,加載到內(nèi)存的Lua代碼都可以訪問這個(gè)變量。為了避免命名沖突和意外修改,一般建議變量定義為局部變量,限制它的作用域。在變量前面加個(gè) local定義局部變量。
這里定義的 BsnsPack ,作用域只在這個(gè)文件里。其他文件不能訪問。也可以在函數(shù)、代碼塊里用 local 定義局部變量。
3、第7行,給 BsnsPack一個(gè)叫 __index 的 key 賦值為 BsnsPack 自己
Lua 的 table 里,__index 是個(gè)特殊的key,這是 Lua實(shí)現(xiàn)類和繼承的關(guān)鍵。
Lua里有個(gè)概念叫做元表。Lua定義了一些語言默認(rèn)key,這些key一般跟 +、-、*、/等操作符、key的訪問、值更新關(guān)聯(lián),這些key叫做元方法(Lua里的函數(shù)/方法也可以作為值),這些元方法合起來叫元表。
Lua里設(shè)置元表的方法是代碼第 21 行的 function setmetatable(t, metatable),調(diào)用這個(gè)方法會(huì)讓參數(shù) metatable 成為 參數(shù) t 的元表。
設(shè)置元表后,在代碼里訪問參數(shù) t 的一個(gè)key時(shí)會(huì)發(fā)生以下情況:
1)Lua先在 t 里找,看有沒有這個(gè)key,如果有,就返回這個(gè)key的值。否則,執(zhí)行2)
2)Lua看參數(shù) metatable 有沒有 __index 這個(gè)key,如果有,就在 __index 對(duì)應(yīng)的值里查找(__index的值如果是表,在這個(gè)表里查找;如果是函數(shù),執(zhí)行這個(gè)函數(shù))
BsnsPack.__index = BsnsPack,如果其他的table設(shè)置 BsnsPack 為元表,就可以訪問 BsnsPack 所有的key。 這些key的值如果是方法,就可以調(diào)用這些方法。
所以 BsnsPack 可以定義方法的模板,這就跟class類似。BsnsPack定義的數(shù)據(jù)key,相當(dāng)于靜態(tài)字段class field。BsnsPack定義的方法key,可以是成員方法member method,也可以是class method,后面介紹
4、第11~23行,定義BsnsPack的一個(gè)叫new的key,它的值是一個(gè)方法
Lua里一個(gè)代碼塊不用花括號(hào){},通過end作為結(jié)束標(biāo)記。
定義方法用 function 開頭,用點(diǎn).或者冒號(hào):分割talbe名和方法名,
用冒號(hào):定義的方法,會(huì)有個(gè)默認(rèn)參數(shù)self,相當(dāng)于調(diào)用者,如果外部用 BsnsPack:new() 這樣調(diào)用,則self == BsnsPack,如果用a:new()這樣調(diào)用,self==a。
用點(diǎn).定義的方法,沒有默認(rèn)參數(shù),只能顯式寫參數(shù)self。
一般地,用冒號(hào):定義成員方法member method(例如第23行的 function BsnsPack:setSerialNo(serialNo) )
1)調(diào)用 o:setSerialNo(serialNo) 時(shí),這里的self是對(duì)象o,只改對(duì)象o的serialNo,其他對(duì)象的serialNo不受影響。
用點(diǎn).定義構(gòu)造對(duì)象的方法(例如第11行的 function BsnsPack.new()),以及靜態(tài)方法class method(例如第69行的 function BsnsPack.test() )
1)在其他地方通過 BsnsPack.new()構(gòu)造BsnsPack對(duì)象
1)在其他地方通過 BsnsPack.test()調(diào)用類方法
建議,方法定義的時(shí)候是冒號(hào):,調(diào)用的時(shí)候用冒號(hào):,定義的時(shí)候是點(diǎn).,調(diào)用的時(shí)候也用點(diǎn).
構(gòu)造方法不一定叫new,只是為了統(tǒng)一,建議都用new,與其他語言一致。
方法new里面的 local o = {},定義的key都是成員字段member field(每次調(diào)用方法 BsnsPack.new() 都創(chuàng)建一個(gè)新的 table并對(duì)其字段初始化后返回)
Lua沒有私有的成員方法,可以定義文件的 local 方法,把對(duì)象作為參數(shù)self顯式的傳進(jìn)去(例如第79行 local function testPrivate(self))
5、第84行,給類BsnsPack定義一個(gè)別名 Request,其實(shí)就是把一個(gè)table賦值給另外一個(gè)變量
6、第87~102行,定義一個(gè)類Response,繼承基類BsnsPack
第87行,定義子類Response
第88行,設(shè)置元表,使得Response可以訪問BsnsPack所有的key(繼承BsnsPack所有的方法)
第89行,所有對(duì)象可以訪問Response所有的key(通過遞歸,包括BsnsPack所有的key)
第94行,通過調(diào)用BsnsPack構(gòu)造方法初始化o,o是BsnsPack的對(duì)象,擁有基類所有的member field
第97行,定義Response相對(duì)于基類新增的字段code
第99、100行,修改o的元表為Response,這樣o可以訪問Response所有的成員方法 member method(通過遞歸,包括BsnsPack所有的成員方法)
Response可以重寫B(tài)snsPack的方法
1 function Response:getPayload()
2 return self.payload
3 end
由于Lua里訪問key,先在table本身查找,如果沒有才在元表查找,所以會(huì)調(diào)用重寫的方法,實(shí)現(xiàn)多態(tài)。
7、第110~115行,導(dǎo)出本文件定義的類。
由于class的定義都是以 local 方式定義的局部變量,外部不能訪問,所以要把它當(dāng)作文件的返回值 return
如果該文件只導(dǎo)出一個(gè)class,直接return這個(gè)局部變量就可以,(例如,如果只導(dǎo)出BsnsPack,return BsnsPack 就可以)
由于本文件需要導(dǎo)出3個(gè)class,這里把他們放到一個(gè)table里導(dǎo)出
其他文件需要訪問這個(gè)文件的class,需要調(diào)用require方法導(dǎo)入進(jìn)來,該方法的參數(shù)是路徑(不含后綴.lua),返回值是這個(gè)lua文件的return值
1 local bsnsPack = require("Assets.Lua.bsns.bsns_pack")
2 local Request = bsnsPack.Request
3 local Response = bsnsPack.Response
8、如果想模塊化管理,把一個(gè)模塊所有的類通過一個(gè)文件暴露給其他模塊,可以在這個(gè)文件定義一個(gè)局部變量,把這個(gè)模塊所有的文件的類,都通過require導(dǎo)入進(jìn)來,并賦值給跟類同名的key,最后返回這個(gè)局部變量
文件bsns.lua
1 local bsns = {}
2
3 local bsnsPack = require("Assets.Lua.bsns.bsns_pack")
4 bsns.Request = bsnsPack.Request
5 bsns.Response = bsnsPack.Response
6
7 bsns.BsnsMod = require("Assets.Lua.bsns.bsns_mod")
8 bsns.BsnsCenter = require("Assets.Lua.bsns.bsns_center")
9
10 return bsns
9、可以實(shí)現(xiàn)一個(gè)通用的類定義函數(shù)
1 --- define a class
2 --- t._className, a string array, define class name
3 --- t._super, a table, define super class
4 --- t.__ctor, a function(self, ...), define member fields
5 --- @param t any
6 function class(t)
7 -- extends super
8 if t._super ~= nil then
9 -- static fields and methods
10 local superStaticClone = {}
11 for k, v in pairs(t._super) do
12 if k == "_ctor" then
13 goto continue
14 end
15
16 superStaticClone[k] = v
17
18 ::continue::
19 end
20
21 setmetatable(t, superStaticClone)
22 end
23
24 t.__index = t
25 -- new method
26 t.new = function(...)
27 local o = {}
28 invokeCtor(o, t, ...)
29
30 setmetatable(o, t) -- bind class
31 return o
32 end
33
34 function invokeCtor(o, cls, ...)
35 if cls._super ~= nil then
36 invokeCtor(o, cls._super, ...)
37 end
38
39 if cls._ctor ~= nil then
40 setmetatable(o, cls)
41 o:_ctor(...)
42 setmetatable(o, nil)
43 end
44 end
45
46 return t
47 end
有了這個(gè)函數(shù)可以這樣定義類
1 local TestClass = class({
2 -- class name
3 _className = "TestClass",
4
5 -- static fields:
6 size = 2,
7 count = 0,
8
9 -- member:
10 _ctor = function(self, ...)
11 local params = {...}
12 self.count = params[1]
13 self.age = params[2]
14 end
15 })
16
17 local TestClass2 = class({
18 _className = "TestClass2",
19 ---@class TestClass
20 _super = TestClass,
21
22 _ctor = function(self, ...)
23 self.fdsl = 3256
24 end
25 })
10、簡單語法介紹
1)Lua里的語句不需要分號(hào);結(jié)尾
2)Lua常用的基本數(shù)據(jù)類型有nil、boolean、number、string、function、table
3)獲取數(shù)組長度用 #數(shù)組變量,例如
1 local array = {"Lua", "Tutorial"}
2 local len = #array
3 print(len)
4)遍歷數(shù)組用
1 for i, v in ipairs(table) do
2
3 end
5)遍歷對(duì)象用
1 for k, v in pairs(obj) do
2
3 end
6)其他語法請(qǐng)查閱菜鳥教程
11、Lua代碼規(guī)范可參考
https://lua.ren/topic/172/
熱門資訊
探討游戲引擎的文章,介紹了10款游戲引擎及其代表作品,涵蓋了RAGE Engine、Naughty Dog Game Engine、The Dead Engine、Cry Engine、Avalanche Engine、Anvil Engine、IW Engine、Frostbite Engine、Creation引擎、Unreal Engine等引擎。借此分析引出了游戲設(shè)計(jì)領(lǐng)域和數(shù)字藝術(shù)教育的重要性,歡迎點(diǎn)擊咨詢報(bào)名。
2. 手機(jī)游戲如何開發(fā)(如何制作傳奇手游,都需要準(zhǔn)備些什么?)
?如何制作傳奇手游,都需要準(zhǔn)備些什么?提到傳奇手游相信大家都不陌生,他是許多80、90后的回憶;從起初的端游到現(xiàn)在的手游,說明時(shí)代在進(jìn)步游戲在更新,更趨于方便化移動(dòng)化。而如果我們想要制作一款傳奇手游的
3. B站視頻剪輯軟件「必剪」:免費(fèi)、炫酷特效,小白必備工具
B站視頻剪輯軟件「必剪」,完全免費(fèi)、一鍵制作炫酷特效,適合新手小白。快來試試!
4. Steam值得入手的武俠游戲盤點(diǎn),各具特色的快意江湖
游戲中玩家將面臨武俠人生的掙扎抉擇,戰(zhàn)或降?殺或放?每個(gè)抉定都將觸發(fā)更多愛恨糾葛的精彩奇遇。《天命奇御》具有多線劇情多結(jié)局,不限主線發(fā)展,高自由...
5. Bigtime加密游戲經(jīng)濟(jì)體系揭秘,不同玩家角色的經(jīng)濟(jì)活動(dòng)
Bigtime加密游戲經(jīng)濟(jì)模型分析,探討游戲經(jīng)濟(jì)特點(diǎn),幫助玩家更全面了解這款GameFi產(chǎn)品。
6. 3D動(dòng)畫軟件你知道幾個(gè)?3ds Max、Blender、Maya、Houdini大比拼
當(dāng)提到3D動(dòng)畫軟件或動(dòng)畫工具時(shí),指的是數(shù)字內(nèi)容創(chuàng)建工具。它是用于造型、建模以及繪制3D美術(shù)動(dòng)畫的軟件程序。但是,在3D動(dòng)畫軟件中還包含了其他類型的...
7. 3D動(dòng)漫建模全過程,不是一般人能學(xué)的會(huì)的,會(huì)的多不是人?
步驟01:面部,頸部,身體在一起這次我不準(zhǔn)備設(shè)計(jì)圖片,我從雕刻進(jìn)入。這一次,它將是一種純粹關(guān)注建模而非整體繪畫的形式。像往常一樣,我從Sphere創(chuàng)建它...
8. 如何自己開發(fā)一款游戲(游戲開發(fā)入門必看:五大獨(dú)立游戲開發(fā)技巧)
?游戲開發(fā)入門必看:五大獨(dú)立游戲開發(fā)技巧無論您是剛剛起步開發(fā)自己的第一款游戲,還是已經(jīng)制作了幾款游戲,本篇文章中的5大獨(dú)立游戲開發(fā)技巧都可以幫助您更好地設(shè)計(jì)下一款游戲。無論你對(duì)游戲有著什么樣的概念,都
?三昧動(dòng)漫對(duì)于著名ARPG游戲《巫師》系列,最近CD Projekt 的高層回應(yīng)并不會(huì)推出《巫師4》。因?yàn)椤段讕煛废盗性诓邉澋臅r(shí)候一直定位在“三部曲”的故事框架,所以在游戲的出品上不可能出現(xiàn)《巫師4》
10. 3D打印技巧揭秘!Cura設(shè)置讓你的模型更堅(jiān)固
想讓你的3D打印模型更堅(jiān)固?不妨嘗試一下Cura參數(shù)設(shè)置和設(shè)計(jì)技巧,讓你輕松掌握!
最新文章
同學(xué)您好!