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

前言:

    衆所周知,現在MVC非常流行。現在只要隨便搜索一下,哪裏都是MVC的影子。剛開始在j2ee裏面,然後是rails,後面居然.net也出來了,ios更不用說,哪裏都是mvc,而且強制你必須使用mvc。但是,我們寫的那些程序,真正完全符合mvc嗎?呵呵,這個不好說,看個人理解程度而異。mvc實在是太火了,那麼cocos2d-x該怎麼實現mvc呢? 

Model-View-Controller (MVC) 在web應用開發中非常流行,它是一種組合設計模式,目前被廣泛應用於帶有圖形交互用戶界面程序開發中。一些web開發框架,比如Ruby On Rails,Django 和 ASP.NET MVC, 它們是不同語言平臺上面的web開發框架,但是,它們都共用同樣的原則--那就是把用戶表示層和邏輯層分離開來。關注點分離(SoC),這個原則在現代軟件工程方法中是一個非常重要的設計理念--不要迷失於實現細節,遇到一個實際問題的時候,要劃分不同的關注點,且這些關注點必須隔離開來,這樣才能達到更好的代碼重用度,以獲得魯棒性、可適配性和可維護性。所有這些軟件屬性對於軟件質量來說都是至關重要的。

Cocos2d-x本身並不是基於mvc的理念來設計的,但是,這並不防礙你在自己的遊戲開發中使用mvc。實現方式肯定是多種多樣的,在這篇博文中, 我只是向大家分享一下我是怎麼在cocos2d-x裏面實現mvc的,同時,在最後,我會寫一個簡單的遊戲demo,當然,裏面使用的是cocos2d-x+mvc。

現有問題

    cocos2d-x裏面有這樣一些類,CCSprite,CCLayer,CCScene,所有這些,都是CCNode的子類。基本上,大家在使用cocos2d-x開發遊戲的時候,都會採用下面的步驟來實現遊戲邏輯:

1 通過應用程序代理類來初始化第一個CCScene(即AppDelegate裏面的第一個CCScene),

2 CCScene裏面實例化一個或者多個CCLayer,並把它們當作孩子添加進去。

3 CCLayer 裏面實例化一個或者多個CCSprite,也調用addChild添加進去

4 CCScene 處理用戶輸入(比如touch事件和加速計的改變),同時更新CCLayer和CCSpirte的屬性,比如更改CCSprite的position,讓sprite運行一個或多個actioin等。

5 CCScene裏在運行一個遊戲循環(game loop,一般是1/60更新一次),然後CCLayer和CCSprite就在這個game loop裏面做一些更新和遊戲邏輯。

    這個過程看起來非常簡單,而且也可以很快地做出遊戲來。這也是爲什麼cocos2d-x這麼流行的原因,它實在是太簡單了。但是,當你的遊戲邏輯越來越複雜的時候,你的代碼會變得越來越難以維護。這裏面最突出的問題就是,CCScene這個類負責的事情太多了---同時要處理用戶交互,還有負責遊戲邏輯(邏輯層)和畫面顯示(表示層)。(譯者:根據SoC的原則,這顯然是不合理的,我們應該把職責分離開來,這樣代碼才更容易維護。同時SRP(單一職責原則)也是這麼要求的,一個類只負責一件事情)

模型(Model)

    MVC它會把一個系統劃分爲以下幾個組件:

· Model ,它負責與領域相關的邏輯處理代碼,也可以說是邏輯層,或者領域層。

· View ,只負責界面顯示。

· Controller ,它負責處理用戶交互。

    讓我們先從model開始。Model代表了遊戲邏輯。因爲我現在正在製作一個platform遊戲,所以,我講的一些東西也是與platform遊戲相關聯的。我的遊戲裏面的model包含下面一些類(當然,僅僅是一部分類)

· Player, 

· 包含一些屬性,比如:player的位置、當前速度(x軸速度、y軸速度)等。

· 包含一些與player有關的處理邏輯,比如:run,walk,jmup等。

· 包含一個update方法,該方法會被遊戲主循環每一幀刷新時所調用,它主要負責更新player model。

· Platform, 

· 包含一些屬性,比如:platform位置、寬度、高度等。

· 包含一些與platform有關的處理邏輯,比如:傾塌等

· 包含一個update方法,該方法會被遊戲主循環每一幀刷新時所調用,它主要負責更新patform的model。

· GameModel, 

· 包含一些遊戲世界的屬性,比如重力等。

· 包含一些方法來執行遊戲邏輯。

· 包含一個update方法,該方法會在每一幀刷新的時候被game loop所調用,然後它就可以更新自己的狀態,同時還會觸發遊戲世界裏面的其它對象也相應地更新自己的狀態。

    你可能會問:有些屬性你完全沒有必要重複定義,你可以直接從CCSprite裏面得到,比如position、width、height等。我想說:有對有錯。說對呢,是因爲它們確實差不多,可以拿來就用。說不對呢,那是因爲,model有可能使用一些不同的計量單位,比如米,而不是像素。(比如box2d這樣的,就不是使用像素作爲單位)。在我的model裏面,我使用的是米,當然,你也可以使用英尺,或者其它單位。渲染引擎對於model來說是透明的,model完全不用關心。

視圖(View)

    根據mvc的原則,view應該只負責界面顯示。它實際上也是在cocos2d-x裏面實現mvc時,最簡單的一個。如果你有一個model,你可以使用CCLayer,然後添加一些CCSprite或者其它coocs2d-x類來處理顯示問題。把model和view分開的好處就是,你沒必要把model的屬性直接映射到view的屬性上面去。比如,你的玩家在x軸方向上移動,但是,你想讓它總是在距離屏幕左邊10px的位置。這時候,你就可以實現CCLayer了,而不是真的在移動sprite。當把model對象顯示出來的時候,你必須考慮單位,如果你使用的是米作爲計量單位,你在渲染的時候必須轉化爲像素。(你可以像box2d裏面一樣,定義一個PTM_RATIO)那麼你的model怎麼和view打交道呢?你可以從controller裏面得到view,或者你可以把game model製作成一個單例,然後使用靜態方法來負責它。

控制器(Controller)

    controlller負責把view和model聯繫起來。它的主要職責就是處理用戶輸入。由於我們需要實例化model和view,我發現在controller裏面來做非常合適。我是把controller類繼承到CCScene類,然後我們一個初始controller類,它由appDelegate來實例化。然而,這裏會有一個問題,touch事件是由CCLayer來處理的,而它在我的設計裏面的角色是view。而我又不想讓view來處理用戶輸入,所以,我需要傳遞一個view的引用給controller(不是直接傳遞,而是通過delegate),然後通過delegate來執行controller的touch事件處理代碼,以此來處理view裏面的touch事件。好了,現在我的controller類就能夠處理來自view的用戶事件了。然後,它可以根據用戶的輸入來操作model,要麼通過修改model的屬性,或者調用model的方法。再更新完model之後,我們的view也需要得到通知並更新。所以這些,我都在game loop裏面完成,實際上它就是一個controller。controller的職責只是負責調用view的update方法,然後剩下的就交給view去完成啦。

還有一件事情…

   遊戲並不僅僅是根據model狀態的更改來更新一下view就可以了,它還需要播放音樂和音效。由於controller負責處理用戶交互,它肯定知道何時該播放什麼音效。但是,有些時候也會有例外。如果一個player掉到platform上面,但是controller並不知道,因爲這部分邏輯判斷在model裏面。那我們可以從model裏面播放音效嗎?。。。不,我們不能這樣做。因爲這樣就破壞了SoC的原則了,model就應該只負責遊戲邏輯。那麼,我們該怎麼做呢?在下一篇博文中,我將向大家展示我是怎麼做的,我打賭,你肯定差不多也想到呢,對吧?


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