cocos2d-x解析ccb及绑定到lua

cocos2d-x解析ccb及绑定到lua

CCB_SELECTORRESOLVER_CCCONTROL_GLUE  SEL_MenuHandler SEL_CallFuncN SEL_CCControlHandler


onResolveCCBCCMenuItemSelector

CCB_SELECTORRESOLVER_CALLFUNC_GLUE 

分类: cocos2d-x   541人阅读  评论(0)  收藏  举报

要点一:C++解析ccb主要是这几个文件

CCBReader.h/cpp、CCNodeLoaderLibrary.cpp、CCNodeLoader.h/cpp等 

CCBReader文件中的CCBReader::readNodeGraph方法是读取ccbi的节点(该方法应该看懂),该方法做的事有

1.读取该节点类型(自定义类型这里用到了)  
[cpp]  view plain copy
  1. /* Read class name. */  
  2. std::string className = this->readCachedString();  

2.节点名字memberVarAssignmentName

[cpp]  view plain copy
  1. // Read assignment type and name  
  2. int memberVarAssignmentType = this->readInt(false);  
  3. std::string memberVarAssignmentName;  
  4. if(memberVarAssignmentType != kCCBTargetTypeNone) {  
  5.     memberVarAssignmentName = this->readCachedString();  
  6. }  
3.解析节点属性

[cpp]  view plain copy
  1. ...  
  2. CCNodeLoader *ccNodeLoader = this->mCCNodeLoaderLibrary->getCCNodeLoader(className.c_str());  
  3. if (! ccNodeLoader)  
  4. {  
  5.     CCLog("no corresponding node loader for %s", className.c_str());  
  6.     returnNULL;  
  7. }  
  8. CCNode *node = ccNodeLoader->loadCCNode(pParent, this);  
  9. ...  
  10. // Read properties  
  11. ccNodeLoader->parseProperties(node, pParent, this);  
从上面3中可以得知mCCNodeLoaderLibrary为CCNodeLoaderLibrary.cpp类实例对象getCCNodeLoader(className.c_str())为获取对应的节点类型Loader实例对象。

要点二:把CCB原有控件及事件绑定到Lua中(CCControlButton)

在CCNode * CCBReader::readNodeGraph(CCNode * pParent)方法最后加上以下代码

[cpp]  view plain copy
  1. //-------------------binding lua  
  2. if (memberVarAssignmentName != "") {  
  3.     ZGLuaUtils::bindCCBAssign(memberVarAssignmentName.c_str(), className.c_str(), node);  
  4. }  
  5. //-------------------binding lua------end  
我们看下C++中ZGLuaUtils类代码

[cpp]  view plain copy
  1. void ZGLuaUtils::bindCCBAssign(constchar* assignmentName, constchar *className, CCNode* node) {  
  2.      lua_State *L = ((CCLuaEngine*)CCScriptEngineManager::sharedManager()->getScriptEngine())->getLuaStack()->getLuaState();  
  3.      lua_getglobal(L, "GF_setCCBBind");    
  4.      /**//* Push PARAMETERS to STACK */  
  5.      tolua_pushstring(L, assignmentName);  
  6.      tolua_pushusertype(L, node, className);  
  7.      /**//* Call FUNCTION in LUA */   
  8.      int iError;   
  9.      iError = lua_pcall(L,    //VMachine    
  10.                         2,    //Argument Count    
  11.                         LUA_MULTRET,    //Return Value Count    
  12.                         0);    
  13.      if (iError)    
  14.      {    
  15.          constchar* errorInfo = lua_tostring(L, 1);  
  16.          CCLOG("CCBReader::bindCCBAssign pcall FAILED, %s, %d", errorInfo, iError);  
  17.      }    
  18.      /**//* Check Return Value Types */   
  19. }  

上面调用 了Lua中的全局函数也即C++调用Lua拉,查看ZGCCBSupport.lua文件

[plain]  view plain copy
  1. GV_CCBVars = nil  
  2. function GF_setCCBBind(nodeKey, node)  
  3.      CCBLOG ("binding.."..nodeKey)  
  4.      GV_CCBVars[nodeKey] = node  
  5. end  

lua中具体实现调用节点控件见LuaLayer.lua文件

[plain]  view plain copy
  1. function LuaLayer:createLayer()  
  2.      self:initForVars()  
  3.      self.layer = CCBReader:nodeGraphFromFile(self.ccbiName)  
  4.      self.ccbReader = GV_CCBReader  
  5.      self.ccbReader:retain()  
  6.      self:initUI()  
  7.      local function sceneEventHandler( eventType )  
  8.            if eventType == "enter" then  
  9.               self:onPreEnter()  
  10.            else  
  11.               self:onPreExit()  
  12.            end  
  13.      end  
  14.      self.layer:registerScriptHandler(sceneEventHandler)  
  15.      return self.layer  
  16. end  
  17. -- init ccb vars  
  18. function LuaLayer:initForVars( )   
  19.      self.ccbVars = {}  
  20.      self:initVarsForCCB()  
  21.      GV_CCBVars = self.ccbVars  
  22. end  
经过以上操作Lua中就能操作该节点拉!下面实现绑定控件的事件,也即注册控件事件 (如CCControlButton)
1)修改CCNodeLoader.h中的BlockCCControlData加上std::string mSelectorName;

[cpp]  view plain copy
  1. struct BlockCCControlData {  
  2.        SEL_CCControlHandler mSELCCControlHandler;  
  3.        CCObject * mTarget;  
  4.        std::string mSelectorName;  
  5.        int mControlEvents;  
  6. };  
2)修改CCNodeLoader.cpp函数parsePropTypeBlockCCControl

[cpp]  view plain copy
  1. BlockCCControlData * CCNodeLoader::parsePropTypeBlockCCControl(CCNode * pNode, CCNode * pParent, CCBReader * pCCBReader) {  
  2.       //-----直接传出带selectorName的BlockData  
  3.       std::string selectorName = pCCBReader->readCachedString();  
  4.       // 在返回之前,要把下面这个玩意读出来,否则的话会造成读取数据的错位  
  5.       pCCBReader->readInt(false);        // for int selectorTarget  
  6.       pCCBReader->readInt(false);         // for int controlEvents  
  7.       if(selectorName.length() > 0) {  
  8.            BlockCCControlData *blockData = newBlockCCControlData();  
  9.            blockData->mSelectorName = selectorName;  
  10.            return blockData;  
  11.       }  
  12.       //-----直接传出带selectorName的BlockData---end  
  13.       return NULL;  
  14. }  
3)修改CCControlLoader.cpp中的事件函数onHandlePropTypeBlockCCControl

[cpp]  view plain copy
  1. #include "CCControlLoader.h"  
  2. #include "ZGLuaUtils.h"  
  3. void CCControlLoader::onHandlePropTypeBlockCCControl(CCNode * pNode, CCNode * pParent, constchar * pPropertyName, BlockCCControlData * pBlockCCControlData, CCBReader * pCCBReader) {  
  4.      ZGLuaUtils::bindCCBFunctionForCCControl(pBlockCCControlData->mSelectorName.c_str(), "CCControlButton", pNode, false);  
  5. }  
我们看下C++中ZGLuaUtils类代码

[cpp]  view plain copy
  1. void ZGLuaUtils::bindCCBFunctionForCCControl(constchar *selectorName, constchar *className, cocos2d::CCNode *node, bool isRegistForTouch) {  
  2.      lua_State *L = getLuaState();  
  3.      lua_getglobal(L, "GF_setCCBCallback");  
  4.      /**//* Push PARAMETERS to STACK */  
  5.      tolua_pushusertype(L, node, className);  
  6.      tolua_pushstring(L, selectorName);  
  7.      tolua_pushboolean(L, isRegistForTouch);  
  8.      /**//* Call FUNCTION in LUA */  
  9.      int iError;  
  10.      iError = lua_pcall(L,    //VMachine  
  11.                         3,    //Argument Count  
  12.                         LUA_MULTRET,    //Return Value Count  
  13.                         0);  
  14.      if (iError)  
  15.      {  
  16.           constchar* errorInfo = lua_tostring(L, 1);  
  17.           CCLOG("CCBReader::bindCCBFunctionForCCControl pcall FAILED, %s, %d", errorInfo, iError);  
  18.      }  
  19.      /**//* Check Return Value Types */  
  20. }  
上面调用 了Lua中的全局函数也即C++调用Lua拉,查看ZGCCBSupport.lua文件
[plain]  view plain copy
  1. function GF_setCCBCallback(node, callbackKey, isRegistForTouch)  
  2.      CCBLOG ("binding callback.."..callbackKey)  
  3.      local value = GV_CCBVars[callbackKey]  
  4.      if isRegistForTouch then  
  5.      -- registe for CCControlButton and others  
  6.           node:registerScriptTouchHandler(GV_CCBVars[callbackKey])  
  7.      else  
  8.      -- registe for CCMenuItems  
  9.           GF_dump(node, "node")  
  10.           GF_dump(callbackKey, "callbackKey")  
  11.           node:registerScriptTapHandler(GV_CCBVars[callbackKey])  
  12.      end  
  13. end  
上面取得了CCBI中事件名称对应到Lua中相同名称的方法再注册节点脚本事件,但是上面貌似完美但是CCControlButton默认没有registerScriptTapHandler 方法,所以node:registerScriptTapHandler(GV_CCBVars[callbackKey])还是有问题所以还要第4步
4)修改CCControlButton.h文件增加以下代码
[cpp]  view plain copy
  1. // add lua touch support  
  2. protected:  
  3.     int m_nScriptTapHandler;  
  4. public:  
  5.     virtualvoid registerScriptTapHandler(int nHandler);  
  6.     virtualvoid unregisterScriptTapHandler(void);  
  7.     int getScriptTapHandler() { returnm_nScriptTapHandler; };  
  8. / add lua touch support  
修改CCControlButton.cpp文件,增加以下代码
[cpp]  view plain copy
  1. #include "script_support/CCScriptSupport.h"  
  2. #include "ZGLuaUtils.h"  
  3. voidCCControlButton::registerScriptTapHandler(int nHandler)  
  4. {       
  5.      unregisterScriptTapHandler();  
  6.      m_nScriptTapHandler = nHandler;  
  7.      LUALOG("[LUA] Add CCMenuItem script handler: %d", m_nScriptTapHandler);  
  8. }  
  9.   
  10. voidCCControlButton::unregisterScriptTapHandler(void)  
  11. {  
  12.      if (m_nScriptTapHandler)  
  13.      {  
  14.          CCScriptEngineManager::sharedManager()->getScriptEngine()->removeScriptHandler(m_nScriptTapHandler);  
  15.          LUALOG("[LUA] Remove CCMenuItem script handler: %d", m_nScriptTapHandler);  
  16.          m_nScriptTapHandler = 0;  
  17.      }  
  18. }   
5)修改ZGToLua 加上以上二个方法以便在Lua中能访问(不能是tolua工具生成,参数是句柄而不是真正意义上的int)
说明:如果Lua在C++中注册回调函数。也即向C++的函数传的参是Lua函数,但C++函数形参却是int型(Lua函数的标号即句柄),在这里程序启动后,每注册一个回调则回调的函数标识是加1的,即句柄是自增长的int型 
上面已经实现在Lua中绑定事件即Lua中注册事件但还要在Lua中实现响应事件
6)修改CCControlButton.cpp文件
[cpp]  view plain copy
  1.    /**(i)在 CCControlButton::~CCControlButton()方法体内加上unregisterScriptTapHandler(); 
  2.     **(ii)在 ccTouchEnded方法实现调用注册的事件即加上以下代码 
  3.     **if (m_nScriptTapHandler != 0) { 
  4.     **     ZGLuaUtils::getLuaEngine()->executeControlButtonEvent(this); 
  5.     **} 
  6.     **/   
  7.    
  8.     void CCControlButton::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)  
  9.     {  
  10.          m_isPushed = false;  
  11.          setHighlighted(false);  
  12.       
  13.       
  14.          if (isTouchInside(pTouch))  
  15.          {  
  16.              sendActionsForControlEvents(CCControlEventTouchUpInside);  
  17.              if (m_nScriptTapHandler != 0) {  
  18.                  ZGLuaUtils::getLuaEngine()->executeControlButtonEvent(this);  
  19.              }  
  20.          }  
  21.          else  
  22.          {  
  23.              sendActionsForControlEvents(CCControlEventTouchUpOutside);          
  24.          }  
  25.     }  
7)修改CCLuaEngin.h/ccp 
[cpp]  view plain copy
  1. //修改.h文件增加以下代码  
  2. #include "cocos-ext.h"  
  3. virtual int executeControlButtonEvent(cocos2d::extension::CCControlButton *controlButton);  
  4.    
  5. //修改.cpp文件增加以下代码  
  6. int CCLuaEngine::executeControlButtonEvent(cocos2d::extension::CCControlButton *controlButton) {  
  7.     int nHandler = controlButton->getScriptTapHandler();  
  8.     if (!nHandler) return0;  
  9.   
  10.     m_stack->pushInt(controlButton->getTag());  
  11.     m_stack->pushCCObject(controlButton, "CCControlButton");  
  12.     returnm_stack->executeFunctionByHandler(nHandler, 2);  
  13. }  
要点三:把CCB自定义控件及事件绑定到Lua中(CCScrollLayerButton)
 1)CCLuaEngin.h/ccp 其它一些控件类会调用CCLuaEngin中的一些方法,而本类又是C++调用Lua堆栈,用处是处理控件和控件的事件响应
[cpp]  view plain copy
  1. //修改.h文件,加上以下代码  
  2. #include "CCScrollLayerButton.h"  
  3. virtual int executeScrollLayerButtonEvent(CCScrollLayerButton *scrollLayerButton);  
[cpp]  view plain copy
  1. //修改.cpp文件,加上以下代码  
  2. int CCLuaEngine::executeScrollLayerButtonEvent(CCScrollLayerButton *scrollLayerButton) {  
  3.     int nHandle = scrollLayerButton->getScriptTapHandler();  
  4.     if (!nHandle) return 0;  
  5.     m_stack->pushInt(scrollLayerButton->getTag());  
  6.     m_stack->pushCCObject(scrollLayerButton, "CCScrollLayerButton");  
  7.     return m_stack->executeFunctionByHandler(nHandle, 2);  
  8. }  
2)修改CCScrollLayerButton.h/cpp 。跟CCControlButton一样加上注册事件及删除事件及取得回调句柄
3)修改CCBReader.cpp  CCNode * CCBReader::readNodeGraph(CCNode * pParent)方法最后加上以下代码
[cpp]  view plain copy
  1. //-------------------binding lua  
  2. if (memberVarAssignmentName != "") {  
  3.      //CCScrollLayerButton特殊处理  
  4.      if (strcmp(className.c_str(), "CCScrollLayerButton") == 0) {  
  5.           vector<string> stringVec;  
  6.           ZGStringUtils::splitString(memberVarAssignmentName, "@", stringVec);  
  7.           string member = stringVec[0];  
  8.           string function = stringVec[1];  
  9.           //bind var name  
  10.           ZGLuaUtils::bindCCBAssign(member.c_str(), "CCScrollLayerButton", node);  
  11.           //bind function  
  12.           ZGLuaUtils::bindCCBFunctionForCCControl(function.c_str(), "CCScrollLayerButton", node, false);  
  13.      }else{  
  14.           ZGLuaUtils::bindCCBAssign(memberVarAssignmentName.c_str(), className.c_str(), node);  
  15.      }  
  16. }  
  17. //-------------------binding lua------end  
3)修改ZGToLua.cpp

bindCCBFunctionForCCControl方法调用lua中的方法ZGCCBSupport.lua 文件中的GF_setCCBCallback方法,而方法又调用了节点的node:registerScriptTapHandler(GV_CCBVars[callbackKey]), 因为Lua调用c++代码且是自定义控件所以ZGToLua中加入CCScrollLayerButton的registerScriptTapHandler方法
4)但是由上面要点一第3小点可得CCBReader还会解析控件的属性所以必须加上以下代码,当然也要在项目上加上CCScrollLayerButtonLoader.h文件

[cpp]  view plain copy
  1. #include "CCScrollLayerButtonLoader.h"  
  2.   
  3.  voidCCNodeLoaderLibrary::registerDefaultCCNodeLoaders() {  
  4.      this->registerCCNodeLoader("CCScrollLayerButton", CCScrollLayerButtonLoader::loader());  
  5.  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值