一、前提:
完成Hello Game項目的創建編譯。
具體參考:Cocos2dx.3x_Hello Game項目創建篇
二、本篇目標:
l 分析proj.win32工程的主要構成
l 分析proj.android工程的主要構成
l 新建一個MyScene.cpp然后在游戲中顯示出來
l 在android真機上運行查看效果
三、分析:
我們游戲開發通常是這樣的,首先在Microsoft Visual Studio 2012中proj.win32工程編寫代碼並且在windows上調試運行,當游戲主體開發完成后,進行so文件的編譯打包,然后繼續在eclipse的proj.android工程中編寫少量的代碼完成游戲在android平台下的打包開發。
l 分析proj.win32工程的主要構成
用Microsoft Visual Studio 2012打開proj.win32工程
組成:
整個hellogame的解決方案由hellogame、libbox2d、libcocos2d、libSpine四個工程項目構成。
1、Hellogame工程:游戲主工程,我們開發工作主要在這個工程中完成
2、libbox2d工程:模擬2D剛體物體的C++物理引擎,大名鼎鼎植物大戰僵屍、憤怒的小鳥等游戲均有這個引擎的功勞
3、libcocos2d工程:這個不用說了,整個cocos2dx核心
4、libSpine工程:工具軟件支持庫
接下來主要對Hellogame工程的代碼進行解析,libbox2d工程在后面的物理引擎篇的時候在進行講解,至於其它2個工程在后續使用到的篇幅中在進行講解。
Hellogame工程的源代碼:
工程主要由src目錄下的AppDelegate.cpp、AppDelegate.h、HelloWorldScene.cpp、HelloWorldScene.h四個源文件和win32目錄下的main.cpp、main.h兩個源文件組成。
src目錄下的源文件是所有6個平台共用的代碼文件,不管是android還是ios都使用這個目錄下的源文件,屬於真正跨平台部分的代碼。
win32目錄下的源文件只是一個main主入口文件,負責win32平台下對游戲的調用。其實在對應的proj.android的工程里也有一個android平台對應的main主入口文件,只是由於平台的不同實現代碼也各有不同,但是目的一樣。
AppDelegate.cpp源代碼:
AppDelegate類似於android的Application的作用,提供一些應用程序級別的狀態的回調,整個游戲應用程序由這個文件方法進行控制。下面是幾個主要方法的說明和解釋:
#include "AppDelegate.h" #include "HelloWorldScene.h" //命名空間宏,偷懶引入cocos2d的頭文件 USING_NS_CC; AppDelegate::AppDelegate() { } AppDelegate::~AppDelegate() { } //設置 OpenGL context //這個設置對所有平台都有效 void AppDelegate::initGLContextAttrs() { //設置 OpenGL context 屬性,目前只能設置6個屬性 //red,green,blue,alpha,depth,stencil GLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8}; GLView::setGLContextAttrs(glContextAttrs); } //當應用程序啟動時執行,游戲程序啟動入口 //在這里我們啟動了第一個scene(場景) //在具體游戲中通常在這里啟動loading界面 //你的游戲從這里開始! bool AppDelegate::applicationDidFinishLaunching() { // 初始化 director auto director = Director::getInstance(); auto glview = director->getOpenGLView(); if(!glview) { glview = GLViewImpl::create("My Game"); director->setOpenGLView(glview); } // 在屏幕上顯示FPS數 // 開發階段建議開啟這個設置,可以通過這個對自己游戲性能有個大體了解 // 等游戲正式發布時關閉這個設置 director->setDisplayStats(true); // 設置 FPS數 默認值為 1.0/60 director->setAnimationInterval(1.0 / 60); // 創建一個HelloWorld的scene.這個是自動回收的對象 auto scene = HelloWorld::createScene(); // 告訴director運行HelloWorld的scene director->runWithScene(scene); return true; } // 當游戲進入后台時會調用這個方法 // 比如玩游戲時按下android手機的home按鍵 // 比如當游戲時有電話打入直接顯示來電界面 void AppDelegate::applicationDidEnterBackground() { Director::getInstance()->stopAnimation(); // 如果你的游戲使用了SimpleAudioEngine,必須在這里進行暫停 // 暫停代碼如下: // SimpleAudioEngine::getInstance()->pauseBackgroundMusic(); } // 當游戲恢復到前台運行時會調用這個方法 // 比如接電話結束是游戲界面又恢復到前台時 void AppDelegate::applicationWillEnterForeground() { Director::getInstance()->startAnimation(); // 如果你的游戲使用了SimpleAudioEngine, 必須在這里進行恢復 // 恢復代碼如下: // SimpleAudioEngine::getInstance()->resumeBackgroundMusic(); }
上述代碼解釋中的提到的director(導演:負責游戲場景的顯示切換等,像電影導演一樣掌控整個電影的一切)、scene(場景:負責顯示一個游戲場景,就像電影的一個場景鏡頭)。
上面代碼中最重要的方法為applicationDidFinishLaunching(),因為你的游戲從這個方法開始!
HelloWorldScene.cpp源代碼:
上面代碼中在AppDelegate類的applicationDidFinishLaunching()方法中創建了一個HelloWorldScene的場景,並且運行這個場景,HelloWorldScene.cpp就是這個場景具體的代碼實現。下面是幾個主要方法的說明和解釋:
#include "HelloWorldScene.h" USING_NS_CC; //創建場景 Scene* HelloWorld::createScene() { //創建一個自釋放的場景對象 auto scene = Scene::create(); //創建一個自釋放的畫面層對象 auto layer = HelloWorld::create(); //把創建的畫面層添加到場景中 //一個場景可以添加多個畫面層 scene->addChild(layer); //返回這個創建的場景 return scene; } // 場景初始化方法 bool HelloWorld::init() { // 1. 首先進行父類初始化 if ( !Layer::init() ) { //如果初始化父類失敗返回false return false; } //獲取整個手機可視屏幕尺寸 Size visibleSize = Director::getInstance()->getVisibleSize(); //獲取手機可視屏原點的坐標 Vec2 origin = Director::getInstance()->getVisibleOrigin(); // 創建一個帶圖標的關閉按鈕 // 點擊后調用menuCloseCallback方法退出游戲 auto closeItem = MenuItemImage::create( "CloseNormal.png", "CloseSelected.png", CC_CALLBACK_1(HelloWorld::menuCloseCallback, this)); // 設置關閉按鈕的顯示位置 // 顯示在可視屏幕的右下角 closeItem->setPosition(Vec2(origin.x + visibleSize.width - closeItem->getContentSize().width/2 , origin.y + closeItem->getContentSize().height/2)); // 創建一個可自釋放的菜單 auto menu = Menu::create(closeItem, NULL); menu->setPosition(Vec2::ZERO); this->addChild(menu, 1); //創建一個顯示"Hello Game"文字的Label auto label = Label::createWithTTF("Hello Game", "fonts/Marker Felt.ttf", 24); // 設置label在屏幕中的顯示位置 label->setPosition(Vec2(origin.x + visibleSize.width/2, origin.y + visibleSize.height - label->getContentSize().height)); // 把label添加到畫面層 this->addChild(label, 1); // 創建一個帶圖片的精靈 auto sprite = Sprite::create("HelloWorld.png"); // 設置圖片精靈的顯示位置 sprite->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y)); // 添加圖片精靈到畫面層 this->addChild(sprite, 0); return true; } // 退出按鈕事件 void HelloWorld::menuCloseCallback(Ref* pSender) { //當是wp8或者winrt平台的時候 #if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert"); return; #endif //結束Director Director::getInstance()->end(); //當是ios平台的時候退出 #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) exit(0); #endif }
上述的代碼是一個簡單的Scene(場景)實現代碼,當我們真正開發游戲時,其實就是制作一個一個的場景,並且通過Director進行調度組織構成一個完整的游戲。
l 分析proj.android工程的主要構成
用eclipse打開proj.android工程
組成:
整個hellogame的相比win32的要簡單多了,除了android項目必須的一些組成部分之外:
1、 Classes文件夾:這里面的源文件和上面proj.win32中的屬於同一份共享。
2、 jni/hellocpp/main.cpp:這個相當於proj.win32中的win32目錄下的源文件,主入口。
3、 libs/armeabi/libcocos2dcpp.so:這個是整個游戲代碼的編譯包,其實真正游戲代碼實現都最終由C++文件編譯打包成這個so類庫供android代碼調用運行游戲。
整個游戲的開發基本上不需要在eclipse中編寫代碼,android平台只需要調用編譯好的so文件即可運行游戲,eclipse中只需要把包含了so文件的android工程打包成apk文件發布即可。
l 新建一個MyScene.cpp然后在游戲中顯示出來
用Microsoft Visual Studio 2012打開proj.win32工程,我們將在這個工程里新加一個自己的Scence(場景)並且顯示出來。這個看着是個很簡單的任務但是對新手來說還是會碰到很多困難,所以這里特別的做一下演示。
文件新建:cpp文件這里有2個新建方法,
1、第一種方式
第一步:在右邊的解決方案資源管理器中右鍵src新建類。
問題:到這里你會發現“瀏覽”按鈕不可以用,新建的cpp只能新建到目錄hellogame\proj.win32下,這樣會導致一個問題。
第二步:先不管這個我們按照提示繼續點擊“添加”進入類向導界面輸入類名MyScene然后點擊完成類的創建,這個時候在proj.win32目錄下新加MyScene.cpp和MyScene.h兩個文件。
2、第二種方式
第一步:在右邊的解決方案資源管理器中右鍵src新建項
問題:到這里你會發現“瀏覽”按鈕可以用,點擊修改一下目錄為hellogame\Classes下,而且需要選擇是新建.ccp文件還是.h文件.
第二步:這里先選擇.cpp類型然后輸入MyScene.cpp然后完成創建,然后繼續前面的步驟新建MyScene.h文件。這個時候在Classes目錄下會出現新加的MyScene.cpp和MyScene.h兩個文件。
代碼編寫:
MyScene.h:
#include "cocos2d.h" class MyScene : public cocos2d::Layer { public: static cocos2d::Scene* createScene(); virtual bool init(); CREATE_FUNC(MyScene); }; MyScene.cpp: #include "MyScene.h" USING_NS_CC; Scene* MyScene::createScene() { auto scene=Scene::create(); auto layer=MyScene::create(); scene->addChild(layer); return scene; } bool MyScene::init() { if(!Layer::init()) { return false; } //獲取整個手機可視屏幕尺寸 Size visibleSize = Director::getInstance()->getVisibleSize(); //獲取手機可視屏原點的坐標 Vec2 origin = Director::getInstance()->getVisibleOrigin(); //創建一個顯示"MyScene"文字的Label auto label = Label::createWithTTF("MyScene", "fonts/Marker Felt.ttf", 24); //設置白色 label->setColor(Color3B::WHITE); // 設置label在屏幕中的顯示位置 label->setPosition(Vec2(origin.x + visibleSize.width/2, origin.y + visibleSize.height - label->getContentSize().height)); // 把label添加到畫面層 this->addChild(label, 1); return true; }
完成MyScene編寫后,我們要先在游戲開啟后的界面中添加一個按鈕菜單點擊后進入MyScene 場景。游戲開啟后的界面場景是HelloWorldScene,所以我們需要在HelloWorldScene中添加一個按鈕,並且為這個按鈕添加一個點擊啟動MyScene的事件。
HelloWorldScene.h:
在這個文件中首先聲明一個按鈕點擊事件:
//切換到下一個scene事件
void menuNextCallback(cocos2d::Ref* pSender);
HelloWorldScene.cpp: 1、首先引入MyScene.h #include "HelloWorldScene.h" #include "MyScene.h" USING_NS_CC; …… 2、實現menuNextCallback事件代碼 // 按鈕點擊事件,點擊后啟動MyScene void HelloWorld::menuNextCallback(Ref* pSender) { //新建MyScene實例 auto scene = MyScene::createScene(); //用這MyScene實例替換當前scene Director::getInstance()->replaceScene(scene); } 4、 添加在屏幕上添加啟動按鈕 …… // 設置關閉按鈕的顯示位置 // 顯示在可視屏幕的右下角 closeItem->setPosition(Vec2(origin.x + visibleSize.width - closeItem->getContentSize().width/2 , origin.y + closeItem->getContentSize().height/2)); // 新建一個帶圖片的按鈕菜單 auto goItem=MenuItemImage::create("next_1.png","next_2.png", CC_CALLBACK_1(HelloWorld::menuNextCallback, this)); goItem->setPosition(Vec2(origin.x + visibleSize.width/2 - closeItem->getContentSize().width/2 ,origin.y/2 + closeItem->getContentSize().height/2)); // 創建一個可自釋放的菜單 auto menu = Menu::create(closeItem,goItem, NULL); menu->setPosition(Vec2::ZERO); this->addChild(menu, 1); ……
好了到此為止我們完成了所有代碼的編寫,現在開始調試運行查看一下效果。
問題:
這個時候如果你是用第二中方法創建的MyScene能正常編譯運行而第一種方法創建的MyScene會發無法通過編譯沒辦法運行會報如下錯誤:
IntelliSense: 無法打開 源 文件 "MyScene.h"
error C1083: 無法打開包括文件:“MyScene.h”: No such file or directory
解決:
第一步:項目名點擊右鍵屬性
第二步:選擇左邊的C/C++然后在右邊的附加包含目錄追添加:;$(ProjectDir)
這個是我本人的附加包含目錄,每個人環境不同應該有點區別
$(EngineRoot)cocos\audio\include;$(EngineRoot)external;$(EngineRoot)external\chipmunk\include\chipmunk;$(EngineRoot)extensions;..\Classes;..;%(AdditionalIncludeDirectories) ;$(ProjectDir)
完成如上設置后在進行項目調試運行就能正常運行起來了,並且點擊按鈕后成功的顯示MyScene的畫面達到了我們設定的目標。
l 在android真機上運行查看效果
要在android真機運行,首先需要進行so文件的打包編譯。
第一步:如果上面的步驟中是按照第一種方法創建的MyScene那么請把MyScene.cpp、MyScene.h兩個文件從proj.win32文件拷貝到Classes文件夾下。如果是按照第二種方法創建的MyScene那么可以忽略本步驟。
第二步:用EditPlus等文本編輯器打開proj.android\jni目錄下的Android.mk文件,把MyScene.cpp添加到需要編譯的源文件清單中然后保存,如下:
……
LOCAL_SRC_FILES := hellocpp/main.cpp \
../../Classes/AppDelegate.cpp \
../../Classes/HelloWorldScene.cpp \
../../Classes/MyScene.cpp
……
第三步:開啟Cygwin開始編譯打包so文件,如果不會請參考:Cocos2dx.3x_Hello Game項目創建篇
第四步:打包so文件成功后,然后開啟eclipse打開游戲工程並且連接android手機運行工程看看真機運行的效果是否跟前面windows中的效果是否一樣。
結束語:
Cocos2d-x3.3入門三部曲到這里就算是完成了,接下來將以具體一個游戲為一個系列的方式繼續深入實戰,第一個實戰系列為:《Cocos2d-x3.x塔防游戲(保衛蘿卜)從零開始》,這個系列總共有多少篇待定,目標是直到做完一個完整的符合上線標准的游戲為止絕非草草的練習之作。
作者交流QQ:2303452599
郵箱:mymoney1001@126.com