尊重原创作品,转载请标明:http://bbs.9ria.com/thread-262618-1-1.html
一个游戏打到一半尿点到了咋整?难道要憋着。。。这不科学啊!
好吧,把暂停游戏和恢复游戏的功能加进去吧,否则也太对不起观众了!
1.暂停功能的加入
再给游戏加个层叫ControlLayer,这个层包含了2个元素,暂停功能和分数显示功能。分数显示和本地存储在后面介绍。
我们先看看暂停功能是怎么加入的。
- //加入暂停按钮
- bool ControlLayer::init()
- {
- bool bRet=false;
- do
- {
- CC_BREAK_IF(!CCLayer::init());
-
- CCSize winSize=CCDirector::sharedDirector()->getWinSize();
-
- //加入PauseMenu
- CCSprite* normalPause=CCSprite::create(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("game_pause_nor.png"));
- CCSprite* pressedPause=CCSprite::create(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("game_pause_pressed.png"));
- pPauseItem=CCMenuItemImage::create();//创建CCMenuItem
- pPauseItem->initWithNormalSprite(normalPause,pressedPause,NULL,this,menu_selector(ControlLayer::menuPauseCallback));//载入双态图和回调函数
- pPauseItem->setPosition(ccp(normalPause->getContentSize().width/2+10,winSize.height-normalPause->getContentSize().height/2-10));
- CCMenu *menuPause=CCMenu::create(pPauseItem,NULL);//创建CCMenu,可以这么理解CCMenuItem是CCMenu的孩子
- menuPause->setPosition(CCPointZero);
- this->addChild(menuPause,101);
-
- bRet=true;
- } while (0);
-
- return bRet;
- }
复制代码
- //暂停按键的回调函数
- void ControlLayer::menuPauseCallback(CCObject* pSender)
- {
- if(!CCDirector::sharedDirector()->isPaused())//如果游戏处于正常状态
- {
- //更改为恢复按钮的双态
- pPauseItem->setNormalSpriteFrame(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("game_resume_nor.png"));
- pPauseItem->setSelectedSpriteFrame(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("game_resume_pressed.png"));
- CCDirector::sharedDirector()->pause();//暂停游戏,这是导演控制的
- }
- else//否则
- {
- //更改为暂停按钮的双态
- pPauseItem->setNormalSpriteFrame(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("game_pause_nor.png"));
- pPauseItem->setSelectedSpriteFrame(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("game_pause_pressed.png"));
- CCDirector::sharedDirector()->resume();//开麦拉!
- }
- }
复制代码
这里没有使用CCMenuItemToggle的原因是它没办法实现一个图案的两个状态(normal和pressed),所以这里我手动进行替换。
2.游戏暂停状态下的触摸问题
如果就这么完了,那也弱爆了。。。游戏的调试过程中发现了这么一个问题,当游戏暂停的时候,主角飞机仍然可以跟随触摸移动,这个bug就坑爹了,你可以在快挂掉的时候按下pause,把飞机挪到安全的位置,然后再按下resume,死不了了。。。
原来cocos2d-x在暂停CCScene之后触摸仍然是有效的,所以我们需要在暂停之后屏蔽触摸。
这个的解决方案主要是两种:
(1)使用CCLayer的setTouchEnabled方法,但是这样可能会引起程序的崩溃,因为系统在派发触摸事件时发现响应列表为空,会触发一个断言。
(2)写一个NoTouchLayer,在这个层里响应触摸并吞噬触摸操作,使比它游戏级低的无法接收到触摸分发。但是优先级又不能高于CCMenu,也就是-128,不然恢复按钮也会被屏蔽,导致游戏无法恢复,除非是同一优先级。使用方法就是addChild和removeChild。关于触摸事件和优先级,请移步:
http://bbs.9ria.com/thread-262595-1-1.html
,再次强调,触摸优先级和addChild的Z轴顺序无关。
- //NoTouchLayer.h
- class NoTouchLayer :
- public CCLayer
- {
- public:
- virtual bool init();
-
- // implement the "static node()" method manually
- LAYER_CREATE_FUNC(NoTouchLayer);
-
- virtual void registerWithTouchDispatcher();
-
- virtual bool ccTouchBegan (cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
- virtual void ccTouchMoved (cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
- virtual void ccTouchEnded (cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
- };
-
- //NoTouchLayer.cpp
- bool NoTouchLayer::init(){
- if (!CCLayer::init() )
- {
- return false;
- }
- setTouchEnabled(true);//设置触摸有效
- return true;
- }
-
- void NoTouchLayer::registerWithTouchDispatcher()
- {
- CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, -127 , true);//优先级低于-128(CCMenu),同时高于其他层(0),true表示吞噬触摸
- CCLayer::registerWithTouchDispatcher();
- }
-
- bool NoTouchLayer::ccTouchBegan (CCTouch *pTouch, CCEvent *pEvent)
- {
- return true;//返回true接收触摸
- }
-
- void NoTouchLayer::ccTouchMoved (CCTouch *pTouch, CCEvent *pEvent)
- {
- }
-
- void NoTouchLayer::ccTouchEnded (CCTouch *pTouch, CCEvent *pEvent)
- {
- }
复制代码
3.第三种暂停屏蔽触摸的方法
上面两种方法我都没有使用。因为游戏只有主角可以被触摸移动,所以在PlaneLayer中的MoveTo函数里,做如下判断:
- if(isAlive && !CCDirector::sharedDirector()->isPaused())
复制代码
这样就够了。如果游戏暂停就不让飞机移动。好像也没有什么问题。
效果图(暂停状态)