尊重開發人員的勞動成果,轉載的時候請務必註明出處:http://blog.csdn.net/haomengzhu/article/details/27186557
Hello World 分析
開啟建立的"findmistress"項目,可以看到專案檔是由多個代碼檔案及檔案夾組成的,其中 Hello World 的代碼檔案直接存放於該專案檔夾中。下面我們來詳細介紹一下項目的檔案組成。1."resource"該檔案夾主要用於存放遊戲中需要的圖片、音頻和配置等資源檔。為了方便管理,可以在其中建立子檔案夾。在不同平台下,對於檔案路徑的定義是不一致的,但實際介面大同小異。Cocos2d-x 為我們屏蔽了這些差異,其中"resource"檔案夾可以預設為遊戲運行時的目錄。
還記得上一節我們運行起來的遊戲嗎?遊戲中顯示的 Cocos2d-x 標誌就放在這個檔案夾下面。除此之外,這個檔案夾還儲存了遊戲左下角 FPS 的字型以及離開遊戲按鈕上的圖片。
2."Classes"和“proj.win32” 檔案夾這兩個檔案夾用於放置遊戲標頭檔和原始碼檔案。可以看到,項目模板為我們添加的三個檔案分別為"main.h"、"main.cpp"和"resource.h",它們是平台相關的程式檔案,為 Windows 專有。通常情況下,程式入口與資源檔管理在不同平台下是不同的,但是 Cocos2d-x 的模板已經基本為我們處理好了這些細節,不需要對它們進行修改。
3."AppDelegate.h" 和 "AppDelegate.cpp" 檔案這兩個檔案是 Cocos2d-x 遊戲的通用入口檔案,類似於一般 Windows 工程中主函數所在的檔案。接觸過 iOS 開發的讀者應 該會覺得這兩個檔案的名字似曾相識,其實 AppDelegate 在 iOS 工程中就是程式的入口檔案,在介紹引擎曆史的時候曾提到過。 Cocos2d-x 來源於 Cocos2d-iPhone,因此無論是代碼風格還是檔案結構,很多方面都沿襲了 Cocos2d-iPhone 的使用習慣。以後文章中,將詳細介紹 Cocos2d-x 的代碼風格與檔案結構。
開啟"AppDelegate.cpp",我們可以看到已經自動添加的代碼,這個檔案實現了 AppDelegate 類。AppDelegate 控制著遊戲的生命週期,除去建構函式和解構函式外,共有 3 個方法,下面我們將逐個介紹。
bool applicationDidFinishLaunching()。應用程式啟動後將調用這個方法。預設的實現中已經包含了遊戲啟動後的必要準備:
//初始化遊戲引擎控制器 Director,以便啟動遊戲引擎 // initialize director auto director = Director::getInstance(); auto glview = director->getOpenGLView(); if(!glview) { glview = GLView::create("My Game"); director->setOpenGLView(glview); }
//啟用 FPS 顯示director->setDisplayStats(true);
//設定繪製間隔 director->setAnimationInterval(1.0 / 60); // create a scene. it's an autorelease object auto scene = HelloWorld::createScene();
// run director->runWithScene(scene);
return true;
這段代碼首先對引擎進行必要的初始化,然後開啟了 FPS 顯示。FPS 即每秒畫面播放速率,也就是螢幕每秒重繪的次數。啟用了FPS 顯示後,當前 FPS 會在遊戲的左下角顯示。通常在遊戲開發階段,我們會啟用 FPS 顯示,這樣就可以方便地確定遊戲運行是否流暢。
接下來是設定繪製間隔。繪製間隔指的是兩次繪製的時間間隔,因此繪製間隔的倒數就是 FPS 上限。對於行動裝置來說,我們通常都會將 FPS 限制在一個適當的範圍內。過低的每秒重繪次數會使動畫顯示出卡頓的現象,而提高每秒重繪次數會導致裝置運算量大幅增加,造成更高的能耗。人眼的重新整理頻率約為 60 次每秒,因此把 FPS 限定在 60 是一個較為合理的設定,Cocos2d-x 就把繪製間隔設定為 1/60 秒。至此,我們已經完成了引擎的初始化,接下來我們將啟動引擎。
最後也是最關鍵的步驟,那就是建立 Hello World 情境,然後指派 Director 運行這個情境。對於遊戲開發人員而言,我們需要在此處來對我們的遊戲進行其他必要的初始化,例如讀取遊戲設定、初始化隨機數列表等。程式的最末端返回 true,表示程式已經正常初始化。
void applicationDidEnterBackground()。當應用程式將要進入後台時,會調用這個方法。具體來說,當使用者把程式切換到後台,或手機接到電話或簡訊後程式被系統切換到後台時,會調用這個方法。此時,應該暫停遊戲中現正播放的音樂或音效。動作激烈的遊戲通常也應該在此時進行暫停操作,以便玩家暫時離開遊戲時不會遭受重大損失。
void applicationWillEnterForeground()。該方法與 applicationDidEnterBackground()成對出現,在應用程式回到前台 時被調用。相對地,我們通常在這裡繼續播放剛才暫停音樂,顯示遊戲暫停菜單等。
"HelloWorldScene.h"與"HelloWorldScene.cpp"檔案。這兩個檔案定義了 Hello World 項目中預設的遊戲情境。
Cocos2d 的遊戲結構可以簡單地概括為情境、層、精靈,而這兩個檔案就是 Hello World 情境的實現檔案。每個遊戲組件都可以添加到另一個組件中,形成層次關係,例如情境中可以包含多個層,層中可以包含多個精靈。在後續文章中,我們將詳細講解Cocos2d 遊戲元素的概念,此處將不詳細說明是如何建立出 Hello World 情境的。
HelloWorldScene 中定義了一個 HelloWorld 類,該類繼承自 cocos2d::Layer,因此 HelloWorld 本身是一個層。HelloWorld 類包含一個靜態函數和兩個執行個體方法,下面我們來看其中比較重要的兩個成員。
static cocos2d::Scene* createScene()。在 Cocos2d 中,在層下設定一個建立情境的靜態函數是一個常見的技巧。我們為 HelloWorld層編寫了 Layer 的一個子類,在子類中為層添加各種精靈或是邏輯處理代碼。然而我們的 Hello World 情境十分簡單,只包含了一個層,沒有任何其他需要處理的問題。因此,我們除了建立 Scene 的一個子類之外,也可以直接使用靜態函數來建立一個空情境,再把層置入情境之中,這樣也十分便捷,範例程式碼如下所示:
// 'scene' is an autorelease object auto scene = Scene::create(); // 'layer' is an autorelease object auto layer = HelloWorld::create();
// add layer as a child to scene scene->addChild(layer);
在這段代碼中, 首先利用 Scene::create方法建立了一個空情境, 然後利用Hello world::create方法建立一個HelloWorld層的執行個體,最後調用 scene 對象的 addChild 方法來把建立的層添加到情境之中。
這是我們第一次見到 addChild 方法,這個方法可以把一個遊戲元素放置到另一個元素之中。只有把一個遊戲元素放置到其他已經呈現出來的遊戲元素中,它才會呈現出來。比如在這個例子中,我們把 HelloWorld 層置入到上面建立的空情境中,而在前面所述的 AddDelegate 中,我們已經讓 Director 運行了該情境,因此 HelloWorld 層就會顯示在螢幕上了。
bool init()。初始化 HelloWorld 類,相關代碼如下://(1) 對父類進行初始化 if ( !Layer::init() ) { return false; }
//(2) 建立菜單並添加到層 auto closeItem = MenuItemImage::create( "CloseNormal.png", "CloseSelected.png", CC_CALLBACK_1(HelloWorld::menuCloseCallback, this)); closeItem->setPosition(Point(origin.x + visibleSize.width - closeItem->getContentSize().width/2 , origin.y + closeItem->getContentSize().height/2));
// create menu, it's an autorelease object auto menu = Menu::create(closeItem, NULL); menu->setPosition(Point::ZERO); this->addChild(menu, 1);
//(3) 建立"Hello World"標籤並添加到層中 auto label = LabelTTF::create("Hello World", "Arial", 24); // position the label on the center of the screen label->setPosition(Point(origin.x + visibleSize.width/2, origin.y + visibleSize.height - label->getContentSize().height));
// add the label as a child to this layer this->addChild(label, 1);
//(4) 建立顯示“HelloWorld.png”的精靈並添加到層中 // add "HelloWorld" splash screen" auto sprite = Sprite::create("HelloWorld.png");
// position the sprite on the center of the screen sprite->setPosition(Point(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
// add the sprite as a child to this layer this->addChild(sprite, 0);
這段代碼可以簡單地劃分為 4 個部分。調用父類的 init 方法來進行最初的初始化。建立關閉程式的菜單並添加到層中。這裡,我們遇到了 addChild(Node* child,int zOrder),與之前遇到的 addChild 方法多出來了一個參數 zOrder,該參數指的是 child 的 Z 軸順序,也就是顯示的先後順序,其值越大,表示顯示的位置就越靠前。setPosition 方法用來設定遊戲元素的位置。
關於菜單以及下面提到的文字標籤,我們也會在後面的章節中詳細介紹。建立一個文字標籤並添加到層中,顯示內容"Hello World"。用"HelloWorld.png"建立一個精靈並添加到層中。最後程式返回 true,表示初始化成功。此時讀者可能會有疑惑,為什麼我們要在一個執行個體方法中初始化類,而不在建構函式中初始化呢?
在 C++中,一般習慣在建構函式中初始化類,然而由於 Cocos2d-x 的來源特殊,所以才沒有採用 C++的編程風格。關於編程風格,我們會在以後的文章中詳細討論。