程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 【深入Cocos2d-x】使用MVC架構搭建游戲Four

【深入Cocos2d-x】使用MVC架構搭建游戲Four

編輯:C++入門知識

喜歡Four這個項目,就趕快在GitHub上Star這個項目吧!

喜歡我的文章,來微博關注我吧:王選易在學C艹

點我下載

項目起源

項目Logo:

下面是該游戲的項目地址,各位想參考源代碼的同學可以到我的GitHub上下載該項目的源碼。

項目主頁

GitHub地址

bug反饋及建議

mvc

我做這個項目的原始目的是實驗MVC在游戲中的應用。

Model-View-Controller(MVC)是一種組合設計模式,它體現了一種關注點分離(Separation of concerns,SoC)的思想。MVC主要把邏輯層和表現層進行了解耦,將一個問題劃分成了不同的關注點。增強了應用的穩定性,易修改性和易復用性。

MVC經常被使用在Web框架中,包括J2EE,RoR和.Net中都對MVC模型進行了框架層面上的封裝,以便程序員可以簡單方便地作出結構良好的Web應用。

Cocos2d-x本身並沒有提供內置的MVC支持,但是,我們還是可以在游戲中基於MVC架構來設計游戲。在這篇博文中,我將向大家展示一下我是如何使用MVC架構來塔尖Four這個游戲的。

游戲情景

Four這個游戲的創意來自一個叫做走四棋的傳統游戲,走四棋規則的詳細介紹在這裡:走四棋的百度百科。

下面我簡單談一下這個面板游戲(board game)的一些特性

  • 一個4行4列的棋盤(Game Board)
  • 棋盤上會有一些“棋子”(Game Piece),每一個方格上只能放一個棋子(Game Piece)。
  • 游戲初始化時,棋盤的上面四格和下面四格分別有4個黑子和四格白子
  • 玩家可以通過話筒使棋子在棋盤上發生移動,從而觸發吃子和勝利等事件。
  • 當游戲中出現一個橫行或者一個豎列的棋子排布變為兩黑一白或者兩白一黑時,即可吃掉一子。
  • 當一方(黑或白)的棋子被吃到只剩一個之後,這一方被記為失敗

舉個例子,下面這幅圖即為游戲過程中的一幅圖。在下面的游戲過程中,位於(1,0)位置的黑子向左移動到(0,0)的位置後即可吃掉白子。

Cocos2d-x提供的工具

Cocos2d-x有這樣一些主要的類,CCSprite,CCLayer,CCScene,CCNotificationCenter。我們會使用這些類進行游戲中MVC架構的搭建,如果你對這些類的作用不熟,請參考我的這篇博文【Cocos2d-x-基礎概念】Director Scene Layer and Sprite。

我們一般的游戲流程是

  • 通過AppDelegate初始化第一個CCScene。
  • 在第一個CCScene創建多個CCLayer。並控制好CClayer的疊加層次(zOrder)。
  • 在CCLayer中添加各種CCSprite或者CCLabelAtlas或者粒子效果。
  • 在CCLayer層注冊觸摸事件的監聽,並且在CCLayer的實現中寫出相應的callback函數,對CCLayer的Child Node進行相應的邏輯處理。

這個過程看起來十分簡單,並且可以十分快速地做出游戲。但是其缺陷就在於在CCLayer中我們做了太多的事情。CCLayer同時承擔了邏輯層和表示層的任務。不符合我們上文中提到的關注點分離的原則。如果游戲中有較為復雜的狀態轉換時就捉襟見肘了。

項目的文件目錄

下面是該游戲項目的目錄結構,我們接下來對這幾個文件夾進行分別的講解:

下面是該項目的一個簡單的類圖

在類圖中,虛線代表的是通過消息機制進行溝通,而在Cocos2d-x中,這種溝通是通過CCNotificationCenter來實現的。

Model(模型)

Model在游戲中代表的是消息驅動的有限狀態機,Model會接受Controller層發送的消息,並根據消息來更改自己的內部數據,然後把內部數據改變這一消息發送給View,通知它更新。

Model在Cocos2d-x對應的是哪個類呢?

很遺憾,但是Cocos2d-x並沒有提供狀態機的feature,所以我們需要自己實現一個Model類,在Model類中,需要自己實現諸如狀態轉換和消息處理等功能。例如在我的Model類中,我提供了如下接口。

class Model : public CCObject {

public:

    // 添加一條狀態轉換,from-起始狀態,msg-接收的消息,to-終結狀態,在msg發生時會發生狀態轉換
    Model* addTransition(const string& from, const string& msg, const string& to);

    // 檢查當前狀態機能否發生msg對應的狀態轉換
    bool checkMessage(const string& msg);

    // 觸發msg對應的狀態轉換
    void onMessage(const string& msg);
    void onMessage(const string& msg, CCObject* o);

    // 等待某個CCAction結束後發送一條消息。
    void waitAction(cocos2d::CCNode* node, cocos2d::CCFiniteTimeAction* action, const string& msg);

    // 得到當前狀態名稱
    const char* getState();
};

注意以下幾點:

  • 讓Model類繼承CCObject,是為了與Cocos2d-x自身的內存管理系統一致。
  • onMessage中,我們做的事情就是首先找到當前狀態在msg情況下的狀態轉換。在狀態轉換後,通過CCNotificationCenter發送一條消息通知游戲中的其他組件更新邏輯。
  • waitAction中,我們是在處理一種異步的狀態轉換,比如一個棋子在移動時就會經歷這樣的狀態轉換start->moving->end,那麼在移動結束後,View就要發送一條類似END_MOVE的消息來通知Model更新自己的狀態。

Model不會持有View,所以View都是通過消息來獲得Model更新的事件的。

我們在編寫游戲時,應該先編寫Model,然後通過測試來保證Model的正確性。

之後,我們去寫View的時候,實際就是對Model這個狀態機發送的各種消息的回調函數的編寫了。

這樣就講表示層和邏輯層分離開,可以方便地單獨測試每個模塊,可維護性大大提高。

邏輯數據和實際數據

在編寫Model的時候,我們經常會遇到這樣的問題,就是Model中的數據是否應當與View中的數據保持一致。

比如:在View層的棋子的位置信息是否應該和Model層的位置信息保持一致?

其實,真實情況就是,這要看Model層的
計算使用那種數據形式更加方便,比如在Model中,我們會把棋盤轉化為一個二維數組,這樣在AI運算,邏輯判斷時,更加有利,所以棋子的邏輯位置和實際位置必然是不同的。

再比如,很多時候游戲中的物理引擎的計量單位是厘米,米。而不是OpenGL中的坐標。這也是為了邏輯運算的方便。

但是有些數值,我們會讓它保持一致,比如人物的屬性等等。

View(視圖)

View在游戲中代表的是Model消息的接受者,在Cocos2d-x中,View一般是指CCLayer的子節點,即CCSprite,CCLabelAtlas,CCMenuItem,Particle System(粒子系統)等等。

它們會重載onEnter函數,在onEnter中注冊自己對某個Message的監聽。同時在onExit函數中將所有監聽清除。(清除監聽很重要,否則會出現很可怕的野指針問題)。

Controller(控制器)

Controller在游戲中負責將用戶觸摸事件轉化為邏輯事件(即我們上文中所說的消息),同時要對用戶觸摸事件中的信息進行正規化,並且通知變更。

Controller在Cocos2d-x中一般用CCLayer
來實現,因為CCLayer自然地繼承了CCTouchDelegate這一接口,本身就可以觸摸事件,所以我在這個游戲中所有的XXXController都是繼承自CCLayer。

Controller另一個很重要的職責,就是創建View和Model,因為Controller相當於Model和View的一個中間層,所以自然Controller會同時持有View和Model的應用,來方便地傳遞數據。

Protocol(協議)

Protocol中定義了一些Model,View和Controller中共享的數據,

  • Message.h中,就定義了游戲中各種類型的消息,
  • Tag.h中,就定義了游戲中一些Node的Tag,其實Tag這個定義不是很准確,其實這裡的Tag指的是唯一標識CCNode的一個ID。
  • ChessboardProrocol.h中,定義了游戲中期盤的寬,搞和一些常用的數據結構。

參考文獻

  • 維基百科
  • 百度百科
  • 子龍山人的博客-如何通過MVC構建游戲

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved