在最近的工程中,由于游戏中设置场景的东西很少,所以决定没必要写成一个场景,并且写成场景后有切换场景时出现的释放资源问题,最终决定用模态弹窗来写。同样,我们先看看最终效果:
前面亮的就是弹出框,后面的就是模态化的背景。
关于模态的做法以及屏蔽下层按钮的做法,建议大家先去看泰然网的这篇文章,里面讲得非常详细并且附带源码:http://www.ityran.com/archives/4854
这里我们主要讲关于CCControlSwitch的问题,也就是图片中这样的按钮的问题。
按照以前弹出框的做法,弹出框上的按钮成功响应并且下层菜单被屏蔽,但是我发现CCControlSwitch按钮竟然也无法被响应,因为之前我们的“设置”是写成一个场景的,在场景中,同样的CCControlSwitch是能够被响应的,所以肯定不是他本身的问题,也就是说,它不能被响应的原因是被屏蔽掉了,因为在调试的时候我也试过调用CCControlSwitch的回调函数,发现没有响应,所以我确定它的确被屏蔽掉了,现在我们来看一下源码“
// 我把设置位置和设置Tag什么的都注释掉,大家只需要关心重点即可
void HSet::initSetMenu()
{
// 这里手动设置触摸优先级,默认菜单是-128,只要比-128大的值(-127),都可以屏蔽下层菜单的触摸,
// 这里设置为-128类似于addChild()函数中的zOrder,虽然值一样,但是之后添加的都将覆盖之前的。
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, -128, true);
// 设置透明度,需要继承CCLayerColor而不是CCLayer
this->setOpacity(150);
CCSize visibleSize = PublicMethod::getVisibleSize();
CCPoint origin = PublicMethod::getOrigin();
// 这是弹出对话框
CCSprite* setDialog = CCSprite::create("/Set/NB_SetDialog.png");
//setDialog->setPosition(ccp(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
// 音乐和音效的图标
CCSprite* music_Icon = CCSprite::create("/Set/NB_Music_Icon.png");
CCSprite* effect_Icon = CCSprite::create("/Set/NB_Effect_Icon.png");
//music_Icon->setPosition(ccp(music_Icon->getContentSize().width, setDialog->getContentSize().height/2));
//effect_Icon->setPosition(ccp(effect_Icon->getContentSize().width, setDialog->getContentSize().height/2 - effect_Icon->getContentSize().height - SET_MENU_ITEM_OFFSET));
setDialog->addChild(music_Icon, 0);
setDialog->addChild(effect_Icon, 0);
// “用户协议”按钮和“开发人员”按钮
CCMenuItemImage* userAgreementButton = CCMenuItemImage::create("/Set/NB_UserAgreement_Normal.png", "/Set/NB_UserAgreement_Select.png", this, NULL);
CCMenuItemImage* producerButton = CCMenuItemImage::create("/Set/NB_Producer_Normal.png", "/Set/NB_Producer_Select.png", this, NULL);
CCMenuItemImage *setBackButton = CCMenuItemImage::create("/Shop/NB_CardBack_Normal.png", "/Shop/NB_CardBack_Select.png", this, menu_selector(HSet::backIsPressed));
//userAgreementButton->setTag(set_itemUserAgreementTag);
//producerButton->setTag(set_itemProducerTag);
//setBackButton->setTag(set_itemBackTag);
//userAgreementButton->setPosition(ccp(userAgreementButton->getContentSize().width/2 + SET_MENU_ITEM_OFFSET, 0));
//producerButton->setPosition(ccp(producerButton->getContentSize().width/2 + SET_MENU_ITEM_OFFSET, -producerButton->getContentSize().height - SET_MENU_ITEM_OFFSET/2));
//setBackButton->setPosition(ccp(setDialog->getContentSize().width/2 - setBackButton->getContentSize().width + SET_BACK_OFFSET_X, setDialog->getContentSize().height/2 - setBackButton->getContentSize().height + SET_BACK_OFFSET_Y));
CCMenu* set_menu = CCMenu::create(producerButton, userAgreementButton, setBackButton, NULL);
//set_menu->setPosition(ccp(setDialog->getContentSize().width/2, setDialog->getContentSize().height/2));
setDialog->addChild(set_menu, 0, set_menuTag);
// 设置音乐和音效的开关按钮,这里是重点
// 我在开关按钮下面添加了一个白底,不重要但是这样比较好看。
CCSprite* musicSwitcherBoard = CCSprite::create("/Set/NB_Switch_Board.png");
//musicSwitcherBoard->setPosition(ccp(music_Icon->getContentSize().width/2 + musicSwitcherBoard->getContentSize().width, music_Icon->getPositionY()));
//musicSwitcherBoard->setTag(musicSwitcherBoardTag);
setDialog->addChild(musicSwitcherBoard, 0);
// 这里我们就在添加音乐的开关按钮
CCControlSwitch *musicSwitcher = CCControlSwitch::create(
CCSprite::create("/Set/NB_Switch_Mask.png"), CCSprite::create("/Set/NB_Switch_On.png"),
CCSprite::create("/Set/NB_Switch_Off.png"), CCSprite::create("/Set/NB_Set_Cursor.png"));
//musicSwitcher->setPosition(ccp(musicSwitcherBoard->getContentSize().width/2, musicSwitcherBoard->getContentSize().height/2));
//musicSwitcher->setTag(musicSwitcherTag);
musicSwitcherBoard->addChild(musicSwitcher,0);
// 这里添加音效的开关按钮,和音乐一样,我就不写了
// ..............................................
// 再把整个对话框添加上去
this->addChild(setDialog, 0, setDialogTag);
}
这样我们的初版弹出设定框就写好了,效果就和之前那个图一样,但是会发现,CCControlSwitch不能响应。于是经过各种跟踪代码调试等方法我找到了问题的所在,也就是上面所说的被屏蔽的问题。即:CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, -128, true);这句代码搞的鬼。
大体来讲就是因为CCControlSwitch是继承自CCControl,CCControl又是继承自CCLayer,而CCMenuItem是继承自CCNode,两个的触摸级别本来就不是一样的,大家可以分别获取一下它们的触摸级别,CCControlSwitch在设置之前是1,而CCMenuItem是-128,所以要分开设置。单步调试的话还有更细节的东西,这里我就不细讲了,直接给出解决方案:
在musicSwitcher创建后再手动设置其优先级,同样是-128
musicSwitcher->setTouchPriority(-128);
这样CCControlSwitch就能够被正常响应,但之后还会报一个错误,我的弹出框是从主界面弹出的,在我点击返回以后,再点击主界面的任何一个地方,都会报一个CCNode的错误,出现这种错误就是因为弹出层返回时没有销毁CCControlSwitch,虽然在我的代码里当设定选单返回后会调用removeFromParent();这样一句函数,但依然是不够的,我们还需要调用tem_musicSwitcher->removeFromParentAndCleanup(true);这样一句函数来手动销毁CCControlSwitch。
OK,这样我们就完成了一个带CCControlSwitch的弹出设定框,大家还可以给弹出设定框写一些特效来丰富它,至于特效怎么写,就留在下一次博客写吧。