cocos2d-x解析ccb及绑定到lua

来源:互联网 发布:java可变长参数 数组 编辑:程序博客网 时间:2024/05/18 03:58

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

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

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

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

2.节点名字memberVarAssignmentName

    // Read assignment type and name    int memberVarAssignmentType = this->readInt(false);    std::string memberVarAssignmentName;    if(memberVarAssignmentType != kCCBTargetTypeNone) {        memberVarAssignmentName = this->readCachedString();    }
3.解析节点属性

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

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

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

    //-------------------binding lua    if (memberVarAssignmentName != "") {        ZGLuaUtils::bindCCBAssign(memberVarAssignmentName.c_str(), className.c_str(), node);    }    //-------------------binding lua------end
我们看下C++中ZGLuaUtils类代码

void ZGLuaUtils::bindCCBAssign(constchar* assignmentName, constchar *className, CCNode* node) {     lua_State *L = ((CCLuaEngine*)CCScriptEngineManager::sharedManager()->getScriptEngine())->getLuaStack()->getLuaState();     lua_getglobal(L, "GF_setCCBBind");       /**//* Push PARAMETERS to STACK */     tolua_pushstring(L, assignmentName);     tolua_pushusertype(L, node, className);     /**//* Call FUNCTION in LUA */      int iError;      iError = lua_pcall(L,    //VMachine                          2,    //Argument Count                          LUA_MULTRET,    //Return Value Count                          0);       if (iError)       {           constchar* errorInfo = lua_tostring(L, 1);         CCLOG("CCBReader::bindCCBAssign pcall FAILED, %s, %d", errorInfo, iError);     }       /**//* Check Return Value Types */ }

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

GV_CCBVars = nilfunction GF_setCCBBind(nodeKey, node)     CCBLOG ("binding.."..nodeKey)     GV_CCBVars[nodeKey] = nodeend

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

function LuaLayer:createLayer()     self:initForVars()     self.layer = CCBReader:nodeGraphFromFile(self.ccbiName)     self.ccbReader = GV_CCBReader     self.ccbReader:retain()     self:initUI()     local function sceneEventHandler( eventType )           if eventType == "enter" then              self:onPreEnter()           else              self:onPreExit()           end     end     self.layer:registerScriptHandler(sceneEventHandler)     return self.layerend-- init ccb varsfunction LuaLayer:initForVars( )      self.ccbVars = {}     self:initVarsForCCB()     GV_CCBVars = self.ccbVarsend
经过以上操作Lua中就能操作该节点拉!下面实现绑定控件的事件,也即注册控件事件 (如CCControlButton)
1)修改CCNodeLoader.h中的BlockCCControlData加上std::string mSelectorName;

struct BlockCCControlData {       SEL_CCControlHandler mSELCCControlHandler;       CCObject * mTarget;       std::string mSelectorName;       int mControlEvents;};
2)修改CCNodeLoader.cpp函数parsePropTypeBlockCCControl

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

#include "CCControlLoader.h"#include "ZGLuaUtils.h"void CCControlLoader::onHandlePropTypeBlockCCControl(CCNode * pNode, CCNode * pParent, constchar * pPropertyName, BlockCCControlData * pBlockCCControlData, CCBReader * pCCBReader) {     ZGLuaUtils::bindCCBFunctionForCCControl(pBlockCCControlData->mSelectorName.c_str(), "CCControlButton", pNode, false);}
我们看下C++中ZGLuaUtils类代码

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

    #include "CCScrollLayerButtonLoader.h"     voidCCNodeLoaderLibrary::registerDefaultCCNodeLoaders() {         this->registerCCNodeLoader("CCScrollLayerButton", CCScrollLayerButtonLoader::loader());     }

原创粉丝点击