cocos2d里面如何实现MVC(五)

分类栏目:cocos教程

146

本文基于前面两篇文章,如果您还没有看过,建议先阅读下面两篇文章:

更新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当前的状态来更新自己的显示