基本概念
為了全面掌握cocos2d-x的開發,我們首先需要了解該引擎的幾個基本概念。實際上,這些基本概念是所有游戲開發所必須的,並非cocos2d-x專有。任何游戲都是通過這些概念所針對的對象組建起來的,游戲的復雜程度決定了這些對象實現的復雜程度。
場景(CCScene)
我們假設一個只有兩關的游戲:第一關(2個小鬼,1個小BOSS);第二關(5個小鬼,1個大BOSS)。通常情況下,我們會這樣設計整個游戲的流程(workflow):
開場動畫,可以有幾個目的:
簡單介紹一下游戲操作
講述故事背景
公司或者工作室動畫LOGO
進入主菜單后可以引導用戶:
開始新游戲
讀取進度
設置游戲 聲音,文字,游戲內容設置……
高分排名 通常都是列表,按分數排列。
幫助 操作簡介
退出
接下來,玩家可以有多種選擇,無論開始新游戲還是讀取進度,游戲都會進入到預設關卡。游戲過程中,第一關勝利就進入第二關,第二關勝利則進入結尾的勝利畫面(播放視頻或者在背景圖上顯示文字),確認后進入排名畫面看看本次得了多少分。如果失敗了,那就會進入失敗結束的畫面,確定后跳轉到主菜單,重新開始。
可以看出,玩家玩游戲的過程就是在我們預設的畫面之間進行跳轉,根據玩家操作的結果(選擇菜單項、消滅敵人或者被敵人殺死)跳轉到不同的畫面。
這些構成游戲流程的畫面就是我們所說的場景,圖中用黑色線框表示的部分。顯然,不同的場景提供不同的操作,大致可以分為以下幾類場景:
展示類場景:播放視頻或簡單的在圖像上輸出文字,來實現游戲的開場介紹、勝利/失敗提示、幫助說明等。
選項類場景:主菜單、游戲參數設置等。
游戲場景:這是游戲的主要內容,除了這個場景之外,其他類別的場景基本都是通用框架實現的。
那么不同的場景是如何實現不同功能的呢?每個場景都是通過不同的層的疊加和組合來實現不同的功能的。因此,通常一個場景是由一個或多個層組成的。
層(CCLayer)
層是我們寫游戲的重點,我們99%以上的時間是在層上實現我們的游戲內容。如下圖所示,一個簡單的主菜單畫面是由3個層疊加實現的:
細心的讀者可能已經注意到,為了讓不同的層可以組合產生統一的效果,這些層基本上都是透明或者半透明的。(否則我們就只能看到最上面的一個層了)
層的疊加是有順序的,如圖所示,編號為1的背景層在最下層,2號在中間,3號在最上面。cocos2d-x也是按照這個次序來疊加畫面的,處於最上層的不透明的部分會將下面的內容覆蓋。
這個次序同樣用於編程模型中的事件響應機制。即編號3的層最先接收到系統事件(手指單擊屏幕事件),然后是編號2,最后是編號1的層。在事件的傳遞過程中,如果有一個層處理了該事件,那么排在后面的層將不再接收到該事件。
我們可以簡單地把層理解為我們在Windows編程中的窗口(hWnd或者WinForm,還有Delphi中的TForm)。
為了方便大家進行游戲開發,cocos2d-x從技術實現角度提供一些公用層:處理菜單用的菜單層,處理顏色顯示的顏色層等。
每一層又可以包含各式各樣的內容要素:文本、鏈接、精靈、地圖等等。其中,精靈是游戲的重點。
精靈(CCSprite)
精靈是整個游戲開發處理的主要對象。敵方的飛機、坦克是系統控制的精靈,玩家控制的我方飛機也是精靈,甚至隨機飛過的一片雲、一只鳥都是精靈。
從技術上講,精靈就是一個可以不斷變化的圖片。這些變化包括:位移、旋轉、縮放以及圖片幀的切換。
所謂游戲,就是玩家操作一個或多個精靈與系統控制的精靈進行互動:近身肉搏、遠程射擊、對話等等。
導演(CCDirector)
我們已經大概了解了一個游戲的整體架構,不同的場景由不同的層組成,每個層又包含精靈在上面運動。玩家玩游戲的過程就是在操作層上的精靈或者菜單項,從而在不同的場景中切換。
好了,有些OO編程基礎的讀者已經猜到導演對象的作用了。是的,按照面向對象的設計原則和反向依賴原則:精靈不應該依賴層,層不應該依賴場景,場景不應該依賴整個流程。導演對象就是整個流程的代表,他負責游戲過程中的場景切換。
導演通常只有一個,因此這個對象是單例(singleton)。cocos2d-x框架已經預定義了該實例,無需額外創建,我們直接使用就可以。
導演對象接收層對象/場景對象的請求,按照預先設計好的流程來切換場景。至此,我們可以勾勒出一個游戲的整體框架和cocos2d-x關鍵對象與之的對應關系:
需要特別說明的是:任何時間,只有一個CCScene對象實例處於激活狀態。該對象可以作為當前游戲內容的對象的容器,對於菜單對象來說,通常屬於當前場景的主層。以上就是一個游戲的主要架構。
實際上,針對每一個游戲場景而言,不同場景(關卡)、每一個層(靜態、動態)、每一個對象(敵人、我方、中立方)其實都很復雜。萬里長征,這才第一步呢。
cocos2d-x的實現類
下面,我們首先逐一介紹cocos2d-x對應上述基本概念的對象,以及他們之間的程序關聯。
CCDirector(導演類)
CCDirector對象的作用類似於Windows編程中的主窗口對象(不同之處在於該對象並不可見),它負責創建、管理應用程序/游戲的主窗口,在特定的條件下顯示某個場景。
針對CCDirector的調用代碼(下面這段代碼是主程序啟動時的標准步驟,在AppDelegate的applicationDidFinishLaunching成員函數內實現):
1 bool AppDelegate::applicationDidFinishLaunching()
2 {
3 // initialize director
4 CCDirector *pDirector = CCDirector::sharedDirector();
5 pDirector->setOpenGLView(&CCEGLView::sharedOpenGLView());
6
7 // enable High Resource Mode(2x, such as iphone4) and maintains low resource on other devices.
8 // pDirector->enableRetinaDisplay(true);
9
10 // turn on display FPS
11 pDirector->setDisplayFPS(true);
12
13 // set FPS. the default value is 1.0/60 if you don't call this
14 pDirector->setAnimationInterval(1.0 / 60);
15
16 // create a scene. it's an autorelease object
17 CCScene *pScene = HelloWorld::scene();
18
19 // run
20 pDirector->runWithScene(pScene);
21 return true;
22 }
顯然,我們看到可以通過CCDirector對象完成以下兩大類任務:
設置主程序窗口的顯示屬性。
依次設定了以下內容:
1.初始化CCDirector對象。
2.設置是否開啟Retina顯示模式。
3.設置是否顯示FPS。
4.設置游戲畫面每秒顯示的幀數,默認是60幀。
管理、顯示場景。
CCDirector對象一次只能顯示一個場景。為了便於管理場景對象,CCDirector對象有3個屬性與場景有關(參見CCDirector.h):
1 /* 當前顯示的場景 */
2 CCScene *m_pRunningScene;
3
4 /* 下一個將要顯示的場景 */
5 CCScene *m_pNextScene;
6
7 /* 待執行的場景隊列 */
8 CCMutableArray<CCScene*> *m_pobScenesStack;
同時,CCDirector對象管理場景的方法主要有以下幾個:
1 /* 用來顯示主程序啟動后的第一個場景,如果已存在運行的場景,則不可使用 */
2 void runWithScene(CCScene *pScene);
3
4 /* 掛起當前正在運行的場景,壓入待執行場景隊列,並開始執行新的場景 */
5 void pushScene(CCScene *pScene);
6
7 /* 從待執行場景隊列中彈出一個場景,並以此取代當前運行中的場景。
8 如果待執行場景隊列已為空,那么程序將終止運行。 */
9 void popScene(void);
10
11 /* 直接用一個場景取代當前場景,這是最常用的一個方法。 */
12 void replaceScene(CCScene *pScene);
13
14 /* 結束運行,釋放當前場景。 */
15 void end(void);
16
17 /* 暫停場景運行。畫面還存在,但時間任務停止。 */
18 void pause(void);
19
20 /* 恢復場景運行。 */
21 void resume(void);
CCScene(場景類)
場景對象當前比較簡單,當前版本的cocos2d-x(1.0.1)基本上沒有附加任何特殊功能,基本上可以看作是層(CCLayer)對象的一個容器。有些例子沒有使用CCScene來作為場景切換,而是直接使用層的變換,筆者建議大家不要這樣。CCScene的作用十分重要,如果要為場景切換增加動畫效果,CCScene是必不可少的。
CCLayer(層類)
CCLayer的主要功能在於:
1)接收觸摸(touch)操作輸入。
2)接收動力感知(Accelerometer)輸入。
除此之外,CCLayer對象本身沒有提供更多的功能。關於CCLayer對象與TouchDispatcher的相互作用關系,我們放在以后的章節重點介紹。
cocos2d-x為了方便大家使用,直接提供了以下4個層:
CCLayerColor(顏色層)
這是一個透明的,可以按照RGB設置填充顏色的層。可以通過setContentSize設置層的大小,改變顏色塊的尺寸。圖中紅色部分就是一個CCLayerColor的實例。
層也支持動作,可以變色、淡入淡出和混合。
CCLayerGradient(漸變層)
CCLayerGradient是CCLayerColor的子類,他可以在背景上繪制漸變色。
CCMenu(菜單層)
這是一個以CCMenu對象為集合類,CCMenuItem類實例組成各式各樣按鈕的菜單管理選擇畫面層。(注意:該層中的實例必須是CCMenuItem類或其子類的實例)
CCMenu類提供的方法主要是用來按照橫向、豎向或者多行列排序展示CCMenuItem類實例的。
為了實現不同的按鈕效果,系統提供了多種類型的CCMenuItem,但每個按鈕都有三中基本狀態:正常、選中、禁用。
下面,我們逐一介紹一下CCMenuItem類系:
CCMenuItem
CCMenuItem是基礎類,不要直接使用該類。作為所有菜單項的父類,CCMenuItem主要完成以下兩個任務:
1.設置按鈕的狀態。
2.負責處理回調函數(當按鈕被單擊后,需要調用的函數叫做回調函數)。具體說就是內置一個NSInvocation *invocation來統一實現回調函數的激活。(這段以后深入研究下再修正吧,在cocos2d-x里肯定不是)
CCMenuItemLabel
CCMenuItemLabel能將任何支持CCLabelProtocol協議的CCNode轉變成一個菜單項,並增加選中時的放大效果。
CCMenuItemAtlasFont/CCMenuItemFont
CCMenuItemAtlasFont和CCMenuItemFont都繼承自CCMenuItemLabel,他們能根據你提供的字符串生成標簽,並以此創建菜單項。他們的區別是CCMenuItemAtlasFont使用圖片集,CCMenuItemFont使用預設字體。
CCMenuItemSprite
CCMenuItemSprite內置3個支持CCRGBAProtocol協議的CCNode對象,表示正常、選中、禁用三個狀態的圖像。
CCMenuItemImage
CCMenuItemImage從CCMenuItemSprite派生而來,你只需提供圖片的名字,創建CCSprite對象的過程由框架自動完成。
CCMenuItemToggle
內部有一個CCMenuItem數組,負責展示不同的狀態,進而達到狀態切換的效果。
CCLayerMultiplex(復合層)
這是可以包含多個層的復合層,將來再專門介紹。
CCSprite(精靈類)
精靈是游戲中的主要靜態、動態目標(敵方怪物、我方操作對象)。具體講就是一個獨立的圖像塊,通常情況下他是運動的(Action):位移、旋轉、縮放、運動——連續漸變圖像形成的運動效果。我們可以直接通過設定精靈的屬性讓他運動,也可以通過動作(Action)來達到同樣的目的。
在cocos2d-x中精靈由CCSprite類實現。精靈允許包含子對象,當父對象變化的時候,子對象會跟着變化。
由於游戲中95%以上的內容都是精靈類實現模擬的,因此如何提高精靈類的執行效率就是一個十分關鍵的問題。
1)緩存圖像內容,減少相同內容文件的讀取次數。
通過CCTextureCache類,cocos2d-x庫按照文件名為主鍵索引全部運行時讀取的圖片文件。當文件名一樣時,直接返回內存中的圖片而不再讀取文件。
所有與圖片文件有關的實現在底層統一調用CCTextureCache類的單例對象,保證最少的系統IO操作,提高程序運行效率。
2)批量提交繪畫,減少OpenGL函數的調用次數。
通過CCSpriteBatchNode類,cocos2d-x庫將所有CCSpriteBatchNode類對象所屬的子CCSprite對象一次提交給OpenGL輸出。
還有一個叫CCSpriteFrameCache的類,用於管理動畫效果的全部幀圖像。該類的實現也調用了CCTextureCache類對象。
小結
至此,讀者對於cocos2d-x的幾個關鍵概念以及對應的實現類有了整體的把握。CCScene、CCLayer、CCSprite類都是從CCNode類派生的,從類對象角度上來說他們是一樣的,可以互相從屬。從游戲設計的角度,他們完成的功能則互不相同,各有重點:
使用CCScene是為了:
1)作為某個場景的總體容器對象,將所有的內容對象(菜單、狀態、游戲角色、NPC)包含在內,層疊關系通過CCNode的addChild的zOrder決定。
2)實現場景切換的特殊效果。因為所有的場景切換特效都是從CCScene的子類CCTransitionScene派生的。
使用CCLayer是為了處理輸入問題:
1)觸摸事件處理
2)動力感知處理
使用CCSprite是為了顯示各式各樣的精靈,展示游戲內容。