|
原文地址:http://blog.csdn.net/musicvs/article/details/8166572
正文:
最近看了一下TestLua的例子,挺有意思的,使用Lua对网游开发来说,很实用。我目前这个项目没有使用Lua等脚本,已经吃尽苦头了,每次客户端更新就流失好多玩家。虽然我的项目没有用cocos2d-x开发,但是因为最近在研究它,所以就好奇一下lua和cocos2d-x的整合。
百度没有多少资料,最实在的一篇教程应该就是Himi那篇了(高手一只,不解释)。所以只能靠自己了。
怎么运行Lua例子,以及在cocos2d-x里使用Lua的简单规则,请看之前我写的那篇教程,以及更加详细的Himi的教程(http://www.himigame.com/iphone-cocos2dx/681.html)。
这里我主要是想分享一下如何在lua中使用自己的类,其实cocos2d-x已经提供工具,并且封装好了c++整合lua。
好,废话说多了,开始~!
1.只关注LuaCocos2d.cpp文件
假设看这篇文章的朋友已经了解了LuaCocos2d.cpp的大概作用(不了解的,可以看看上面推荐的那篇Himi的文章),我们知道,要在lua使用cocos2d-x里的类,就首先要在LuaCocos2d.cpp里“声明”,此声明非彼声明哈,但是比较贴切。反正就是要在这个LuaCocos2d.cpp里做文章就是了。虽然这个cpp文件很庞大,但是都是一些重复的东西,形如:
[cpp]view plaincopy
print?
- tolua_cclass(tolua_S,"CCActionEase","CCActionEase","CCActionInterval",NULL);
- tolua_beginmodule(tolua_S,"CCActionEase");
- tolua_function(tolua_S,"copyWithZone",tolua_Cocos2d_CCActionEase_copyWithZone00);
- tolua_function(tolua_S,"reverse",tolua_Cocos2d_CCActionEase_reverse00);
- tolua_function(tolua_S,"create",tolua_Cocos2d_CCActionEase_create00);
- tolua_endmodule(tolua_S);
这些操作就像是在向程序注册我们的类,让这些类可以在lua中使用。
2.真正想知道的事情是,除了cocos2d-x的类,我们可以在lua中使用自己的类吗?
当然可以了,就算不是在cocos2d-x引擎里,本身lua就可以在c++中互相调用的(当然,Java也可以)。只是,既然cocos2d-x帮我们封装好了,我们就用它提供的方法来使用lua吧。
首先,我第一时间会想到,在LuaCocos2d.cpp中依葫芦画瓢,把自己的类加进去就好了。当然,我也是这么想的,但是在添加的过程中碰了钉子,很多规则不太清楚,总是有些错误。后来。。。
3.tolua++.exe工具
后来我发现了cocos2d-x竟然提供了这个工具,这是十分难发现的,隐藏得很深的,没有任何提示的,我竟然能发现它,噗。
(我才不会告诉你们LuaCocos2d.cpp文件的顶部有注释,并且注释已经告诉我们有这个工具的)
[cpp]view plaincopy
print?
- /*
- ** Lua binding: Cocos2d
- ** Generated automatically by tolua++-1.0.92 on 08/30/12 12:11:53.
- */
工具在这个路径下:cocos2d-2.0-x-2.0.2\tools\tolua++,有windows版本的,和mac版本的。
这个工具可以帮我们生成自定义类的“声明”代码。怎么使用?该目录下有个README文件,我用我那蹩脚的英语水平看懂了80%,并且加上了蹩脚的中文注释,希望不要介意:
1.Generating the lua<-->C bindings with tolua++
//使用此命令生成LuaCocos2d.cpp文件
tolua++.exe -tCocos2d -o LuaCocos2d.cpp Cocos2d.pkg
An ant script has been provided to generate the relevant files, to do this after
modifying the .pkg files you should use the following command in this directory:
ant
This will generate the bindings file, patch it to compile successfully and move it
to the standard destination.
2. Writing .pkg files //为要在lua使用的类编写pkg文件
1) enum keeps the same //枚举类型保留不变
2) remove CC_DLL for the class defines, pay attention to multi inherites //不要使用CC_DLL,改用多继承
3) remove inline keyword for declaration and implementation //删除内置变量?
4) remove public protect and private //不要用访问限定词
5) remove the decalration of class member variable //不要成员变量
6) keep static keyword //保留静态关键词
7) remove memeber functions that declared as private or protected //非public的函数都删除
也许有点混乱,来看看该目录下的这个文件:Cocos2d.pkg
$#include "LuaCocos2d.h"
$pfile "CCAction.pkg"
$pfile "CCActionCamera.pkg"
$pfile "CCActionCatmullRom.pkg"
$pfile "CCActionEase.pkg"
$pfile "CCActionGrid.pkg"
$pfile "CCActionGrid3D.pkg"
$pfile "CCActionManager.pkg"
| 其实这些就是cocos2d-x的一些,这些类放在这里,是为了自动生成LuaCocos2d.cpp文件,这样,在lua中就可以使用这些类了。
那么,我们同样可以把自定义的类放到这里来。
当然,必须按照规则来编写pkg文件。
别着急,一步步来…
4.编写pkg文件
a. 首先我写了一个自定义的类,这个类很简单,用来生成精灵的工厂类:
[cpp]view plaincopy
print?
- /************************************************************************/
- /* 精灵工厂 */
- /* 使用了简单工厂,但,不是工厂模式 */
- /************************************************************************/
- #ifndef __SPRITE_FACTORY_H__
- #define __SPRITE_FACTORY_H__
- #include "cocos2d.h"
- usingnamespace cocos2d;
- class SpriteFactory
- {
- public:
- enum SpriteType
- {
- en_close,
- en_grossini,
- en_grossinis_sister,
- en_grossinis_sister2,
- };
- static SpriteFactory* sharedSpriteFactory();
- CCSprite* createSprite(CCLayer* mLayer, SpriteType enSpriteType);
- private:
- static SpriteFactory* mFactory;
- };
- #endif
b. 然后,开始编写pkg文件,还记得README里的规则吗?再看一次:
1) enum keeps the same //枚举类型保留不变
2) remove CC_DLL for the class defines, pay attention to multi inherites //不要使用CC_DLL,改用多继承
3) remove inline keyword for declaration and implementation //删除内置变量?
4) remove public protect and private //不要用访问限定词
5) remove the decalration of class member variable //不要成员变量
6) keep static keyword //保留静态关键词
7) remove memeber functions that declared as private or protected //非public的函数
根据这个规则,我要把public和private关键字去掉,还要把所有成员变量去掉,当然,多余的什么include、using namespace都不要了,对了,枚举类型要保留。
于是,最后的pkg文件如下:
[cpp]view plaincopy
print?
- class SpriteFactory
- {
- enum SpriteType
- {
- en_close,
- en_grossini,
- en_grossinis_sister,
- en_grossinis_sister2,
- };
- static SpriteFactory* sharedSpriteFactory();
- CCSprite* createSprite(CCLayer* mLayer, SpriteType enSpriteType);
- };
好简洁,我喜欢。
OK,现在来试试生成LuaCocos2d.cpp文件吧,打开cmd,进入tolua++.exe工具的目录,把我们的SpriteFactory.pkg文件也拷到这个目录,啊~!对了!要在Cocos2d.pkg里加上SpriteFactory.pkg文件:
$pfile " SpriteFactory.pkg"
然后,在cmd里输入命令,开始生成LuaCocos2d.cpp文件~
OK,没有意外的话,LuaCocos2d.cpp已经在当前目录下了,把它拷到你的lua工程里,替换掉原来的LuaCocos2d.cpp文件,然后,编译~!
大功告成……啊才怪啊~!
正文:
上回说到,把LuaCocos2d.cpp文件拷到我们的lua工程里,然后,编译。
你会发现一大堆的编译错误,超过100个了,木了个头的。怎么回事,我只能认定是这个工具出问题了。
怎么办?没关系~我们在LuaCocos2d.cpp里搜索一下我们的SpriteFactory类吧,肯定有的,看看其中一段:
[cpp]view plaincopy
print?
- /* method: sharedSpriteFactory of class SpriteFactory */
- #ifndef TOLUA_DISABLE_tolua_Cocos2d_SpriteFactory_sharedSpriteFactory00
- staticint tolua_Cocos2d_SpriteFactory_sharedSpriteFactory00(lua_State* tolua_S)
- {
- #ifndef TOLUA_RELEASE
- tolua_Error tolua_err;
- if (
- !tolua_isusertable(tolua_S,1,"SpriteFactory",0,&tolua_err) ||
- !tolua_isnoobj(tolua_S,2,&tolua_err)
- )
- goto tolua_lerror;
- else
- #endif
- {
- {
- SpriteFactory* tolua_ret = (SpriteFactory*) SpriteFactory::sharedSpriteFactory();
- tolua_pushusertype(tolua_S,(void*)tolua_ret,"SpriteFactory");
- }
- }
- return 1;
- #ifndef TOLUA_RELEASE
- tolua_lerror:
- tolua_error(tolua_S,"#ferror in function 'sharedSpriteFactory'.",&tolua_err);
- return 0;
- #endif
- }
- #endif //#ifndef TOLUA_DISABLE
知道我想说什么吧?既然它已经能生成自定类的这些代码了,那还怕什么。
现在回到生成LuaCocos2d.cpp的步骤,打开Cocos2d.pkg文件,把其它所有无关的类删除~!变成这样:
[cpp]view plaincopy
print?
- <span style="font-size:14px;">$#include "LuaCocos2d.h"
- $pfile " SpriteFactory.pkg"
- </span>
然后继续输入命令,生成LuaCocos2d.cpp文件。
于是,这样生成的文件就只有我们自定义类的声明代码了:
[cpp]view plaincopy
print?
- <span style="font-size:14px;">#include "LuaCocos2d.h"
- /* function to register type */
- staticvoid tolua_reg_types (lua_State* tolua_S)
- {
- #ifndef Mtolua_typeid
- #define Mtolua_typeid(L,TI,T)
- #endif
- tolua_usertype(tolua_S,"CCSprite");
- Mtolua_typeid(tolua_S,typeid(CCSprite), "CCSprite");
- tolua_usertype(tolua_S,"CCLayer");
- Mtolua_typeid(tolua_S,typeid(CCLayer), "CCLayer");
- tolua_usertype(tolua_S,"SpriteFactory");
- Mtolua_typeid(tolua_S,typeid(SpriteFactory), "SpriteFactory");
- }
- /* method: sharedSpriteFactory of class SpriteFactory */
- #ifndef TOLUA_DISABLE_tolua_Cocos2d_SpriteFactory_sharedSpriteFactory00
- staticint tolua_Cocos2d_SpriteFactory_sharedSpriteFactory00(lua_State* tolua_S)
- {
- #ifndef TOLUA_RELEASE
- tolua_Error tolua_err;
- if (
- !tolua_isusertable(tolua_S,1,"SpriteFactory",0,&tolua_err) ||
- !tolua_isnoobj(tolua_S,2,&tolua_err)
- )
- goto tolua_lerror;
- else
- #endif
- {
- {
- SpriteFactory* tolua_ret = (SpriteFactory*) SpriteFactory::sharedSpriteFactory();
- tolua_pushusertype(tolua_S,(void*)tolua_ret,"SpriteFactory");
- }
- }
- return 1;
- #ifndef TOLUA_RELEASE
- tolua_lerror:
- tolua_error(tolua_S,"#ferror in function 'sharedSpriteFactory'.",&tolua_err);
- return 0;
- #endif
- }
- #endif //#ifndef TOLUA_DISABLE
- /* method: createSprite of class SpriteFactory */
- #ifndef TOLUA_DISABLE_tolua_Cocos2d_SpriteFactory_createSprite00
- staticint tolua_Cocos2d_SpriteFactory_createSprite00(lua_State* tolua_S)
- {
- #ifndef TOLUA_RELEASE
- tolua_Error tolua_err;
- if (
- !tolua_isusertype(tolua_S,1,"SpriteFactory",0,&tolua_err) ||
- !tolua_isusertype(tolua_S,2,"CCLayer",0,&tolua_err) ||
- !tolua_isnumber(tolua_S,3,0,&tolua_err) ||
- !tolua_isnoobj(tolua_S,4,&tolua_err)
- )
- goto tolua_lerror;
- else
- #endif
- {
- SpriteFactory* self = (SpriteFactory*) tolua_tousertype(tolua_S,1,0);
- CCLayer* mLayer = ((CCLayer*) tolua_tousertype(tolua_S,2,0));
- SpriteFactory::SpriteType enSpriteType = ((SpriteFactory::SpriteType) (int) tolua_tonumber(tolua_S,3,0));
- #ifndef TOLUA_RELEASE
- if (!self) tolua_error(tolua_S,"invalid 'self' in function 'createSprite'", NULL);
- #endif
- {
- CCSprite* tolua_ret = (CCSprite*) self->createSprite(mLayer,enSpriteType);
- tolua_pushusertype(tolua_S,(void*)tolua_ret,"CCSprite");
- }
- }
- return 1;
- #ifndef TOLUA_RELEASE
- tolua_lerror:
- tolua_error(tolua_S,"#ferror in function 'createSprite'.",&tolua_err);
- return 0;
- #endif
- }
- #endif //#ifndef TOLUA_DISABLE
- /* Open function */
- TOLUA_API int tolua_Cocos2d_open (lua_State* tolua_S)
- {
- tolua_open(tolua_S);
- tolua_reg_types(tolua_S);
- tolua_module(tolua_S,NULL,0);
- tolua_beginmodule(tolua_S,NULL);
- tolua_cclass(tolua_S,"SpriteFactory","SpriteFactory","",NULL);
- tolua_beginmodule(tolua_S,"SpriteFactory");
- tolua_constant(tolua_S,"en_close",SpriteFactory::en_close);
- tolua_constant(tolua_S,"en_grossini",SpriteFactory::en_grossini);
- tolua_constant(tolua_S,"en_grossinis_sister",SpriteFactory::en_grossinis_sister);
- tolua_constant(tolua_S,"en_grossinis_sister2",SpriteFactory::en_grossinis_sister2);
- tolua_function(tolua_S,"sharedSpriteFactory",tolua_Cocos2d_SpriteFactory_sharedSpriteFactory00);
- tolua_function(tolua_S,"createSprite",tolua_Cocos2d_SpriteFactory_createSprite00);
- tolua_endmodule(tolua_S);
- tolua_endmodule(tolua_S);
- return 1;
- }
- #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 501
- TOLUA_API int luaopen_Cocos2d (lua_State* tolua_S) {
- return tolua_Cocos2d_open(tolua_S);
- };
- #endif
- </span>
这就没有问题了,我们不要替换它原有LuaCocos2d.cpp文件,而是依葫芦画瓢地把我们生成的LuaCocos2d.cpp文件里新增的内容拷到原有的文件里。这样编译就基本不会报错了,即使报错,也只是小范围报错,顶多几个,不会出现上百个错误吓死人了。
然后编译,运行,没有问题了。
我写了一个lua文件测试我的功能:
[plain]view plaincopy
print?
- local function createLayer()
- local layer = CCLayer:create();
- local sprite = SpriteFactory:sharedSpriteFactory():createSprite(layer, SpriteFactory.en_grossini);
- sprite:setPosition(200, 200);
- return layer;
- end
- local scene = CCScene:create();
- scene:addChild(createLayer());
- CCDirector:sharedDirector():replaceScene(scene);
运行效果:
完美~!噗,自己赞自己。 |
|