【精品教程】Cocos2d-x v3.6制作射箭游戲(一)
最近玩了一個叫做大箭師鮑比的射箭游戲,覺得蠻好玩的,對此也產生了強烈的copy情結。所以從今天開始,我們將開始新的篇章,同大家分享這款基于 Cocos2d-x-3.6 引擎的游戲的一些制作心得,希望對大家有所幫助。
下圖是原版游戲的效果圖,有興趣的童鞋可以在網上找來玩玩。
PS:之前已寫過多次教程,現如今本人當然還是覺得寫初級教程要得心應手些(呵呵,畢竟能力所限),不過初級的寫的次數多了,也稍微有些厭煩了。所以,本教程我們將加大進度,游戲中所涉及到的一些基礎概念我們將不會做過多的陳述(當然必要的步驟還是會列舉出來的)。所以小白同志們注意了,如果根不上進度的請先看看基礎教程哦,這里推薦本人之前寫過的SLG游戲作為入門教程。
那么,下面我們就正式進入到游戲的開發吧。
前期須知
首先,本游戲所用引擎版本為 Cocos2d-x v3.6 ,開發工具用的是Xcode 5.1。
開發環境未配置的童鞋請先移步到這里將環境配置好。
Cocos2d-x 3.6 創建項目的方式與它之前的幾個版本并沒有什么區別,打開終端(Windows下是打開cmd)進入到引擎文件夾目錄,運行setup.py,然后再輸入以下命令行就可以創建一個新項目。
- cocos new arrowGame -p com.cocos2dx.rs -l cpp -d /Users/cocos2d-x/workspace/cocos2dx/projects
new:new后是項目名
-p :-p后是包名
-l :-l后是語言(cpp指c++)
-d :-d后是項目生成路徑
項目初配置
在新建的項目中已經有一些默認的文件和類,比如這里的 HelloWorldScene 類。它對于我們是沒用的,所以你可以把它刪除,然后再新建一個需要的游戲場景類。
在進行以上操作的時候,我們需要修改 AppDelegate.cpp 文件中相應的方法來啟動新建的游戲場景。如現在我們新建一個游戲場景類并命名為 GameScene,那么在 AppDelegate.cpp 文件的 applicationDidFinishLaunching() 方法中,我們需要***個就啟動它,而不是啟動原來的 HelloWorldScene。所以如下代碼所示修改 runWithScene 的場景:
- auto scene = GameScene::createScene();
- director->runWithScene(scene);
另外,本游戲所用游戲資源是按 864 * 480 的大小制作的,所以為了讓這套資源能應用到市場上各類分辨率大小的移動設備,接下來我們需要做的事是進行分辨率適配。
分辨率適配同樣在 applicationDidFinishLaunching 方法中進行,只需添加以下兩行代碼:
- glview->setDesignResolutionSize(480.0f, 320.0f, ResolutionPolicy::FIXED_HEIGHT);
- director->setContentScaleFactor(480.0f / 320.0f);
這里具體的原理我就不解釋了,請大家參考我之前的文章。
GameScene 場景分析
GameScene 場景是本游戲的主場景,開始游戲之前,我們先從原游戲的游戲場景中看看我們需要做些什么?
首先,對于游戲地圖,這里有一些排布整齊的磚塊、箱子、障礙物之類的圖塊。看到這個你是不是跟我一樣,***反應就是用 TiledMap 編輯器來編輯。不管你是不是,反正我是了,而且我也決定要用了。這樣一來,游戲中玩家和敵人的位置我們也可以通過 TiledMap 的對象屬性來標識了。
然后,游戲中玩家射出去的箭是呈拋物線射出去的,一般大家都會覺得這個功能只要讓箭執行貝塞爾動作就可以實現。但不要忘了,箭在按曲線移動的時候它的角度也在不停的變換,所以我們不能單純的認為很簡單,這個需要另辟蹊徑,重寫自己需要的貝塞爾動作!
當箭射出去后,它碰到磚塊、箱子時會有個一定的反彈效果,所以很顯然這里我們需要用物理引擎來實現這個模塊的功能。
先就分析到這里,下面我們來看看 GameScene 的聲明。
GameScene的聲明
其實 GameScene 與 HelloWorldScene 差不多,其初定義如下:
- #include "cocos2d.h"
- USING_NS_CC;
- class GameScene : public Layer
- {
- public:
- GameScene();
- static cocos2d::Scene* createScene();
- virtual bool init();
- void addGameBg();
- CREATE_FUNC(GameScene);
- private:
- Size winSize; // 窗口尺寸
- TMXTiledMap *map; // 地圖背景對象
- TMXObjectGroup * objectGroup; // 對象組對象
- float objectPosOffX; // 對象組X方向上的偏移值
- };
在 addGameBg 方法中我們將載入游戲背景,這里我們把游戲背景分為如下的兩部分,一部分是背景圖片,另一部分是地圖背景。這樣的組合有利于關卡設計中多樣性的搭配。
#p#
地圖背景
地圖背景是用 TiledMap 編輯器制作出來的,本游戲中它是由27*15個相同大小的圖塊(32*32)組合而來(透明的地方沒有圖塊)。從上圖你也可以看出,我們已在地圖上設置了當前關卡地形的大致布局。另外,我們之前不是說好要用 TiledMap 的對象屬性來標識玩家和敵人的位置嗎,下面就是 TiledMap 中添加了對象的例子。
注意:對象是為了能讓開發更方便而設計的,它并不對應于某個地圖圖片,只是標明了某個透明物體的位置/形狀/大小等屬性,這樣開發者就可以通過相關 API 獲取某個對象的位置,從而在相應的位置繪制真實看的見的 Node 對象了。我們在制作 TiledMap 地圖時,可以想上圖一樣給對象取一個標示它的名字,這樣我們就可以通過對象的名字來獲取到它的位置等信息了。對象常常用于添加除背景以外的游戲元素(如道具、障礙物等)。
創建教程中的地圖大致可分為以下兩個步驟:
- 創建普通圖層 “logicLayer”,我們在這上邊放置看的到的圖塊。如地圖中的磚塊、箱子、草地等等。這里我們可以根據自己的想法,創建出各種類型的地圖樣式。
- 創建對象層“object”,同時在對象層上創建各個對象,并給每個對象添加名字屬性。
初學者如果想了解更多詳細的地圖制作過程,可參考Quick-Cocos2d-x初學者游戲教程(七)一文。
載入程序
介紹了地圖背景之后,接下來我們就來看看 addGameBg 的實現,如下所示:
- void GameScene::addGameBg(){
- // 添加圖片背景,把它放在屏幕正中間
- Sprite* spGameBg = Sprite::create("bg1.jpg");
- spGameBg->setPosition(Vec2(winSize.width/2, winSize.height/2));
- this->addChild(spGameBg, -1);
- // 添加地圖背景,把它放在屏幕正中間
- map = TMXTiledMap::create("map1.tmx");
- map->setAnchorPoint(Vec2(0.5f, 0.5f));
- map->setPosition(Vec2(winSize.width / 2, winSize.height/2));
- this->addChild(map, -1);
- // 獲取 objectGroup 對象(也就是地圖中的對象層)
- objectGroup = map->getObjectGroup("object");
- // 計算對象組在 X 方向上的偏移值
- objectPosOffX = -(map->getContentSize().width - winSize.width) / 2;
- }
將 TiledMap 制作出的 .tmx 地圖文件加載到游戲中需要用到 Cocos2dx 提供的 TMXTiledMap 類,它可以直接通過 .tmx 文件名來創建瓦片地圖。
TMXTiledMap 類有很多方法可以操控我們的 地圖文件,如上代碼所示的 getObjectGroup 方法,它可以獲取對應名稱的對象層。
這里需要特別說明的是 objectPosOffX 這個屬性。由于對象組中對象的位置坐標是從屏幕的(0, 0)點開始的,所以當我們把地圖背景放置在屏幕中間時,地圖可能超出屏幕外或不足填滿整個窗口,這時對象的坐標就可能會出現如下圖所示的偏移。
所以,我們需要計算出對象的偏移值,以便后面獲取對象時修正它的位置。
好了,此時你在 init 方法中調用 addGameBg() 就可以看到游戲背景了。
PS:是不是覺得背景兩邊被裁減了,是的,不過不要以為出錯了,因為我們要的就是這個效果,這是分辨率適配下選擇 FIXED_HEIGHT 模式的后遺癥。這也是為什么我們要計算對象組在 X 方向上的偏移值的原因。
這章就講到這里,下章我將添加射箭的玩家,敬請期待。