这段时间用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