cocos2d meets MVC – Implementing simple board game part 3

This is the 3rd part from the series how to build a simple puzzle game using cocos2d and MVC pattern. If you haven’t read previous parts I suggest you do it before reading this post:

Updating the Model

When the user touches the toolbox item and then touches the space on a game board we want that the game piece represented by a toolbox item will be placed on a game board at touch position. In the previous part we already implemented touchedAtRow method in GameBoardViewDelegate. We will extend this protocol and add additional method for handling toolbox item selection.

@protocol GameBoardViewDelegate
 
- (void)gameBoard:(GameBoard *)gameBoard touchedAtRow:(int)row column:(int)column;
- (void)gameBoard:(GameBoard *)gameBoard toolboxItemTouchedAtIndex:(int)index;
 
@end

We need to change the implementation of our touches handler, so that we now detect whether we clicked on a toolbox or on a game board.

- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    CGPoint point = [self convertTouchToNodeSpace:touch];
 
    // touched on a game board
    if (CGRectContainsPoint(gameBoardRectangle, point)) {
        int row, column;
        // calculate row and column based on a touch coordinate
        // ...
        // call controller
        [self.delegate gameBoard:self.gameBoard touchedAtRow:row column:column];
    }
    // touched on a toolbox
    else if (CGRectContainsPoint(toolboxRectangle, point)) {
        int index;
        // calculate toolbox item index based on a touch coordinate
        [self.delegate gameBoard:self.gameBoard toolboxItemTouchedAtIndex:index];
    }
}

Handling events on the Controller side is easy, first of all we extend the Model to keep the state of our model and allows us to modify the state based on user touches. Our interface will look something like this (implementation details omitted for clarity):

@interface GameBoard : NSObject {
// ...
}
 
// ...
- (void)putGamePiece:(GamePiece *)gamePiece row:(int)row column:(int)column;
- (GamePiece *)getGamePieceFromToolboxItemAtIndex:(int)index;
@end

Then we finish the implementation of GameBoardViewDelegate in GameBoardController and handle our events accordingly.

- (void)gameBoard:(GameBoard *)aGameBoard toolboxItemTouchedAtIndex:(int)index {
    // keep the toolbox selection state in the Model
    gameBoard.selectedToolboxItemIndex = index;
}
 
- (void)gameBoard:(GameBoard *)aGameBoard touchedAtRow:(int)row column:(int)column {
    // if the toolbox item is selected move item from toolbox to game board
    if (gameBoard.selectedToolboxItemIndex != -1) {
        GamePiece *gamePiece = [gameBoard getGamePieceFromToolboxItemAtIndex:gameBoard.selectedToolboxItemIndex];
        [gameBoard putGamePiece:gamePiece row:row column:column];
    }
}

What we achieved so far is that when the user touches on of the toolbox item and then touches the space on a game board the Model gets updated reflecting the desired game board state.

Notifying the View about the changes in the Model

In order to reflect the state of the Model in the View we need to send some notifications so when the Model gets changed the View will be able to react upon it.

We do this the same way we notify the Controller about the View changes. We start from the delegate declaration inside the  Model.

@protocol GameBoardDelegate;
@interface GameBoard : NSObject
// ...
@property (nonatomic, assign)
id<GameBoardDelegate> delegate;
// ...
@end
 
@protocol GameBoardDelegate
- (void)gameBoard:(GameBoard *)gameBoard didPutGamePiece:(GamePiece *)gamePiece row:(int)row column:(int)column;
@end
 
@implementation GameBoard
 
- (void)putGamePiece:(GamePiece *)gamePiece row:(int)row column:(int)column {
    // ...
    // store game piece
    // notify that the game piece was put on a gameboard
    [delegate gameBoard:self didPutGamePiece:gamePiece row:row column:column];
}
 
@end

The last part is the implementation of GameBoardDelegate in the GameBoardView so that when the game piece is put on a game board the View will put a CCSprite at a given position.

@interface GameBoardView : CCLayer
// ...
@end
 
@implementation GameBoardView
 
- (id)initWithGameBoard:(GameBoard *)aGameBoard delegate:(id)aDelegate {
    if ((self = [super init])) {
        // retain gameboard
        self.gameBoard = aGameBoard;
        self.gameBoard.delegate = self;
 
        // assign delegate
        self.delegate = aDelegate;
    }
}
 
- (void)gameBoard:(GameBoard *)gameBoard didPutGamePiece:(GamePiece *)gamePiece row:(int)row column:(int)column {
    // create CCSprite and put it on a game board at corresponding position
    CCSprite *gamePieceSprite = [CCSprite spriteWithFile:fileName];
    // ...
    [self addChild:gamePieceSprite];
}
 
@end

Summary

All the pieces are now connected together. The interaction between the Model, the Controller and the View conforms to MVC paradigm:

  • The View handles the touches and notifies the Controller,
  • The Controller reacts upon the user touches and updates the Model,
  • The model updates its state, does the logic and tells the View that it has been changed,
  • The View updates itself based on the current Model state.
Comments?
Be Sociable, Share!
This entry was posted in idevblogaday, iPhone and tagged , , , , , , , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

7 Comments

  1. Kamrul
    Posted December 2, 2011 at 12:38 am | Permalink

    Thank you for taking the time to create this ‘blog’. Please can you make a sample project available for download so that I can further explore how you code fits together?

  2. basi
    Posted December 7, 2011 at 7:33 am | Permalink

    We have little bit experience in cococs2d for game development and little bit experience in MVC(java struts). this blog make very helpful for integrating both….
    can you bind the project for downloads…

  3. Mas
    Posted February 2, 2012 at 12:05 am | Permalink

    HI,
    thanks for the info, it was very useful.
    Question:If you had multiple scenes, and they all have lets say a options button in common, would it make scene to have a single super-class that is a CCScene that implements the options button and have the others scenes as subclasses to inherit the superclass behavior(options button) + have their own custom stuff?
    if so, how would this fit into your mvc model, would you have multiple scene instances in the controller class and also have multiple GameBoardDelegate for each scene?
    thanks

    • Posted February 9, 2012 at 11:37 pm | Permalink

      Hi,

      You can put a standard behavior to your base Controller class and extend it by your subclasses that also add scene specific logic to it. This also applies to views. But be aware that creating a complex inheritance tree is not a good idea so in this case you might prefer composition over inheritance.

  4. Kuro
    Posted March 30, 2012 at 6:33 am | Permalink

    @interface GamePiece : NSObject
    //How to achieve ?
    @end

  5. Coder
    Posted May 8, 2012 at 10:50 pm | Permalink

    Hi! thanks for creating this tutorial it has been very helpful.
    I seem to be missing something i doubled checked everything but the callback never gets to my controller for some reason i fail to see, can you point me in the right direction as where to look?
    Also did you get to upload the project?
    Thanks in advance

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">