本人使用的是cocos2d-x2.1.4 版本,cocosbuilder则为3.0版本 在使用lua对ccbi文件解析时需要cocosbuilder中勾选上js controller选项,此时基类不是custom类型了,这样的话自己在C++里面扩展的控件就不能使用了,不过我们也可不需要勾选js controller照样可以让脚本解析得了ccbi 文件
此时需要修改ccbreader源代码:
第一处:
CCNode* CCBReader::readNodeGraphFromData(CCData *pData, CCObject *pOwner, const CCSize &parentSize)
{
mData = pData;
CC_SAFE_RETAIN(mData);
mBytes = mData->getBytes();
mCurrentByte = 0;
mCurrentBit = 0;
mOwner = pOwner;
CC_SAFE_RETAIN(mOwner);
mActionManager->setRootContainerSize(parentSize);
mActionManager->mOwner = mOwner;
mOwnerOutletNodes = new CCArray();
mOwnerCallbackNodes = new CCArray();
CCDictionary* animationManagers = CCDictionary::create();
CCNode *pNodeGraph = readFileWithCleanUp(true, animationManagers);
if (pNodeGraph && mActionManager->getAutoPlaySequenceId() != -1 && !jsControlled)
{
// Auto play animations
mActionManager->runAnimationsForSequenceIdTweenDuration(mActionManager->getAutoPlaySequenceId(), 0);
}
// Assign actionManagers to userObject
// if(jsControlled) { //修改:注释掉if判断直接执行if里面的内容
mNodesWithAnimationManagers = new CCArray();
mAnimationManagersForNodes = new CCArray();
// }
CCDictElement* pElement = NULL;
CCDICT_FOREACH(animationManagers, pElement)
{
CCNode* pNode = (CCNode*)pElement->getIntKey();
CCBAnimationManager* manager = (CCBAnimationManager*)animationManagers->objectForKey((intptr_t)pNode);
pNode->setUserObject(manager);
// if (jsControlled) //修改:注释掉if判断直接执行if里面的内容
{
mNodesWithAnimationManagers->addObject(pNode);
mAnimationManagersForNodes->addObject(manager);
}
}
return pNodeGraph;
}
第二处:
CCNode * CCBReader::readNodeGraph(CCNode * pParent) {
/* Read class name. */
std::string className = this->readCachedString();
std::string jsControlledName;
if(jsControlled) {
jsControlledName = this->readCachedString();
}
// Read assignment type and name
int memberVarAssignmentType = this->readInt(false);
std::string memberVarAssignmentName;
if(memberVarAssignmentType != kCCBTargetTypeNone) {
memberVarAssignmentName = this->readCachedString();
}
CCNodeLoader *ccNodeLoader = this->mCCNodeLoaderLibrary->getCCNodeLoader(className.c_str());
if (! ccNodeLoader)
{
CCLog("no corresponding node loader for %s", className.c_str());
return NULL;
}
CCNode *node = ccNodeLoader->loadCCNode(pParent, this);
// Set root node
if (! mActionManager->getRootNode())
{
mActionManager->setRootNode(node);
}
// Assign controller
if(/*jsControlled &&*/ node == mActionManager->getRootNode()) //修改注释掉/*jsControlled &&*/
{
mActionManager->setDocumentControllerName(jsControlledName);
}
// Read animated properties
CCDictionary *seqs = CCDictionary::create();
mAnimatedProps = new set<string>();
int numSequence = readInt(false);
for (int i = 0; i < numSequence; ++i)
{
int seqId = readInt(false);
CCDictionary *seqNodeProps = CCDictionary::create();
int numProps = readInt(false);
for (int j = 0; j < numProps; ++j)
{
CCBSequenceProperty *seqProp = new CCBSequenceProperty();
seqProp->autorelease();
seqProp->setName(readCachedString().c_str());
seqProp->setType(readInt(false));
mAnimatedProps->insert(seqProp->getName());
int numKeyframes = readInt(false);
for (int k = 0; k < numKeyframes; ++k)
{
CCBKeyframe *keyframe = readKeyframe(seqProp->getType());
seqProp->getKeyframes()->addObject(keyframe);
}
seqNodeProps->setObject(seqProp, seqProp->getName());
}
seqs->setObject(seqNodeProps, seqId);
}
if (seqs->count() > 0)
{
mActionManager->addNode(node, seqs);
}
// Read properties
ccNodeLoader->parseProperties(node, pParent, this);
bool isCCBFileNode = (NULL == dynamic_cast<CCBFile*>(node)) ? false : true;
// Handle sub ccb files (remove middle node)
if (isCCBFileNode)
{
CCBFile *ccbFileNode = (CCBFile*)node;
CCNode *embeddedNode = ccbFileNode->getCCBFileNode();
embeddedNode->setPosition(ccbFileNode->getPosition());
embeddedNode->setRotation(ccbFileNode->getRotation());
embeddedNode->setScaleX(ccbFileNode->getScaleX());
embeddedNode->setScaleY(ccbFileNode->getScaleY());
embeddedNode->setTag(ccbFileNode->getTag());
embeddedNode->setVisible(true);
//embeddedNode->ignoreAnchorPointForPosition(ccbFileNode->isIgnoreAnchorPointForPosition());
mActionManager->moveAnimationsFromNode(ccbFileNode, embeddedNode);
ccbFileNode->setCCBFileNode(NULL);
node = embeddedNode;
}
#ifdef CCB_ENABLE_JAVASCRIPT
/*
if (memberVarAssignmentType && memberVarAssignmentName && ![memberVarAssignmentName isEqualToString:@""])
{
[[JSCocoa sharedController] setObject:node withName:memberVarAssignmentName];
}*/
#else
if (memberVarAssignmentType != kCCBTargetTypeNone)
{
if(!jsControlled)
{
CCObject * target = NULL;
if(memberVarAssignmentType == kCCBTargetTypeDocumentRoot)
{
target = mActionManager->getRootNode();
}
else if(memberVarAssignmentType == kCCBTargetTypeOwner)
{
target = this->mOwner;
}
if(target != NULL)
{
CCBMemberVariableAssigner * targetAsCCBMemberVariableAssigner = dynamic_cast<CCBMemberVariableAssigner *>(target);
bool assigned = false;
if (memberVarAssignmentType != kCCBTargetTypeNone)
{
if(targetAsCCBMemberVariableAssigner != NULL) {
assigned = targetAsCCBMemberVariableAssigner->onAssignCCBMemberVariable(target, memberVarAssignmentName.c_str(), node);
}
if(!assigned && this->mCCBMemberVariableAssigner != NULL) {
assigned = this->mCCBMemberVariableAssigner->onAssignCCBMemberVariable(target, memberVarAssignmentName.c_str(), node);
}
}
}
}
//else //修改注释掉else判断
{
if(memberVarAssignmentType == kCCBTargetTypeDocumentRoot) {
mActionManager->addDocumentOutletName(memberVarAssignmentName);
mActionManager->addDocumentOutletNode(node);
} else {
mOwnerOutletNames.push_back(memberVarAssignmentName);
mOwnerOutletNodes->addObject(node);
}
}
}
// Assign custom properties.
if (ccNodeLoader->getCustomProperties()->count() > 0) {
bool customAssigned = false;
if(!jsControlled)
{
CCObject * target = node;
if(target != NULL)
{
CCBMemberVariableAssigner * targetAsCCBMemberVariableAssigner = dynamic_cast<CCBMemberVariableAssigner *>(target);
if(targetAsCCBMemberVariableAssigner != NULL) {
CCDictionary* pCustomPropeties = ccNodeLoader->getCustomProperties();
CCDictElement* pElement;
CCDICT_FOREACH(pCustomPropeties, pElement)
{
customAssigned = targetAsCCBMemberVariableAssigner->onAssignCCBCustomProperty(target, pElement->getStrKey(), (CCBValue*)pElement->getObject());
if(!customAssigned && this->mCCBMemberVariableAssigner != NULL)
{
customAssigned = this->mCCBMemberVariableAssigner->onAssignCCBCustomProperty(target, pElement->getStrKey(), (CCBValue*)pElement->getObject());
}
}
}
}
}
}
#endif // CCB_ENABLE_JAVASCRIPT
delete mAnimatedProps;
mAnimatedProps = NULL;
/* Read and add children. */
int numChildren = this->readInt(false);
for(int i = 0; i < numChildren; i++) {
CCNode * child = this->readNodeGraph(node);
node->addChild(child);
}
// FIX ISSUE #1860: "onNodeLoaded will be called twice if ccb was added as a CCBFile".
// If it's a sub-ccb node, skip notification to CCNodeLoaderListener since it will be
// notified at LINE #734: CCNode * child = this->readNodeGraph(node);
if (!isCCBFileNode) {
// Call onNodeLoaded
CCNodeLoaderListener * nodeAsCCNodeLoaderListener = dynamic_cast<CCNodeLoaderListener *>(node);
if(nodeAsCCNodeLoaderListener != NULL) {
nodeAsCCNodeLoaderListener->onNodeLoaded(node, ccNodeLoader);
} else if(this->mCCNodeLoaderListener != NULL) {
this->mCCNodeLoaderListener->onNodeLoaded(node, ccNodeLoader);
}
}
return node;
}
第三处:
bool CCBReader::readCallbackKeyframesForSeq(CCBSequence* seq) {
int numKeyframes = readInt(false);
if(!numKeyframes) return true;
CCBSequenceProperty* channel = new CCBSequenceProperty();
channel->autorelease();
for(int i = 0; i < numKeyframes; ++i) {
float time = readFloat();
std::string callbackName = readCachedString();
int callbackType = readInt(false);
CCArray* value = CCArray::create();
value->addObject(CCString::create(callbackName));
value->addObject(CCString::createWithFormat("%d", callbackType));
CCBKeyframe* keyframe = new CCBKeyframe();
keyframe->autorelease();
keyframe->setTime(time);
keyframe->setValue(value);
// if(jsControlled) { //修改注释掉这里的if条件
string callbackIdentifier;
mActionManager->getKeyframeCallbacks()->addObject(CCString::createWithFormat("%d:%s",callbackType, callbackName.c_str()));
// }
channel->getKeyframes()->addObject(keyframe);
}
seq->setCallbackChannel(channel);
return true;
}
---------------补充 ----------------------------------------
上面只是确保你能够解析不勾选js controller 也能解析ccbi文件,接下来还需要改一下按钮绑定变量和回调函数的代码
还要修改CCBAnimationManager文件
Sequence* CCBAnimationManager::actionForCallbackChannel(CCBSequenceProperty* channel) {
float lastKeyframeTime = 0;
Vector<FiniteTimeAction*> actions;
auto& keyframes = channel->getKeyframes();
ssize_t numKeyframes = keyframes.size();
for (long i = 0; i < numKeyframes; ++i)
{
CCBKeyframe *keyframe = keyframes.at(i);
float timeSinceLastKeyframe = keyframe->getTime() - lastKeyframeTime;
lastKeyframeTime = keyframe->getTime();
if(timeSinceLastKeyframe > 0) {
actions.pushBack(DelayTime::create(timeSinceLastKeyframe));
}
auto& keyVal = keyframe->getValue().asValueVector();
std::string selectorName = keyVal[0].asString();
CCBReader::TargetType selectorTarget = (CCBReader::TargetType)keyVal[1].asInt();
//if(_jsControlled) { ---------这里
std::stringstream callbackName;
callbackName << static_cast<int>(selectorTarget);
callbackName << ":" + selectorName;
auto callback = _keyframeCallFuncs.at(callbackName.str());
if (nullptr != callback)
{
CallFunc* callbackClone = callback->clone();
if (callbackClone != nullptr)
{
actions.pushBack(callbackClone);
}
}
//}
//else ---------这里
{
Ref* target = nullptr;
if(selectorTarget == CCBReader::TargetType::DOCUMENT_ROOT)
target = _rootNode;
else if (selectorTarget == CCBReader::TargetType::OWNER)
target = _owner;
if(target != nullptr)
{
if(selectorName.length() > 0)
{
SEL_CallFuncN selCallFunc = 0;
CCBSelectorResolver* targetAsCCBSelectorResolver = dynamic_cast<CCBSelectorResolver *>(target);
if(targetAsCCBSelectorResolver != nullptr)
{
selCallFunc = targetAsCCBSelectorResolver->onResolveCCBCCCallFuncSelector(target, selectorName.c_str ());
}
if(selCallFunc == 0)
{
CCLOG("Skipping selector '%s' since no CCBSelectorResolver is present.", selectorName.c_str());
}
else
{
auto savedTarget = std::make_shared<Vector<Ref*>>();
savedTarget->pushBack(target);
auto callback = CallFuncN::create([savedTarget, selCallFunc](Node* sender){
auto t = savedTarget->at(0);
(t->*selCallFunc)(sender);
});
actions.pushBack(callback);
}
}
else
{
CCLOG("Unexpected empty selector.");
}
}
}
}
if(actions.size() < 1) return nullptr;
return Sequence::create(actions);
}
还要修改CCNodeLoader文件
BlockData * NodeLoader::parsePropTypeBlock(Node * pNode, Node * pParent, CCBReader * ccbReader)
{
std::string selectorName = ccbReader->readCachedString();
CCBReader::TargetType selectorTarget = static_cast<CCBReader::TargetType>(ccbReader->readInt(false));
if(selectorTarget != CCBReader::TargetType::NONE)
{
Ref* target = NULL;
if(!ccbReader->isJSControlled())
{
if(selectorTarget == CCBReader::TargetType::DOCUMENT_ROOT)
{
target = ccbReader->getAnimationManager()->getRootNode();
}
else if(selectorTarget == CCBReader::TargetType::OWNER)
{
target = ccbReader->getOwner();
}
if(target != NULL)
{
if(selectorName.length() > 0)
{
SEL_MenuHandler selMenuHandler = 0;
CCBSelectorResolver * targetAsCCBSelectorResolver = dynamic_cast<CCBSelectorResolver *>(target);
if(targetAsCCBSelectorResolver != NULL)
{
selMenuHandler = targetAsCCBSelectorResolver->onResolveCCBCCMenuItemSelector(target, selectorName.c_str());
}
if(selMenuHandler == 0)
{
CCBSelectorResolver * ccbSelectorResolver = ccbReader->getCCBSelectorResolver();
if(ccbSelectorResolver != NULL)
{
selMenuHandler = ccbSelectorResolver->onResolveCCBCCMenuItemSelector(target, selectorName.c_str());
}
}
if(selMenuHandler == 0) {
CCLOG("Skipping selector '%s' since no CCBSelectorResolver is present.", selectorName.c_str());
} else {
BlockData * blockData = new BlockData();
blockData->mSELMenuHandler = selMenuHandler;
blockData->_target = target;
return blockData;
}
} else {
CCLOG("Unexpected empty selector.");
}
} else {
CCLOG("Unexpected NULL target for selector.");
}
}
//else
{
if (selectorTarget == CCBReader::TargetType::DOCUMENT_ROOT)
{
ccbReader->addDocumentCallbackNode(pNode);
ccbReader->addDocumentCallbackName(selectorName);
// Since there isn't a Control::EventType::NONE, add a TOUCH_DOWN type as a placeholder.
ccbReader->addDocumentCallbackControlEvents(Control::EventType::TOUCH_DOWN);
}
else if (selectorTarget == CCBReader::TargetType::OWNER)
{
ccbReader->addOwnerCallbackNode(pNode);
ccbReader->addOwnerCallbackName(selectorName);
// Since there isn't a Control::EventType::NONE, add a TOUCH_DOWN type as a placeholder.
ccbReader->addOwnerCallbackControlEvents(Control::EventType::TOUCH_DOWN);
}
}
}
return NULL;
}
BlockControlData * NodeLoader::parsePropTypeBlockControl(Node * pNode, Node * pParent, CCBReader * ccbReader)
{
std::string selectorName = ccbReader->readCachedString();
CCBReader::TargetType selectorTarget = static_cast<CCBReader::TargetType>(ccbReader->readInt(false));
int controlEvents = ccbReader->readInt(false);
if(selectorTarget != CCBReader::TargetType::NONE)
{
if(!ccbReader->isJSControlled())
{
Ref* target = NULL;
if(selectorTarget == CCBReader::TargetType::DOCUMENT_ROOT)
{
target = ccbReader->getAnimationManager()->getRootNode();
}
else if(selectorTarget == CCBReader::TargetType::OWNER)
{
target = ccbReader->getOwner();
}
if(target != NULL)
{
if(selectorName.length() > 0)
{
Control::Handler selControlHandler = 0;
CCBSelectorResolver * targetAsCCBSelectorResolver = dynamic_cast<CCBSelectorResolver *>(target);
if(targetAsCCBSelectorResolver != NULL)
{
selControlHandler = targetAsCCBSelectorResolver->onResolveCCBCCControlSelector(target, selectorName.c_str());
}
if(selControlHandler == 0)
{
CCBSelectorResolver * ccbSelectorResolver = ccbReader->getCCBSelectorResolver();
if(ccbSelectorResolver != NULL)
{
selControlHandler = ccbSelectorResolver->onResolveCCBCCControlSelector(target, selectorName.c_str());
}
}
if(selControlHandler == 0)
{
CCLOG("Skipping selector '%s' since no CCBSelectorResolver is present.", selectorName.c_str());
}
else
{
BlockControlData * blockControlData = new BlockControlData();
blockControlData->mSELControlHandler = selControlHandler;
blockControlData->_target = target;
blockControlData->mControlEvents = (Control::EventType)controlEvents;
return blockControlData;
}
} else {
CCLOG("Unexpected empty selector.");
}
} else {
CCLOG("Unexpected NULL target for selector.");
}
}
//else
{
if(selectorTarget == CCBReader::TargetType::DOCUMENT_ROOT)
{
ccbReader->addDocumentCallbackNode(pNode);
ccbReader->addDocumentCallbackName(selectorName);
ccbReader->addDocumentCallbackControlEvents((Control::EventType)controlEvents);
}
else
{
ccbReader->addOwnerCallbackNode(pNode);
ccbReader->addOwnerCallbackName(selectorName);
ccbReader->addOwnerCallbackControlEvents((Control::EventType)controlEvents);
}
}
}
return NULL;
}
好了,修改这些地方就可以保证lua能够解析了,不明白的可以看看这些注释地方有什么异同点。