Implementing MVC framework for cocos2d-x projects

Implementing MVC pattern for cocos2d-x projects

(Full solution to this framework can be downloaded from GitHub)

To understand this article a working knowledge of the cocos2d-x framework is required. I came across a wonderful book which explained how to implement cocos2d in the MVC pattern. Since the team decided to go with cocos2d-x path, I decided to use my existing knowledge of this implementation pattern. Trust me, if you want to scale your game, you will want to implement this. For simple games, probably this does not matter as much (but you never know until you have finished your game :) ).

cocos2d-x MVC pattern

A short description on the MVC pattern

  • The Controller sends a command to the model to update the model’s state. It can also send commands to it’s associated view to change the views’s presentation of the model.
  • The Model notifies it’s associated views and controllers when there has been a change in the state. This notification allows the views to produce an updated output and the controllers to change the available set of commands.
  • The View requests information from the model that it needs for generating an output representation to the user.

Now we implement this pattern for cocos2d-x framework. I will create a simple x-code project to demonstrate the implementation. This sample has a ‘background’, a ‘ball’ and a ‘collision’ animation. The ball will bounce all over the background randomly. When the ball hits the ground, it will create a collision animation on the point of contact to the ground. Player can swipe/touch the ball to get rid off it. In this scene, we have just the three “game objects”, a background, a ball and a collision animation. These objects are considered as model. Background is simple, it does not have any states or actions. This just combines with the ball and the collision object to present to the view.

cocos2d-x class CCLAYER acts as a controller here. When the user interacts with the screen, it sends a message to the controller, which in return sends a command to the model according to either instructions from the user, or planned game steps (like bounce the ball).
cocos2d-x MVC pattern

Model: The Ball and the Collision class contains information about themselves. It has no idea what is happening in the controller class. For example, the ball knows how to bounce and it will do so when asked. In the MVC pattern, model cannot access the controller directly, but it can inform the controller that it has finished the task that it was suppose to do. The way this can be achieved is through a delegate control.

In this example, when the ball finishes bouncing, the view needs to show a collision animation. The ball informs the game layer class through a delegate control that it has finished bouncing, and therefore the layer requests the collision class to animate at the same time. The game layer requests the ball to bounce

Ball* ball = Ball::create();
//Set delegate so that ball can send messages back to the controller
ball->setDelegate(this);
ball->initWithSpriteFrame(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("ball_1.png"));
ball->setPosition(spawnLocation);
ball->setInitialPosition(spawnLocation);
ball->changeState(kStateBouncing);
_sceneSpriteBatchNode->addChild(ball, ZValue, kBallTagValue);
The ball bounces
CCJumpTo *jumpTo = CCJumpTo::create(1.5f, this->getInitialPosition(),
this->getPositionY() + getScreenSize().height/2, 1.0);
CCSequence *sequence = CCSequence::create(jumpTo, CCCallFuncN::create(this, callfuncN_selector(Ball::bounceMe)) ,NULL);
this->runAction(sequence);
The ball updates the game layer that it has finished bouncing

this->getDelegate()->touchGround(this->getPosition());
The game layer knows that the ball has finished bouncing and then it requests the collision to animate at the position where the ball had finished bouncing
void GamePlayLayer::touchGround(CCPoint startPosition){
Collision *collision = Collision::create();
collision->initWithSpriteFrame(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("collision_1.png"));
collision->setPosition(startPosition);
collision->changeState(kStateTapped);
_sceneSpriteBatchNode->addChild(collision, ZValue, kBallTagValue);
}
The Collision class the receives command to animate, which it obeys
CCSequence *sequence = CCSequence::create(CCAnimate::create(getAnim()), CCCallFuncN::create(this, callfuncN_selector(Collision::removeAndClean)) ,NULL);
//finish animation and remove the sprite.
this->runAction(sequence);
The user taps at the ball to kill it

void GamePlayLayer::ccTouchesBegan(CCSet *touches, CCEvent *event){
  CCTouch* touch = (CCTouch*)touches->anyObject();
  Ball* ball = (Ball*)_sceneSpriteBatchNode->getChildByTag(kObjectTypeBall);
  if (ball != NULL && ball->boundingBox().containsPoint(touch->getLocation())) {
    ball->stopAllActions();
    ball->changeState(kStateTapped);
    this->createObjectOfType(kObjectTypeBall, 5, ccp(getScreenSize().width/2,getScreenSize().height/8.0), kZValue);
  }
}

Full solution to this framework can be downloaded from GitHub This solution contains a rough implementation of the MVC pattern for the cocos2d-x framework. In the start it looks like we have complicated things, but trust me, when the project gets bigger and you have 100’s of sprites to manage, coding becomes very simple and manageable if you follow ‘a’ pattern (not just necessarily this one). This pattern is working great for me and I have fully implemented this in my upcoming Game ‘Masato’. Please comment below and let me know your thoughts around it. There is always room for improvements. Here is a video to demonstrate the end result.

References:

  • http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller
  • http://www.informit.com/store/learning-cocos2d-a-hands-on-guide-to-building-ios-games-9780321735621
Posted in Tutorials

Leave a Reply

Your email address will not be published. Required fields are marked *

*

Join 1 other subscriber