cocos2d里面如何實現MVC(四)


    在上一篇文章中,我們使用cocos2d基於mvc做了一個簡單了游戲架子,這個架子還非常簡單,還有許多東西有待實現。

介紹模型

    在上一篇博文中,我們介紹了view和controller。為了實現mvc模式,我們還需要添加一個model類來維護游戲的狀態。我們的實現應該要包含下列這些類:

  1. GameBoardView - 也就是View,
  2. GameBoardController - 也就是Controller.
  3. GameBoard – 也就是Model.

Model 實現

GameBoard 實現

    我們在第一部分所描述的需求是這樣子的:

    。。。一個game board是通過n行n列組成的,它會隨着游戲難度有所變化。

    因此,我們按照下面的編碼方式來實現之:

@interface GameBoard : NSObject {
NSInteger numberOfRows;
NSInteger numberOfColumns;
}

- (id)initWithRows:(NSInteger)aNumberOfRows columns:(NSInteger)aNumberOfColumns;

@property (nonatomic) NSInteger numberOfRows;
@property (nonatomic) NSInteger numberOfColumns;

@end

    請注意,model是從NSObject繼承過來的---因為model只需要關注game board的狀態就行了(當然,還有相應的更新狀態的方法)---我們不應該把其它東西也放進來,比如繼承到CCNode就不行,我們並不需要CCNode的東西,所以,為了純粹性,我們這里繼承到game board。

GameBoardView 的實現

    我們現在需要修改View,同時它包含一個model的引用,我們可以通過initWithGameBoard方法來初始化這個成員變量:

@interface GameBoardView : CCNode {
GameBoard *gameBoard;
}

@property (nonatomic, retain) GameBoard *gameBoard;

- (id)initWithGameBoard:(GameBoard *)aGameBoard;

@end

   具體GameBoardView的實現細節如下:(為了演示方便,我們忽略了實際渲染每一個小方塊的代碼)

- (id)initWithGameBoard:(GameBoard *)aGameBoard {
if ((self = [super init])) {
// retain gameboard
self.gameBoard = aGameBoard;

// render gameboard background
CCSprite *gameboardSprite = [CCSprite spriteWithFile:@"gameboard.png"];
gameboardSprite.anchorPoint = CGPointMake(0, 0);

[self addChild:gameboardSprite];

// render spaces
for (int i = 0; i < gameBoard.numberOfRows; i++) {
for (int j = 0; j < gameBoard.numberOfColumns; j++) {
// position and render game board spaces
}
}
}

return self;
}

GameBoardController

    最后,我們要更新GameBoardController的init方法,因為view需要把GameBoard對象通過init方法注入進去,所以,我們在controller的init方法里面,就應該定義好model對象,然后傳遞給view。

- (id)init {
if ((self = [super init])) {
// initialize model
gameBoard = [[GameBoard alloc] initWithRows:7 columns:9];

// initialize view
view = [[GameBoardView alloc] initWithGameBoard:gameBoard];

[self addChild:view];
}

return self;
}

處理touch事件

GameBoardView updates

    為了能夠處理touch事件,我們需要再稍微修改一下View。我們讓它繼承至CCLayer,而不是CCNode。因為CCLayer內置了處理touch事件的方法:

@interface GameBoardView : CCLayer {
...
}

    而view本身是不應該處理用戶的交互(touch事件)的,所以,我們需要定義一個代理(GameBoardViewDelegate)。(譯者:為什么這里要定義代理呢?所謂代理代理,當然就是你不想做的事,找別人去做,這就是代理。所以,當你寫代碼的時候,你想保持類的簡單性、重用性,你就可以把事件盡量都交給其它類去做,自己只管做好自己的事。也就是SRP,單一職責原則。如果一個類關注的點過多,做的事情太多。這些事情不管是你直接做的,還是調用別的對象去完成的。這都不行,自己做這些事,那就會使類的功能復雜化,維護不方便。而過多地調用其它對象來完成一些事情,表面上看起來好像不錯,實際上是過度耦合了。我們編寫類的原則應該是追求高內聚,低耦合的。可能你會說,用代理不也是交給別人做嗎?沒錯,問的好。但是,代理是接口,我們是針對接口編程,所以它的重用性會非常好。因此,下次當你想寫可擴展和可重用的代碼的時候,不妨先想想代理這個東西吧。objc里面delegate是用protocol實現的,而java和c++則是用接口實現的,具體他們之間怎么轉換的,比較一下應該就可以了。)

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

    我們還需要再修改一下GameBoardView的init方法,通過傳送一個delegate進來處理touch事件。

- (id)initWithGameBoard:(GameBoard *)aGameBoard delegate:(id)aDelegate;

下面是touch事件的具體實現:

- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint point = [self convertTouchToNodeSpace:touch];

// calculate row and column touched by the user and call a delegate method
// ...
[self.delegate gameBoard:self.gameBoard touchedAtRow:row column:column];
}

GameBoardController 更新

    GameBoardController將會負責處理用戶touch事件,所以,我們需要讓GameBoardController實現GameBoardViewDelegate接口:

@interface GameBoardController : CCNode<GameBoardViewDelegate>
- (void)gameBoard:(GameBoard *)gameBoard touchedAtRow:(int)row column:(int)column {
// do the game logic here and update view accordingly
}

   還有最后一步,那就是修改view的init方法,把controller傳遞進去。

// initialize view
view = [[GameBoardView alloc] initWithGameBoard:gameBoard delegate:self];

總結

    在這篇文章中,我們實現了Model,同時還通過一些代碼把view和controller聯系起來了。同時,我們還在view和controller,以及用戶touch事件之間建立了聯系,這樣controller類就可以來響應游戲里面的用戶輸入了。(譯者:為什么費這么多勁,無非就是職責分離,這個非常重要!)。在接下來的文章里面,我們會談到下面兩個問題:

  • 在Controller里面更新Model,
  • 通知View關於Model的改變.

 

 

后記:本文已同步更新到cocos2d mvc這個系列里面去了。

    如果你覺得本文章對你有所幫助,請您點一下旁邊的“推薦”按鈕,這樣可以讓更多的人看到,同時也會給我寫作的動力,謝謝大家。









免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM