Cocos2d-x裡面如何實現MVC(五)
阿新 • • 發佈:2018-12-21
本文基於前面兩篇文章,如果您還沒有看過,建議先閱讀下面兩篇文章:
更新Model
當用戶從工具箱中選一個小工具,然後把它放置到game board上面去時,我們需要編碼響應這些事件。在上一篇文章中,我們已經實現了GameBoardViewDelegate的touchedAtRow方法。我們還需要給這個協議再新增一個介面方法。如下所示:
我們需要修改touch事件處理器,這樣就可以判斷我們到底是觸摸了工具箱還是game board。class GameBoardViewDelegate { public: virtual void touchAtGrid(GameBoard *gameBoard, int row, int column) = 0; virtual void touchWithToolBoxItemAtIndex(GameBoard *gameBoard, int index) = 0; };
在controller類裡面處理touch事件是非常簡單的,我們只需要持有一個model的引用,然後基於touch事件來呼叫model的方法就行了。我們的介面看起來和下面差不多,只是省略掉了一些實現細節:void GameBoardView::ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent) { CCTouch *touch = (CCTouch*) pTouches->anyObject(); if(touch == NULL) return; // 置換座標,等效如下 //CCPoint location = touch->locationInView(touch->view()); //location = CCDirector::sharedDirector()->convertToGL(location); CCPoint point = this->convertTouchToNodeSpace(touch); // 下面假設遊戲區與工具區8:2來劃分寬度 CCSize size = CCDirector::sharedDirector()->getWinSize(); CCRect *gameBoardRectangle = new CCRect(0, 0, size.width*0.8, size.height); CCRect *toolBoxRectangle = new CCRect(size.width*0.8, 0, size.width*0.2, size.height); if(CCRect::CCRectContainsPoint(*gameBoardRectangle, point)){ // calculate row and column touched by the user and call a delegate method int row = 0; int column = 0; // ... this->gameBoardViewDelegate->touchAtGrid(gameBoard, row, column); } else if (CCRect::CCRectContainsPoint(*toolBoxRectangle, point)){ int index = 0; // calculate toolbox item index based on a touch coordinate this->gameBoardViewDelegate->touchWithToolBoxItemAtIndex(gameBoard, index); } }
class GameBoard : public CCObject
{
public:
// ...
GamePiece* getGamePieceFromToolBoxItemAtIndex(int index);
public:
// ...
int selectedToolBoxItemIndex;
};
然後,我們在GameBoardController裡面完全實現GameBoardViewDelegate的兩個方法。void GameBoardController::touchAtGrid(GameBoard *gameBoard, int row, 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, column);
}
}
void GameBoardController::touchWithToolBoxItemAtIndex(GameBoard *gameBoard, int index) {
// keep the toolbox selection state in the Model
gameBoard->selectedToolboxItemIndex = index;
}
到目前為止,我們實現了,使用者可以點選工具箱中的小工具,然後把它們放置到game board中的一個小方塊上面,同時model類在中間起了橋樑作用。
通知view關於model的改變
為了在view裡面反映出model的狀態更改,我們可以在model有變化的時候給view傳送通知訊息,然後view就可以根據不同的訊息來作出不同的響應了。和我們在實現view通過controller一樣,這裡我們也定義了一個GameBoardDelegate,用來通知view model的變化。
class GameBoardDelegate
{
public:
virtual void didPutGamePiece(GamePiece *gamePiece, int row, int column) = 0;
};
class GameBoard : public CCObject
{
// ...
public:
void setGameBoardDelegate(GameBoardDelegate *aGameBoardDelegate);
private:
GameBoardDelegate *gameBoardDelegate;
};
void GameBoard::putGamePiece(GamePiece *gamePiece, int row, int column)
{
// ...
// store game piece
// notify that the game piece was put on a gameboard
this->gameBoardDelegate->didPutGamePiece(gamePiece, row, column);
}
void GameBoard::setGameBoardDelegate(GameBoardDelegate *aGameBoardDelegate)
{
this->gameBoardDelegate = aGameBoardDelegate;
}
在GameBoardView裡面實現GameBoardDelegate的時候,當我們需要在game board上面放置一個小工具的時候,我們定義了一個CCSprite。
class GameBoardView :
public CCLayer, public GameBoardDelegate
{
// ...
};
void GameBoardView::initWithGameBoard(GameBoard *aGameBoard, GameBoardViewDelegate *aDelegate)
{
// ...
this->gameBoard = aGameBoard;
this->gameBoard->retain();
this->gameBoard->setGameBoardDelegate(this);
this->gameBoardViewDelegate = aDelegate;
// ...
}
void GameBoardView::didPutGamePiece(GamePiece *gamePiece, int row, int column)
{
// create CCSprite and put it on a game board at corresponding position
CCSprite *gamePieceSprite = CCSprite::spriteWithFile("CloseNormal.png");
// ...
this->addChild(gamePieceSprite, 1);
}
總結
現在框架中所有的部分都聯絡起來了,model、view和controller三者組成了著名的MVC模式
· View接收touch事件,然後把事件傳遞給controller,
· Controller 響應使用者的touch事件,然後更新model
· model 更新它自身的狀態, 處理遊戲邏輯,然後告訴view它改變了哪些東西。
· View則基於Model當前的狀態來更新自己的顯示