很快就要開始介紹Lua裏的「面向對象」了,在此以前,咱們先來了解一下Lua的模塊。安全
笨木頭花心貢獻,哈?花心?不,是用心~函數
轉載請註明,原文地址:http://www.benmutou.com/archives/1786測試
文章來源:笨木頭與遊戲開發ui
Lua的模塊是什麼東西呢?一般咱們能夠理解爲是一個table,這個table裏有一些變量、一些函數…lua
等等,這不就是咱們所熟悉的類嗎?spa
沒錯,和類很像(實際上我說不出它們的區別)。code
咱們來看看一個簡單的模塊,新建一個文件,命名爲game.lua,代碼以下:對象
1
2 3 4 5 6 7 8 9 10 11 |
game
= {} function game.play() print("那麼,開始吧"); end function game.quit() print("你走吧,我保證你不會出事的,呵,呵呵"); end return game; |
咱們定義了一個table,而且給這個table加了兩個字段,只不過這兩個字段的值是函數而已。繼承
至於如何使用模塊,那就要用到咱們以前介紹過的require了。遊戲
咱們在main函數裏這麼使用:
1
2 3 4 5 6 7 8 |
local function main() cc.FileUtils:getInstance():addSearchPath("src") game = require("game"); game.play(); end |
注意,咱們要require其餘文件的時候,要把文件路徑給設置好,不然會找不到文件。
由於我使用的是Cocos Code IDE,直接調用addSearchPath函數就能夠了,個人game.lua文件是在src目錄下的。
好了,運行代碼,結果以下:
[LUA-print] 那麼,開始吧
OK,這就是一個很簡單的模塊,若是咱們習慣了Java、C++等面嚮對象語言,那也能夠簡單地把模塊理解爲類。
假設咱們想把剛剛的game模塊改個名字,改爲eatDaddyGame,那麼,咱們須要作如下兩件事情:
1).修改game.lua的文件名
2).修改game.lua的內容,把全部的game改爲eatDaddyGame
目前的game.lua函數還算少,就兩個,實際上一個模塊的函數確定不會少的,那麼,要這麼去改這些函數,太煩了。
若是批量修改,又怕有哪一個地方改錯。
因而,咱們能夠這麼偷懶:
1
2 3 4 5 6 7 8 9 10 11 12 13 |
game
= {} local M = game; function M.play() print("那麼,開始吧"); end function M.quit() print("你走吧,我保證你不會出事的,呵,呵呵"); end return M; |
咱們用一個局部變量M來代替了game,因而,之後咱們只須要修改前面兩個的game就能夠了,函數部分的內容徹底不須要去修改。
這個偷懶其實蠻有用的,某些狀況下,修改越少,越安全~
實際上,咱們能夠更加得偷懶,之後修改模塊名,只須要修改模塊的文件名就能夠了,文件內容能夠無論,具體怎麼實現?
看代碼:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 |
local M = {}; local modelName = ...; _G[modelName] = M; function M.play() print("那麼,開始吧"); end function M.quit() print("你走吧,我保證你不會出事的,呵,呵呵"); end return M; |
留意一下,這裏有一個 local modelName = …
「…」就是傳遞給模塊的模塊名,在這裏其實就是「game」這個字符串。
接着,有點微妙了,還記得以前介紹的全局環境_G嗎?咱們以」game」做爲字段名,添加到_G這個table裏。
因而,當咱們直接調用game的時候,其實就是在調用_G[「game」]的內容了,而這個內容就是這裏的M。
能邏輯過來嗎?就是這麼簡單,在你沒有忘記_G的前提下~
若是說,剛剛已經達到了咱們做爲高(ai)智(zhe)商(teng)人羣的巔峯,那,你就太天真了。
巔峯就是要拿來超越的,還記得咱們的非全局環境嗎?就是那個setfenv函數。
咱們來看看下面的代碼:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
local M = {}; local modelName = ...; _G[modelName] = M; setfenv(1, M); function play() print("那麼,開始吧"); end function quit() print("你走吧,我保證你不會出事的,呵,呵呵"); end return M; |
咱們把game.lua這個模塊裏的全局環境設置爲M,因而,咱們直接定義函數的時候,不須要再帶M前綴。
由於此時的全局環境就是M,不帶前綴去定義變量,就是全局變量,這時的全局變量是保存在M裏。
因此,實際上,play和quit函數仍然是在M這個table裏。
因而,咱們連前綴都不用寫了,這真是懶到了一個極致,簡直就是藝術~
另外,因爲當前的全局環境是M,因此, 在這裏不須要擔憂從新定義了已存在的函數名,由於外部的全局變量與這裏無關了。
固然,若是你們如今就運行代碼,確定會報錯了。
由於咱們的全局環境改變了,因此print函數也找不到了。
爲了解決這個問題,咱們看看第5條內容吧~
第一個方法,就是咱們以前介紹過的,使用繼承,以下代碼:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
local M = {}; local modelName = ...; _G[modelName] = M; -- 方法1:使用繼承 setmetatable(M, {__index = _G}); setfenv(1, M); function play() print("那麼,開始吧"); end function quit() print("你走吧,我保證你不會出事的,呵,呵呵"); end return M; |
沒錯,使用__index元方法就能解決這個問題了,當找不到print等函數時,就會去原來的_G裏查找。
第二個方法更簡單,使用一個局部變量把原來的_G保存起來,以下代碼:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
local M = {}; local modelName = ...; _G[modelName] = M; -- 方法2:使用局部變量保存_G local _G = _G; setfenv(1, M); function play() _G.print("那麼,開始吧"); end function quit() _G.print("你走吧,我保證你不會出事的,呵,呵呵"); end return M; |
這種方法的缺點比較明顯,那就是,每次調用print等函數時,都要使用_G前綴。
第三個方法比較繁瑣,使用局部變量把須要用到的其餘模塊保存起來,以下代碼:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
local M = {}; local modelName = ...; _G[modelName] = M; -- 方法3:保存須要使用到的模塊 local print = print; setfenv(1, M); function play() print("那麼,開始吧"); end function quit() print("你走吧,我保證你不會出事的,呵,呵呵"); end return M; |
這種方法的缺點更明顯了,全部用到的模塊都要用局部變量聲明一次,煩人。
但,就速度而言,第三種方案比第二種方案快,第二種方法又比第一種快。
但至於快多少,我也不知道,只是理論上~我也沒測試。
本覺得剛剛介紹的那些技巧已經夠偷懶的吧?
但Lua彷佛知道咱們有多懶似的,它居然把咱們把這一切都自動完成了。
再來回憶咱們剛剛爲了偷懶而寫的幾句代碼:
1
2 3 4 5 6 |
local M = {}; local modelName = ...; _G[modelName] = M; setmetatable(M, {__index = _G}); setfenv(1, M); |
就這幾句代碼,其實咱們能夠忽略不寫,由於,咱們有module函數,它的功能就至關於寫了這些代碼。
咱們修改一下game.lua的內容,以下代碼:
1
2 3 4 5 6 7 8 9 |
module
(..., package.seeall); function play() print("那麼,開始吧"); end function quit() print("你走吧,我保證你不會出事的,呵,呵呵"); end |
注意,前面的幾行代碼都沒了,只留下了一個module函數的調用。
module函數的調用已經至關於以前的那些代碼了。
而package.seeall參數的做用就是讓原來的_G依然生效,至關於調用了:setmetatable(M, {__index = _G});
再次留意一下,代碼末尾的return M也不見了,由於module函數的存在,已經不須要咱們主動去返回這個模塊的table了。
這篇結束的內容彷佛有點多,我也寫了一個多小時了。
其實我還省略很多東西,好比package.loaded,lua路徑查找的規則等等。
由於這些Cocos Code IDE,或者說是Cocos2d-x lua,已經幫咱們作了,咱們不須要去管這些。
因此我就拈輕怕重了,啊不,是顧此失彼…不對~!反正,就是那個意思了~!
原文地址:http://www.benmutou.com/archives/1786