Three Reasons why Adopting MVC makes sense even for a small cocos2d iPad Game

The Model-View-Controller (MVC) design pattern is engrained into many frameworks, and of course also into Cocoa Touch. To put it into a nutshell, MVC separates the management of data (the model) and the display (the viewer), linking these components by a controller. This promotes flexible design and reusability. In other words, if the process where the data comes from changes, the components that display it to the user and allow user interaction won’t have to change.

When I started my little FlipMemory project, a memory game for the iPad, the first release early 2010 was based on UIKit. For the second release in early 2011, I did a complete rewrite, based on the excellent cocos2d-iphone toolkit  (which of course also works on the iPad).

In all the (simple) sample projects I have worked through back then when I learned cocos2d, the code that manages the model was mingled with the view components. So my first approach was to do it alike, and not bother about adopting MVC.

But I was wrong, and therefore had to redesign FlipMemory, and here is why.

1. MVC makes it easier to test your Model – a core component in any app

When I rewrote FlipMemory in cocos2d, I started by creating a class that manages the memory card logic: A deck of matching cards, responding to events like ‘user turned around a card’ , ‘check if cards match’ and ‘reshuffle the opponent’s cards in multiplayer mode’.

[sourcecode language="css"]
enum TurnResult {
turnedFirstCardOfPair,
foundMatchingCard,
foundNonmatchingCard,
cardAlreadyTurned,
cardAlreadyRemovedAtIndex,
indexBeyondRange
};

@protocol GameModelDelegate
-(void)timerIncrementedByASecond;
-(void)counterForSolvedCardsChanged;
-(void)turnCardToFront:(int)index;
-(void)turnCardToBack:(int)index;
-(void)removeMatchingCards:(int)index1 index2:(int)index2;
@end

@interface GameModel : NSObject {
NSMutableArray *cards;
int indexOfFirstCardOfTurnedPair;
int indexOfSecondCardOfTurnedPair;
int pairsToSolve;
id delegate;
}

-(id)initWithMaxIndex:(int)maxIndex delegate:(id)delegate;
-(enumTurnResult)turnCard:(int)index;
-(int)valueAtIndex:(int)index;
-(BOOL)isCardTurnedAtIndex:(int) index;
-(BOOL)isCardEmptyAtIndex:(int)index;
-(int)numberOfCards;
-(int)pairsToSolve;
@end

[/sourcecode]

I wrapped this game model into a very simple view controller, that consisted of old-style printf and scanf statements. That way, I could play a memory game in the Xcode console   :)

[sourcecode language="css"]
X X X X X X X X

–> 1
X 2 X X X X X X

–> 5
X 2 X X X 1 X X
[/sourcecode]

and so on, you get the idea.

2. MVC allowed me to add two player functionality to FlipMemory

When it was time to add multi player functionality, I created two instances of the model class. That was it.

Well no, there was a lot more code to it of course… But without having one class that manages the game logic, I think it would have been very hard to add multi-player.

Here’s the definition of the Game class:

[sourcecode language="css"]
@interface Game : NSObject {
BOOL gameRunning;
NSUInteger numberOfPlayers;
enumGameMode gameMode;
NSMutableArray *players;
NSMutableArray *models;
}
[/sourcecode]

and here how it creates the model for each player. While that can certainly be cleaned up, I guess it demonstrates the point I want to make:

[sourcecode language="css"]
for (int player=0; player<numberOfPlayers; player++) {
Player *player = [[Playeralloc] initWithGameMode:theGameMode difficulty:difficulty];
[players addObject:player];
[player release];

GameModel *model = [[GameModelalloc] initWithNumberOfPairs:numberOfPairs maxValue:[BoardLayernumberOfImagesForTheme:theme] gameMode:gameMode];
[models addObject:model];
[model release];
}
[/sourcecode]

3. MVC makes it easier to add new features to your game, because you break down your code into smaller pieces

As Robert C. Martin said over and over again in “Clean Code – A Handbook of Agile Software Craftsmanship”  you need to keep you classes small, otherwise you won’t be able to maintain your code. While I cannot claim that each class in FlipMemory only does one thing (yet), I certainly see the value of that principle.

Whenever I get time, I’m working on small enhancements of FlipMemory (e.g. Game Center integration, level design) – because that’s my testing ground.

Leave a Reply

Your email address will not be published. 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>