How to create your own game using Cocos2d-x and BlackBerry Native SDK

Game Lifecycle

GameLifeCycle

In this last and final step we will add the ability to pause and resume the game. It’s important to implement this for the correct handling of application lifecycle events. For example, when the game is pushed to the background, we need to stop doing everything in our game including rendering and audio playback. This is to ensure the game doesn’t consume resources when running in the background and cause battery drain.

24. In HelloWorldScene.h:

(a) Under public declarations add:

//Pause and Resume game methods - these are public so our AppDelegate can call them
void pauseGame();

void resumeGame();

(b) Under private declarations add :

//Pause status
bool _gamePaused;
//Pause/Resume menu items
cocos2d::CCMenuItemImage* _resumeMenuItem;
cocos2d::CCMenuItemImage* _pauseMenuItem;
cocos2d::CCMenuItemToggle* _pauseResumeToggleItem;

//Pause/Resume menu handler
void menuPauseResumeCallback(CCObject* sender);

25. In HelloWorldScene.cpp

(a) Under HelloWorld::init() add right before the schedule updateGame call:

//Initialize Pause/Resume and toggle menu item
_pauseMenuItem = CCMenuItemImage::create();
_pauseMenuItem->setNormalSpriteFrame(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("pause.png"));
_resumeMenuItem = CCMenuItemImage::create();
_resumeMenuItem->setNormalSpriteFrame(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("resume.png"));

_pauseResumeToggleItem = CCMenuItemToggle::createWithTarget(this,menu_selector(HelloWorld::menuPauseResumeCallback),_pauseMenuItem,_resumeMenuItem,NULL);
_pauseResumeToggleItem->setScale(0.5f);
//Position the pause/resume menu item to the top right corner of the screen
_pauseResumeToggleItem->setPosition(ccp(visibleSize.width - _pauseResumeToggleItem->getScaleX() * _pauseResumeToggleItem->getContentSize().width/2 ,
				visibleSize.height- _pauseResumeToggleItem->getScaleY() * _pauseResumeToggleItem->getContentSize().height/2));
_mainMenu->addChild(_pauseResumeToggleItem);

(b) Add the pause and resume methods:

void HelloWorld::pauseGame() {
	//Pause scene
	CCDirector::sharedDirector()->pause();
	_gamePaused = true;
	//Pause audio playback
	CocosDenshion::SimpleAudioEngine::sharedEngine()->pauseAllEffects();
	CocosDenshion::SimpleAudioEngine::sharedEngine()->pauseBackgroundMusic();
	//When the AppDelegate directly pauses the game we want to ensure the resume item is displayed
	_pauseResumeToggleItem->setSelectedIndex(1);

}

void HelloWorld::resumeGame() {
	//Resume scene
	CCDirector::sharedDirector()->resume();
	_gamePaused = false;
	//Resume audio playback
	CocosDenshion::SimpleAudioEngine::sharedEngine()->resumeAllEffects();
	CocosDenshion::SimpleAudioEngine::sharedEngine()->resumeBackgroundMusic();
}

(c) Add the pause/resume toggle menu item handler:

void HelloWorld::menuPauseResumeCallback(CCObject* sender) {
	  CCMenuItemToggle *toggleItem = (CCMenuItemToggle *)sender;
	  if (toggleItem->selectedItem() == _resumeMenuItem) {
		  pauseGame();
	  } else if (toggleItem->selectedItem() == _pauseMenuItem) {
		  resumeGame();
	  }
}

(d) Just like we prevented the player from shooting when the game ends, we need to do the same when the game is paused. In HelloWorld::ccTouchesBegan(cocos2d::CCSet *touches, cocos2d::CCEvent *event ) change the if statement to add check for game pause:

void HelloWorld::ccTouchesBegan(cocos2d::CCSet *touches, cocos2d::CCEvent *event ) {
	if (!_gameOver && !_gamePaused) {
            //...existing code
	}
}

(e) Change the HelloWorld::menuRestartCallback(CCObject* sender) add a check for game pause:

void HelloWorld::menuRestartCallback(CCObject* sender) {
	//if the game is paused we need to resume the game first before resetting otherwise we will end up
	//restarting in paused state
	if (_gamePaused) {
		resumeGame();
	}
	//Restart game with a cool rotozoom transition
    CCDirector::sharedDirector()->replaceScene(CCTransitionRotoZoom::create(1.0, this->scene()));
}

(f) Under CCScene* HelloWorld::scene() change the line scene->addChild(layer) as follows:

//add a tag so that our AppDelegate can retrieve the scene 
//and call pause/resume methods for application lifecycle
scene->addChild(layer,1,100); //<-Change this line

26. In AppDelegate.cpp, change the AppDelegate::applicationDidEnterBackground() method so it calls the pause game method:

void AppDelegate::applicationDidEnterBackground() {
    CCDirector::sharedDirector()->stopAnimation();

    //Retrieve HelloWorld scene by using the tag and call the pauseGame method
    CCScene* scene = (CCDirector::sharedDirector()->getRunningScene());
    if (scene !=NULL) {
    	HelloWorld* helloWorldScene = dynamic_cast <HelloWorld*>(scene->getChildByTag(100));
    	if (helloWorldScene != NULL) {
    		helloWorldScene->pauseGame();
    	}
    }
    
}

In the code above, we first defined the variables to keep track of game pause state and initialized them in the init(..) method. We also defined two methods to pause and resume the game so our app delegate can access them when handling lifecycle events. We then implemented the pause and resume methods by simply calling in-built Cocos2d-x methods to pause the game scene and audio playback. Next, we implemented the menuPauseResumeCallback(…) which toggles between pause and resume methods when the user taps on the pause/resume menu item. Finally, to pause the game once it’s pushed to background, we added the call to pauseGame(…) under the app delegate’s applicationDidEnterBackground(…) method.

Build/deploy the project and you should be able to pause and resume the game. Try pushing the game to the background and it should automatically pause. Bringing the game to the foreground will leave it in a paused state as expected. The pause/resume menu item will reflect the correct state (pause) because of the extra line of code we added to manually reset the menu item.

You can download the completed source code for this step from here.

Our game is now complete. But it doesn’t have to stop here. You can take this sample gane and adapt it to your own game concept. For example, you can replace the space background with a road and the player spaceship with a car. The asteroids can be replaced by other cars on the road. By barely changing any code, you now have a collision avoidance racing game.

You can download complete source code for SpaceGame which includes updated app name, icon and splash screen from GitHub at https://github.com/blackberry/Core-Native-Community-Samples/tree/master/SpaceGame

One thought on “How to create your own game using Cocos2d-x and BlackBerry Native SDK”

Leave a comment