這段時間用lua在做一個項目,用cocos2dx爲基礎來開發,採用lua腳本語言爲核心語言。但是對lua幾乎零基礎的我,處處碰壁。首先瞭解到lua一般是用面向過程的方式來寫腳本,並且看到cocos2dx裏的lua sample幾乎都是用的面向過程的方式來寫的,但是我還是比較熟悉C++的面向對象的方式來寫。
先是研究到lua通過元表的方式可以模擬面向對象的編程方式,但在網上多數的資料都是子類繼承lua寫的基類,而cocos2dx卻要繼承C++的類,所以cocos2dx裏的extern.lua就派上用場了,它裏面編寫了lua繼承C++類的模板,直接調用class函數就可以實現繼承cocos2dx裏C++類。
extern.lua保存在cocos2dx的cocos2d-x-2.2.1\samples\Lua\TestLua\Resources\luaScript\extern.lua。
以下簡單寫寫試用方式:
require "luaScript/extern.lua"
local Login = class("Login",
function()
return CCLayer:create()
end
)
function Login:create()
local ret = Login.new()
ret:init()
return ret
end
function Login:init()
--添加需要的初始化腳本
end
然後就可以用local login = Login:create()來創建以上的子類了。
但是隨着功能的增加發現又要重寫C++父類的方法,該怎麼寫呢,又在網上一通查找,可以沒發現幾個真正能用的方式。最後還是發現了一個blog寫的實現了這樣的功能。鏈接地址是http://www.litefeel.com/lua-override-userdata/。實際上早有發現這樣個blog,但是當時沒看明白就忽略了,後來再次發現的時候,茅塞頓開。這裏簡單寫下我的使用方式,以上鍊接的blog寫了幾種實現的方式,各有利弊。
方法一:
local _setVisible = nil
local MyLayer = class("MyLayer", function()
local layer = CCLayer:create()
-- save c++ member method point.
_setVisible = layer.setVisible
return layer
end)
-- override CCLayer::setVisible
function MyLayer:setVisible(visible)
-- invoke CCLayer::setVisible
_setVisible(self, visible)
-- to do something.
end
以上方法一雖然是作者說的最優的方法,但是總感覺這樣寫很彆扭。而且懷疑實例化以上多個類時,_setVisible這個變量是不是被所有實例化的類共享的,比較懶一直沒去證實。
方法二:
local MyLayer = class("MyLayer", function()
return CCLayer:create()
end)
-- override CCLayer::setVisible
function MyLayer:setVisible(visible)
-- invoke CCLayer::setVisible
getmetatable(self).setVisible(self, visible)
-- to do something.
end
此方法二雖然實現很簡潔,但是經測試,以上的方式只能繼承C++的直接父類,父類的父類是不能繼承的。我也很喜歡這中實現方式,但很遺憾,不是所有情況都能用。
然後繼承了C++的父類,怎麼添加lua類裏自己的成員變量呢,網上大多數都是這樣寫的:
require "extern"
MySprite = class("MySprite",
function(fileName)
return CCSprite:create(fileName)
end
)
MySpriteMySprite.__index = MySprite
MySprite.type = 0
function MySprite:createMS(fileName,_type)
local mySprite = MySprite.new(fileName)
mySprite:myInit(_type)
return mySprite
end
function MySprite:myInit(_type)
self.type =_type
end
但是經使用發現,以上的方法 MySprite.type = 0 這個成員變量是被所有實例化的lua類共享的,所有此種方式對於實例化一次的類來說使用不影響,但如果多次實例化就出現問題了。經過多次研究測試後發現以下這樣寫就可以被多次實例化:
require "extern"
MySprite = class("MySprite",
function(fileName)
return CCSprite:create(fileName)
end
)
function MySprite:createMS(fileName,_type)
local mySprite = MySprite.new(fileName)
mySprite.type = 0
mySprite:myInit(_type)
return mySprite
end
function MySprite:myInit(_type)
self.type =_type
end
可能剛開始接觸lua的時候看到過這樣的說法,self類似於C++裏的this,大概可以這樣理解,但並不是完全一樣。self.var裏的self是指當前var所屬於的table,與直接使用Table.var是不一樣的(這裏的Table是指定義的table變量名)。
以上都是自己在使用lua過程中,對lua的一些結論和認識,如有發現問題,歡迎指正和討論。
最後給自己寫的小遊戲打下廣告,一個釋放你壓力的小遊戲,一個你敢叫它敢動的小遊戲。敢不敢來試下?
點擊下載,或在 Google Play Store 搜索 Make a Noise