Cocos2d-x裏面如何實現MVC(三)

    引子:前面兩篇文章介紹了一些關於在cocos2d-x裏面如何實現mvc的理論知識,接下來的這三篇教程,我將用一個簡單的教程示例,給大家演示一下具體代碼實現細節。

    這篇文章的寫作目的就是讓大家更好地理解如何在cocos2d-x裏面實踐mvc模式(當然,這裏演示的不一定是標準的mvc,因爲cocos2d-x特殊的編程方式。但是,這並不妨礙我們編寫更好的代碼,你們說對吧?),本文是基於前兩篇文章的,所以,在繼續閱讀之前,我強烈建議你先讀一下第一篇的理論介紹。

情景

    我們將製作一個簡單的面板解謎遊戲(board puzzle game),當然,我們不是簡單地開發一個遊戲,而是要利用mvc開發出一個簡單的“遊戲框架”,而且這個框架將會在我的新遊戲裏面使用到,它具有如下一些特性:

1 一個n行n列的遊戲面板(game board),n可以隨着遊戲難度進行變化。 

2 這個遊戲面板裏面會包含一些“小方塊(game pieces)”,而且每一個game board上都只能放一個game piece。

3 這個遊戲面板可以初始化一些固定的小方塊,玩家在遊戲過程中,是不能移動這些小方塊的。

4 這裏還定義了一個“工具箱(toolbox)”,它上面可以放置許多小工具(toolbox item),它們可以看作是“可放置可移動小方塊的槽子”。

5 小工具(或者叫槽子)上面可以放置許多同一類型的小工具。

6 這些小工具可以從工具箱上面移動,並且可以放置到game board 上面。


基本概念

來自 wikipedia:

    model負責管理應用領域的數據和行爲邏輯,同時負責響應對自己的狀態數據請求(這些請求通常是從view過來的),然後響應一些指令來更改自身的狀態(這些請求通常是來自controller的)。在一個事件驅動的系統中,model會通知訂閱者(observers)(通常是views)它的狀態改變,這樣view就可以做相應的顯示更新。

    view則根據model的狀態來合理地顯示,通常是一些UI元素。一個model可以對應多個view,比如,同一數據的柱狀圖、餅狀條、曲線圖等。

   controller負責接收多用戶輸入和調用model的一些方法。一個controller通過從用戶那裏獲得輸入,然後操作model對象,最後,model通知view來更新顯示。

   從維基百科的定義中,我們可以識別出以下幾個主要的類(我們會在後面把model給加上去):

7 GameBoardView 代表應用程序的主視圖

8 GameBoardController 是GameBoardView的一個控制器。


    請注意,這裏的實線代表一種直接的關聯關係(controller裏面包含一個view的引用),而虛線則代表了一種間接的關聯(通過觀察者模式)。這裏的直接關聯後面會用來實現touch事件處理。

實現

項目組織結構

    在VS2008裏面基於cocos2d-x的默認模板創建一個新的項目之後,我們又創建了下面這些組:

9 View – views & controller 組 (我們也可以把view和controller放在那個不同的group裏面,但是,由於我們兩個有直接的關聯關係,爲了方便,我就把它們放在一起了)

10 Model – 之後,我們會把model類放在這個group下面。


GameBoardView 的實現

    接下來,我們開始實現GameBoardView。首先,我們把GameBoardView繼承至CCNode。

class GameBoardView : public CCLayer {
    // ...
 
    // implement the "static node()" method manually
    LAYER_NODE_FUNC(GameBoardView);
 
}
    然後,實現它的init方法,然後簡單地顯示一串字符來驗證程序的正確性。(譯者:這就和我們有時候會在方法的第一句加一個CCLOG一樣,只是爲了驗證函數是否被調用了,確保每一步都是按照你的想法去走的,這樣比那種埋頭編寫2個小時代碼不編譯,而後花一晚上修改編譯錯誤和bug要好很多。有時候只是輸出還不夠,還必須要做單元測試,這樣才能提高效率)
virtual bool init(){
 
    bool bRet = false;
    do
    {
        // 先調用超類的init方法
        CC_BREAK_IF(! CCLayer::init());
 
        CCLabelTTF *label = CCLabelTTF::labelWithString("Hello World from view", "Marker Felt", 48);
        // 獲取窗體的尺寸
        CCSize size = CCDirector::sharedDirector()->getWinSize();
        label->setPosition(ccp(size.width/2, size.height/2));
        this->addChild(label, 0);
 
        bRet = true;
    } while (0);
 
    return bRet;
}

GameBoardController 實現

GameBoardController負責初始化view,所以它裏面包含了一個GameBoardView的引用,將來就可以非常方便地直接使用了。

class GameBoardController : public CCLayer {
public:
    GameBoardView *view;
    // ...
 
    // implement the "static node()" method manually
    LAYER_NODE_FUNC(GameBoardController);
}
因爲我們的GameBoardController繼承到CCNode,所以,我們可以把GameBoardView當作GameBoardController的孩子給添加進去。
virtual bool init(){
    bool bRet = false;
    do{
        // 先調用超類的init方法
        CC_BREAK_IF(! CCLayer::init());
 
        view = GameBoardView::node();
        this->addChild(view, 0);
 
        bRet = true;
    }while(0)
 
    beturn bRet;
}
 
static CCScene* scene(){
    CCScene *scene = NULL;
    do{
        scene = CCScene::node();
        CC_BREAK_IF(!scene);
 
        GameBoardController *layer = GameBoardController::node();
        CC_BREAK_IF(!layer);
 
        scene->addChild(layer);
    }while(0);
 
    return scene;
}

最後的修改

    我們然後修改AppDelegate類,然後運行我們新創建的contorller:

CCDirector::sharedDirector()->runWithScene(GameBoardController::scene());

   好了,現在編譯並運行。當程序跑起來的時候,這個結果和cocos2d自帶的模板運行效果差不多。但是,有個很重要的區別,那就是我們創建了一個mvc的骨架,在接下來的遊戲邏輯中,我們可以在上面做很多文章。

接下來做什麼

    該項目進行到現在,已經爲我們引入一些更高級的概念打下了良好的基礎,所以,在下一篇教程裏,我們將涉及下面兩個東西:

11 處理touch事件.

12 引用model的概念.




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章