本文基于前面两篇文章,如果您还没有看过,建议先阅读下面两篇文章:
更新Model
当用户从工具箱中选一个小工具,然后把它放置到game board上面去时,我们需要编码响应这些事件。在上一篇文章中,我们已经实现了GameBoardViewDelegate的touchedAtRow方法。我们还需要给这个协议再添加一个接口方法。如下所示:
@protocol GameBoardViewDelegate - (void)gameBoard:(GameBoard *)gameBoard touchedAtRow:(int)row column:(int)column; - (void)gameBoard:(GameBoard *)gameBoard toolboxItemTouchedAtIndex:(int)index; @end
我们需要修改touch事件处理器,这样就可以判断我们到底是触摸了工具箱还是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]; } }
在controller类里面处理touch事件是非常简单的,我们只需要持有一个model的引用,然后基于touch事件来调用model的方法就行了。我们的接口看起来和下面差不多,只是省略掉了一些实现细节:
@interface GameBoard : NSObject { // ... } // ... - (void)putGamePiece:(GamePiece *)gamePiece row:(int)row column:(int)column; - (GamePiece *)getGamePieceFromToolboxItemAtIndex:(int)index; @end
然后,我们在GameBoardController里面完全实现GameBoardViewDelegate的两个方法。
- (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]; } }
到目前为止,我们实现了,用户可以点击工具箱中的小工具,然后把它们放置到game board中的一个小方块上面,同时model类在中间起了桥梁作用。
通知view关于model的改变
为了在view里面反映出model的状态更改,我们可以在model有变化的时候给view发送通知消息,然后view就可以根据不同的消息来作出不同的响应了。和我们在实现view通过controller一样,这里我们也定义了一个GameBoardDelegate,用来通知view 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
在GameBoardView里面实现GameBoardDelegate的时候,当我们需要在game board上面放置一个小工具的时候,我们定义了一个CCSprite。
@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
总结
现在框架中所有的部分都联系起来了,model、view和controller三者组成了著名的MVC模式
- View接收touch事件,然后把事件传递给controller,
- Controller 响应用户的touch事件,然后更新model
- model 更新它自身的状态, 处理游戏逻辑,然后告诉view它改变了哪些东西。
- View则基于Model当前的状态来更新自己的显示