在Lua中使用自定义类——tolua++工具使用

原文地址 http://blog.csdn.net/musicvs/article/details/8166572 


正文:

 

最近看了一下TestLua的例子,挺有意思的,使用Lua对网游开发来说,很实用。我目前这个项目没有使用Lua等脚本,已经吃尽苦头了,每次客户端更新就流失好多玩家。虽然我的项目没有用cocos2d-x开发,但是因为最近在研究它,所以就好奇一下luacocos2d-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 plain  copy
 print ?
  1. tolua_cclass(tolua_S,"CCActionEase","CCActionEase","CCActionInterval",NULL);  
  2.   tolua_beginmodule(tolua_S,"CCActionEase");  
  3.    tolua_function(tolua_S,"copyWithZone",tolua_Cocos2d_CCActionEase_copyWithZone00);  
  4.    tolua_function(tolua_S,"reverse",tolua_Cocos2d_CCActionEase_reverse00);  
  5.    tolua_function(tolua_S,"create",tolua_Cocos2d_CCActionEase_create00);  
  6.   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 plain  copy
 print ?
  1. /* 
  2. ** Lua binding: Cocos2d 
  3. ** Generated automatically by tolua++-1.0.92 on 08/30/12 12:11:53. 
  4. */  


工具在这个路径下: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 plain  copy
 print ?
  1. /************************************************************************/  
  2. /* 精灵工厂                                   */  
  3. /* 使用了简单工厂,但,不是工厂模式           */  
  4. /************************************************************************/  
  5. #ifndef __SPRITE_FACTORY_H__  
  6. #define __SPRITE_FACTORY_H__  
  7.   
  8. #include "cocos2d.h"  
  9.   
  10. using namespace cocos2d;  
  11.   
  12. class SpriteFactory  
  13. {  
  14. public:  
  15.     enum SpriteType  
  16.     {  
  17.         en_close,  
  18.         en_grossini,  
  19.         en_grossinis_sister,  
  20.         en_grossinis_sister2,  
  21.     };  
  22.   
  23.     static SpriteFactory* sharedSpriteFactory();  
  24.   
  25.     CCSprite* createSprite(CCLayer* mLayer, SpriteType enSpriteType);  
  26. private:  
  27.     static SpriteFactory* mFactory;  
  28. };  
  29.   
  30. #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的函数

        

根据这个规则,我要把publicprivate关键字去掉,还要把所有成员变量去掉,当然,多余的什么includeusing namespace都不要了,对了,枚举类型要保留。

于是,最后的pkg文件如下:

[cpp]  view plain  copy
 print ?
  1. class SpriteFactory  
  2. {  
  3.   
  4.     enum SpriteType  
  5.     {  
  6.         en_close,  
  7.         en_grossini,  
  8.         en_grossinis_sister,  
  9.         en_grossinis_sister2,  
  10.     };  
  11.   
  12.     static SpriteFactory* sharedSpriteFactory();  
  13.   
  14.     CCSprite* createSprite(CCLayer* mLayer, SpriteType enSpriteType);  
  15. };  


 

好简洁,我喜欢。

         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 plain  copy
 print ?
  1. /* method: sharedSpriteFactory of class  SpriteFactory */  
  2. #ifndef TOLUA_DISABLE_tolua_Cocos2d_SpriteFactory_sharedSpriteFactory00  
  3. static int tolua_Cocos2d_SpriteFactory_sharedSpriteFactory00(lua_State* tolua_S)  
  4. {  
  5. #ifndef TOLUA_RELEASE  
  6.     tolua_Error tolua_err;  
  7.     if (  
  8.         !tolua_isusertable(tolua_S,1,"SpriteFactory",0,&tolua_err) ||  
  9.         !tolua_isnoobj(tolua_S,2,&tolua_err)  
  10.         )  
  11.         goto tolua_lerror;  
  12.     else  
  13. #endif  
  14.     {  
  15.         {  
  16.             SpriteFactory* tolua_ret = (SpriteFactory*)  SpriteFactory::sharedSpriteFactory();  
  17.             tolua_pushusertype(tolua_S,(void*)tolua_ret,"SpriteFactory");  
  18.         }  
  19.     }  
  20.     return 1;  
  21. #ifndef TOLUA_RELEASE  
  22. tolua_lerror:  
  23.     tolua_error(tolua_S,"#ferror in function 'sharedSpriteFactory'.",&tolua_err);  
  24.     return 0;  
  25. #endif  
  26. }  
  27. #endif //#ifndef TOLUA_DISABLE  

知道我想说什么吧?既然它已经能生成自定类的这些代码了,那还怕什么。

现在回到生成LuaCocos2d.cpp的步骤,打开Cocos2d.pkg文件,把其它所有无关的类删除~!变成这样:

[cpp]  view plain  copy
 print ?
  1. <span style="font-size:14px;">$#include "LuaCocos2d.h"  
  2.   
  3. $pfile " SpriteFactory.pkg"  
  4. </span>  


 

然后继续输入命令,生成LuaCocos2d.cpp文件。

于是,这样生成的文件就只有我们自定义类的声明代码了:

[cpp]  view plain  copy
 print ?
  1. <span style="font-size:14px;">#include "LuaCocos2d.h"  
  2.   
  3. /* function to register type */  
  4. static void tolua_reg_types (lua_State* tolua_S)  
  5. {  
  6. #ifndef Mtolua_typeid  
  7. #define Mtolua_typeid(L,TI,T)  
  8. #endif  
  9.  tolua_usertype(tolua_S,"CCSprite");  
  10.  Mtolua_typeid(tolua_S,typeid(CCSprite), "CCSprite");  
  11.  tolua_usertype(tolua_S,"CCLayer");  
  12.  Mtolua_typeid(tolua_S,typeid(CCLayer), "CCLayer");  
  13.  tolua_usertype(tolua_S,"SpriteFactory");  
  14.  Mtolua_typeid(tolua_S,typeid(SpriteFactory), "SpriteFactory");  
  15. }  
  16.   
  17. /* method: sharedSpriteFactory of class  SpriteFactory */  
  18. #ifndef TOLUA_DISABLE_tolua_Cocos2d_SpriteFactory_sharedSpriteFactory00  
  19. static int tolua_Cocos2d_SpriteFactory_sharedSpriteFactory00(lua_State* tolua_S)  
  20. {  
  21. #ifndef TOLUA_RELEASE  
  22.  tolua_Error tolua_err;  
  23.  if (  
  24.      !tolua_isusertable(tolua_S,1,"SpriteFactory",0,&tolua_err) ||  
  25.      !tolua_isnoobj(tolua_S,2,&tolua_err)  
  26.  )  
  27.   goto tolua_lerror;  
  28.  else  
  29. #endif  
  30.  {  
  31.   {  
  32.    SpriteFactory* tolua_ret = (SpriteFactory*)  SpriteFactory::sharedSpriteFactory();  
  33.     tolua_pushusertype(tolua_S,(void*)tolua_ret,"SpriteFactory");  
  34.   }  
  35.  }  
  36.  return 1;  
  37. #ifndef TOLUA_RELEASE  
  38.  tolua_lerror:  
  39.  tolua_error(tolua_S,"#ferror in function 'sharedSpriteFactory'.",&tolua_err);  
  40.  return 0;  
  41. #endif  
  42. }  
  43. #endif //#ifndef TOLUA_DISABLE  
  44.   
  45. /* method: createSprite of class  SpriteFactory */  
  46. #ifndef TOLUA_DISABLE_tolua_Cocos2d_SpriteFactory_createSprite00  
  47. static int tolua_Cocos2d_SpriteFactory_createSprite00(lua_State* tolua_S)  
  48. {  
  49. #ifndef TOLUA_RELEASE  
  50.  tolua_Error tolua_err;  
  51.  if (  
  52.      !tolua_isusertype(tolua_S,1,"SpriteFactory",0,&tolua_err) ||  
  53.      !tolua_isusertype(tolua_S,2,"CCLayer",0,&tolua_err) ||  
  54.      !tolua_isnumber(tolua_S,3,0,&tolua_err) ||  
  55.      !tolua_isnoobj(tolua_S,4,&tolua_err)  
  56.  )  
  57.   goto tolua_lerror;  
  58.  else  
  59. #endif  
  60.  {  
  61.   SpriteFactory* self = (SpriteFactory*)  tolua_tousertype(tolua_S,1,0);  
  62.   CCLayer* mLayer = ((CCLayer*)  tolua_tousertype(tolua_S,2,0));  
  63.   SpriteFactory::SpriteType enSpriteType = ((SpriteFactory::SpriteType) (int)  tolua_tonumber(tolua_S,3,0));  
  64. #ifndef TOLUA_RELEASE  
  65.   if (!self) tolua_error(tolua_S,"invalid 'self' in function 'createSprite'", NULL);  
  66. #endif  
  67.   {  
  68.    CCSprite* tolua_ret = (CCSprite*)  self->createSprite(mLayer,enSpriteType);  
  69.     tolua_pushusertype(tolua_S,(void*)tolua_ret,"CCSprite");  
  70.   }  
  71.  }  
  72.  return 1;  
  73. #ifndef TOLUA_RELEASE  
  74.  tolua_lerror:  
  75.  tolua_error(tolua_S,"#ferror in function 'createSprite'.",&tolua_err);  
  76.  return 0;  
  77. #endif  
  78. }  
  79. #endif //#ifndef TOLUA_DISABLE  
  80.   
  81. /* Open function */  
  82. TOLUA_API int tolua_Cocos2d_open (lua_State* tolua_S)  
  83. {  
  84.  tolua_open(tolua_S);  
  85.  tolua_reg_types(tolua_S);  
  86.  tolua_module(tolua_S,NULL,0);  
  87.  tolua_beginmodule(tolua_S,NULL);  
  88.   tolua_cclass(tolua_S,"SpriteFactory","SpriteFactory","",NULL);  
  89.   tolua_beginmodule(tolua_S,"SpriteFactory");  
  90.    tolua_constant(tolua_S,"en_close",SpriteFactory::en_close);  
  91.    tolua_constant(tolua_S,"en_grossini",SpriteFactory::en_grossini);  
  92.    tolua_constant(tolua_S,"en_grossinis_sister",SpriteFactory::en_grossinis_sister);  
  93.    tolua_constant(tolua_S,"en_grossinis_sister2",SpriteFactory::en_grossinis_sister2);  
  94.    tolua_function(tolua_S,"sharedSpriteFactory",tolua_Cocos2d_SpriteFactory_sharedSpriteFactory00);  
  95.    tolua_function(tolua_S,"createSprite",tolua_Cocos2d_SpriteFactory_createSprite00);  
  96.   tolua_endmodule(tolua_S);  
  97.  tolua_endmodule(tolua_S);  
  98.  return 1;  
  99. }  
  100.   
  101.   
  102. #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 501  
  103.  TOLUA_API int luaopen_Cocos2d (lua_State* tolua_S) {  
  104.  return tolua_Cocos2d_open(tolua_S);  
  105. };  
  106. #endif  
  107. </span>  


 

这就没有问题了,我们不要替换它原有LuaCocos2d.cpp文件,而是依葫芦画瓢地把我们生成的LuaCocos2d.cpp文件里新增的内容拷到原有的文件里。这样编译就基本不会报错了,即使报错,也只是小范围报错,顶多几个,不会出现上百个错误吓死人了。

 

然后编译,运行,没有问题了。

我写了一个lua文件测试我的功能:

[plain]  view plain  copy
 print ?
  1. local function createLayer()  
  2.     local layer = CCLayer:create();  
  3.       
  4.     local sprite = SpriteFactory:sharedSpriteFactory():createSprite(layer, SpriteFactory.en_grossini);  
  5.     sprite:setPosition(200, 200);  
  6.     return layer;  
  7. end  
  8.   
  9. local scene = CCScene:create();  
  10. scene:addChild(createLayer());  
  11. CCDirector:sharedDirector():replaceScene(scene);  



 

运行效果:

 

完美~!噗,自己赞自己。


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值