Cocosbuilder使用教程

轉自:http://article.ityran.com/archives/2544

轉自:http://article.ityran.com/archives/2544

手把手教你使用CocosBuilder一次性導出Cocos2d-html5,Cocos2d-x和Cocos2d-iPhone的遊戲資源文件。這個遊戲90%的工作量是用工具完成。

這篇教程將會展示如何使用 CocosBuildercocos2d-iphone製作遊戲的動作,地圖場景和界面。CocosBuilder 已經被Zynga 使用在遊戲Dream PetHouse 和 Zynga Slots開發中。目前,由於若干遊戲使用CocosBuilder,Zynga 索性將其開源出來(MIT License)。未來必定有更多的遊戲在開發中使用該工具。
這篇文章是建立在你很熟悉object-c以及cocos2d-iphone或者cocos2d-x的基礎上的。如果你希望學習cocos2d,泰然也有很多文章推薦給你。
在開始本文之前,確保你下載並安裝了CocosBuilder 的最新版(本教程基於2.1beta版本)並且升級cocos2d2.0或cocos2d-x的2.03版本以上。

The Game

我們將創造遊戲主角Cocos Dragon。Cocos Dragon有一對很小的翅膀因此他飛不高,所以我們需要讓他觸碰金幣來給他加速上升直到碰到炸彈爲止。你可以到youtube看這個遊戲的視屏:youtube

本遊戲可以在iOS模擬器上運行,遊戲通過觸摸來操作方向。假如你希望把這個遊戲設計運用到你的產品中,我推薦你用重力感應來替換觸摸方式。

設置工程

建立新的xcode工程。工程名稱:CocosDragon。

下載本教程需要用到的美術資源,解壓並加到工程中。
現在我們需要建立遊戲相應的CocosBuilder 工程。打開CocosBuilder 選擇File ->New Project。命名爲CocosDragon 保存並把資源文件放到xcode的Resources 文件夾(CocosBuilder的資源在一個名爲ccbResources的文件夾)打開theHelloCocosBuilder.ccb文件.我們不會使用HelloCocosBuilder 文件,所以你可以在CocosBuilder文件系統中幹掉他。

創建動畫類型的主界面

我們將開始製作Cocos Dragon所有的界面文件,然後將界面鏈接到相應的代碼中。首先,我們創建一個主菜單。
在CocosBuilder打開的CocosDragon 工程中選擇File->New File。我們將讓主界面只支持iPhone,所以在resolutions settings(方案設置)中勾選iPhone Portrait ,並確保root object type(根對象類型)爲CCLayer 並勾選full screen (全屏)。

點擊創建,然後命名爲“ MainMenuScene ”並且保存到Resources 文件夾。一個新的空文件MainMenuScene.ccb將在CocosBuilder中開啓。

主界面我們會包含一個漸變的背景,一個logo,一個開始遊戲的按鈕,和幾片雲彩的動畫。首先,讓我們開始加入漸變的背景。在窗口頂部的工具欄點擊CCLayerGradient 按鈕。

我們希望漸變層(gradient layer)充滿整個屏幕。選擇這個層,設置填充(content size)大小單位爲“%”並且設置寬高爲100×100.

讓我們把顏色修改爲其他值以遍更適合我們遊戲的主色調。點擊開始顏色(start color)和完成顏色( end color)以至RGB值爲下圖顯示這樣。

繼續添加logo到主界面( menu scene)。在左邊的工程視圖(project view)中,拖拽logo.png到canvas 區域。你添加的圖片就會像如下那樣顯示:

當啓動主選單場景時會有漂亮的動畫,但是我們還需要在啓動時增加logo的動畫。首先,點擊canvas 區域下面的時間設置來指定動畫的長度。這裏我們把動畫出現的時間線設置爲2秒。

現在,我們把logo視爲一個精靈,並設置logo精靈的關鍵幀(keyframes )。拖拽時間戳到動畫完成的地方(我們這個工程就是之前設置的 00:02:00),並且確保logo已經被選定。在動畫菜單中選擇插入關鍵幀位置(Keyframe /Position),或者使用快捷鍵’P’.在時間線界面(timeline view),logo精靈會摺疊並顯示剛纔添加的關鍵幀。

一旦關鍵幀插入時間線的節點中,我們節點的位置既可以自動添加新的關鍵幀。首先,移動時間戳到原點(00:00:00的位置)。然後,拖拽logo到繪圖界面( canvas area)的頂部可見區域(你可以在拖拽的時候按住shift按鈕以便對齊)。當你正在做以上操作時,一個新的關鍵幀就被自動添加到時間線的原點處,並且我們在兩個關鍵幀中間生成平滑過渡的所有幀。

你可以點擊Play來測試一下這個動畫。你也可以移動時間戳來看看每個幀的位置。

這個動畫我們完成的很漂亮並且每幀的過渡很平滑,但是讓我們再加點料。在關鍵幀之間右擊 插值線(譯者注:interpolation line,就是插入了過渡幀的地方)並且選擇彈出(Bounce Out)。

OK,我們讓logo被覆蓋了,但是我們依然需要一個啓動遊戲的按鈕。我們將用CCMenu CCMenuItemImage來實現這個功能。那麼,開始添加菜單功能,在工具欄中點擊CCMenu按鈕。如下圖:

一個CCMenu 將會添加到你的文件中。CCMenu 保持選中狀態,在工具欄點擊CCMenuItemImage 按鈕(在CCMenu按鈕右邊)。CCMenuItemImage 會在可是換編輯區域左下角顯示一個佔位符圖像。

拖動這個圖片到屏幕中間,也可以使用Cmd+方向鍵或者 Cmd+shift+方向鍵來精準拖動,檢視器( inspector)中輸入需要的值。選中CCMenuItemImage ,選擇你希望菜單顯示的其他圖片樣式。通常情況,未按下時我們使用圖片名稱“play-button.png”,按下時我們使用“ play-button-down.png”。

我們現在又一個帶logo和play 按鈕的選擇菜單場景,但是這還是感覺有點空蕩蕩的。所以我們加入一些雲彩來充實一下。在工程界面,拖拽一些雲 彩到可視化區域。你可以拖拽圖片的邊角來改變雲彩的大小。要改變雲彩的遮蓋(z-order)可以在時間線區域將相應的時間線拖到上面或者下面,當然也可 以在對象選項中(Object menu)選擇Arrange / Bring放到上層,選擇Arrange / Send放到下層。

現在讓我們添加雲彩的介紹動畫。這就像之前logo精靈那樣做就好。把時間戳移動到動畫的末尾。給每個雲彩和play按鈕添加一個關鍵幀。你可以選 中每個雲彩然後點擊快捷鍵‘p’。當關鍵幀已經被添加到所有對象的動畫末尾後,把時間戳移動到動畫開頭。現在拖拽每個雲彩,讓底部

點擊‘Play’來測試動畫。我們現在有一個很漂亮的主菜單介紹動畫。當動畫播放完畢後,整個場景就是完全禁止的。這不是很好,所以後面我們還會完善。

CocosBuilder提供了多個時間線。在文件中,多個時間線可以連續或者不連續播放,也可以通過代碼控制回放。兩個不同動畫的時間線可以實現平滑過渡。我們這個工程會實現多個時間線,當介紹動畫的時間線播放完成後,會循環播放另一個動畫。

在動畫菜單選擇編輯時間線(Edit Timelines)。在彈出框中,先將默認的時間線重命名爲Intro。然後點擊plus-sign添加一條時間線並命名爲Loop,點擊完成。

我們選擇要編輯的時間線,點擊drop-down按鈕(圖上已經標出),選中Timelines->Loop。

現在我們有一條未添加關鍵幀的時間線。這條時間線默認是10秒鐘,我們的工程剛好就要這麼長。爲了方便看出完成後的長度,你可以拖動比例條(scale slider)到左邊。

雖然只是一個很小的動畫,但可以給場景帶來生機。選擇一片雲彩。將時間戳拖到起點,點擊快捷鍵’s'。這將會給比例屬性添加一個關鍵幀。現在把時間 戳拖動到時間線末尾並再次點擊快捷鍵‘s’。這將會在動畫末尾添加一個關鍵幀。注意,這條線表示插入的view將會輕微淡出。這是因爲兩個關鍵幀是完全一 樣的,所以沒有動畫產生。現在這個情況就已經不錯了,因爲我們希望動畫的首尾相同,以便重複播放。

按住option鍵點擊兩個關鍵幀中間,就在時間線的開頭和結尾之間添加一個新的關鍵幀。點擊這個新建的關鍵幀讓它出於選中狀態,通過調整比例值,或者拖動雲彩,讓雲彩稍微變大一點。

回放動畫,你可以看到一片雲彩慢慢變大,然後再變回原始大小。讓我們給每片雲彩做相同的操作。點擊所有的關鍵幀讓選擇框包含他們。你也可以用shift來選中。選中後,在Edit菜單選擇 複製。把時間戳移動到時間線原點,選擇另一片雲彩點擊粘貼。並重覆在所有云彩中操作(並沒有添加關鍵幀)。

再次回放動畫。你可以看到所有的雲彩都按比例做放大縮小動作了,但是他們是在同時放大縮小,這很古怪,不是嗎?點擊每片雲彩,延伸時間線,並移動中間那個關鍵幀的位置。這樣就會讓雲彩在不同時間播放動畫了。多試幾次你就會有經驗調整到合適的長度了。

最後,我們要讓動畫在我們需要的時候自動循環,就要用到鏈式時間線功能(chain timeline )。點擊時間線編輯器左下角的文本,這裏顯示沒有鏈式時間線。彈出框中點擊 循環(loop)。這就會讓動畫自動循環了。

現在回到介紹動畫的時間線(點擊時間線drop-down菜單,選擇Timelines -> Intro)。在Intro右邊完成的地方鏈接 Loop時間線。當我們用代碼調用這個場景時,會自動播放Intro動畫,Intro完成後回循環播放Loop動畫。

主菜單的大部分已經完成,我們剩下的僅僅是在代碼中調用這個界面。要調用這個場景,我們要給根節點設置一個定製類。選擇根節點(在文件document的CCLayer中)。設置類名爲“MainMenuScene”。我們會在稍後在代碼中創建MainMenuScene。

選擇Play按鈕。進入CCMenuItem下的pressedPlay:進入選擇器的輸入框,選擇目標“Document root”。當我們點擊按鈕pressedPlay:文件根節點方法(MainMenuScene)就會被調用。

遊戲場景

我們使用遊戲場景來載入在實際遊戲中需要的所有東西。同時它也用來顯示分數。在file菜單中選擇New File 並選擇和你MainMenuScene中選擇的相同的選項(CCLayer, full screen, iPhone portrait),命名文件爲GameScene並保存在文件夾。

對於這個遊戲來說,我們會使用和菜單場景一樣的背景梯度。或是再創建一遍,或是通過雙擊項目視圖的MainMenuScene,選擇CCLayerGradient,複製黏貼到你的新文件處。

點擊工具欄上的CCLayer圖標來給場景加一個層。稍後在代碼中我們會使用這個空的層來加載一個關卡。

層添加後,我們添加一個label用來顯示當前遊戲的分數。點擊工具欄上的CCLabelTTF標籤。

如圖所示,把位置設成(160,40),字體設置成o System Fonts / MarkerFelt-Wide,字號大小24,尺寸設成100*40,校準設成center,最後把文字設成“0”

這個遊戲場景已經差不多完工了,唯一還差的就是和代碼的連接。選擇根節點並且設置自定義類爲GameScene。然後選擇文本標籤,我們將要指派這個標籤作爲根節點類的一個成員變量。將左側的下拉菜單中選擇爲Doc root var,並且設置那個變量的名字爲scoreLabel。

我們也需要連接剛纔創建的那個空層到代碼。處理步驟同上並將變量明設爲levelLayer。

現在我們已經完成這個遊戲場景啦。讓我們繼續創建一些遊戲對象。

增加遊戲物體

我們這個遊戲會用到4種遊戲物體。遊戲的主角:龍,以及錢幣,炸彈,和爆炸效果。所有遊戲物體都是我們稍後創建的GameObject類的子類。GameObject類是CCNode的一個子類。因此,CocosBuilder創建的遊戲中的所有對象都繼承自CCNode。(當然還有可能作爲GameObject的插件程序存在,但是在本遊戲中,我們並需要使用)。

讓我們開始創建遊戲中最複雜的物體—龍。在File菜單中選取New File,創建一個新文件。選擇根節點對象爲CCNode,反選全屏選項(full screen),選擇分辨率選項爲iphone。

選擇根節點並設置自定義類爲Dragon。

龍由幾個不同的移動部件組成:身體和2個翅膀。首先我們先加入翅膀這樣他們就會出現在身體的後面。在項目視圖拖動gameobjects.plist/dragon-wing.png 到畫布區域。設置翅膀的位置爲(-8,4),另一個錨點設爲(0.84,0.094).

然後,增加身體部分。拖動gameobjects.plist/dragon-body.png到畫布區域。設置身體的位置爲(0,0)。你的文件看起來就會是這樣:

我們將龍的單個翅膀做動畫,然後複製翅膀並翻轉成一對做動畫的翅膀。首先,設置時間軸長度爲1秒。然後,選擇翅膀,將時 間軸標記(timeline)移到開始處並按R鍵來增加一幀,以做翻轉。將時間軸(timeline)標記移動到結束處,再增加一幀翻轉。現在移動到中部 (00:00:15)。朝下旋轉翅膀—-你可以通過按住option鍵,並拖曳其中一個選擇選擇點來快捷旋轉它。旋轉這個翅膀差不多80度左右。

我們現在有了撲騰的翅膀啦,但是通過增加Bounce Out緩衝,我們可以讓它顯示的更加自然。在第一幀和中間幀之間右鍵,選擇Bounce Out.。在中間那幀和最後一幀也做同樣的設置。

現在來創建另外一隻翅膀。首先確保沒有幀被選中,然後選擇翅膀。在edit菜單中選擇Copy,並Paste.第二個翅膀就被複制到龍的身體前面了,因此我們需要使用Object菜單中的Arrange /Send Backward選項請 確保新的翅膀在檢查器中FilpX選項有被選中。這隻會翻轉圖像,我們同意需要設置它的位置和錨點,設置位置爲(8,4),錨點 (0.16,0.094)。這個翅膀的動畫現在看起來不錯了,但是選擇的方向是錯的。雙擊中間的那一幀來鎖定它。你可以改變檢查器(inspector) 中的旋轉角度(大概80度左右)。繼續播放動畫,這時候,龍的兩隻翅膀應該都正常了。

在遊戲中,我們的小龍會在碰到炸彈的時候停止撲騰它的翅膀。當撞到炸彈的時候,我們會播放另一個剪短的動畫,然後再撲騰翅膀。因此我們需要2個時間軸。選擇Animation 菜單的Choose Edit Timelines…。重命名當前的時間軸爲Flying,增加一個新的時間軸爲Hit,然後點擊Done

我們希望飛行的時間軸循環播放,所有點擊No chained timeline並選擇Flying。然後切換到新創建的Hit時間軸。設置它的長度爲2秒並和Flying連接起來。當龍被擊中時候,我們播放hit動畫,播放完成後它自動繼續Flying動畫。

剩下還有要做的就是創建一個龍被擊中的動畫。移動時間軸的標記到末尾,選擇每個翅膀並按R來增加旋轉動畫。現在移動標記到開頭。將每個翅膀旋轉向下,我分別設置了-123和123的值。爲每個翅膀增加一個Bounce Out屬性。

選擇龍的身體部分,移動時間軸標記到00:00:15.處。按F來增加一幀。現在,移動標記到開頭處並按F增加一個精靈幀。在檢查器(inspector)中,設置精靈框爲frame togameobjects.plist/dragon-body-hit.png。點擊play按鈕來試試hit動畫怎麼樣。

Bomb

炸彈

在街機遊戲中怎麼可能會少了壞人?我們需要一些很酷的炸彈~創建一個新文件就像dragon文件一樣(選項也一樣)。命名文件爲Bomb並保存。選擇根節點並設置自定義類爲Bomb。

我們現在要爲我們的炸彈增加一些旋轉的釘子。設置時間軸長度爲2s。拖曳gameobjects.plist-bomb-spikes.png到畫布處並設置位置爲(0,0),同樣的拖曳thegameobjects.plist/bomb-body.png。炸彈身體會在尖刺的上方。

爲了讓炸彈看起來更邪惡一點,我們需要讓釘子旋轉。選擇釘子精靈並移動時間軸標記至初始部分。按R來增加一幀旋轉的關鍵幀。通過移動時間軸標記到末尾增加一個關鍵幀(按R鍵)並設置精靈的旋轉角度是360度。播放動畫,我們可以看到釘子繞着身體旋轉了。

最後,請確保時間軸自動的循環播放,你可以動過點擊No chained timeline text 並選擇Default的時間軸。


Coin

硬幣

在我們的遊戲中我們會看到2種硬幣,普通硬幣和結束硬幣。吃了普通硬盤會給與我們的龍一個短暫的加速,吃了結束硬幣會結束當前關卡。我們可以使用相同的類對於這2種硬幣,但是在其中加一個額外的屬性以方便我們在代碼中區分他們。

用和dragon,bomb文件一樣的設置創建一個新文件。命名爲Coin,設置自定義類爲Coin。

拖曳gameobjects.plist/coin01.png到畫布區並設置位置爲(0,0)。現在我們想要增加一幀基於硬幣的動畫,設置時間軸的長度爲00:01:06.確保時間軸標記在最前面而且硬幣精靈被選中。現在選擇項目視圖中的coin01.png到coin18.png。

選擇Animation 菜單中的Create Frames from Selected Resources按鈕。你將爲硬幣精靈添加一系列的關鍵幀。動畫起了作用,但是好像稍微太快了點。拖動選擇框包圍他們來選擇所有的關鍵幀,然後,選擇Animation 菜單中的Stretch Selected Keyframes 按鈕。設置拉伸率(stretch)爲2.0並點擊Done。這時關鍵幀時間被隔開,動畫看起來就更慢了。

對於炸彈,通過設置默認的時間軸,完成這個文件,並保存。

現在我們開始創建“結束硬幣”。打開Finder,複製Coin.ccb文件,並重命名爲EndCoin.ccb。切回到CocosBuilder,雙擊項目視圖來新建一個文件。爲了區別這2種硬幣,我們需要在根節點增加一個自定義的屬性。選擇根節點並點擊檢查器中的Edit Custom Properties。創建一個新的屬性,命名爲isEndCoin,設置種類爲Bool並設置值爲1.點擊Done、

當文件在我們的app中載入的時候,這個自定義屬性就會被設置進自定義的類裏。爲了使這個旋轉的硬幣視覺上有別於普通的硬幣。選擇硬幣,並點擊color well來彈出顏色選取器,設置如下所示的顏色,這樣,我們就完成了2個不同的硬幣。

Explosion

爆炸

當炸彈爆炸的時候,我們需要一些花哨的爆炸效果。我們可以使用粒子系統。每一個爆炸由2個粒子系統構成。

首先創建一個新文件,設置都同前面創建龍、炸彈和硬幣的一樣並命名文件爲Explosion。設置時間軸長度爲2秒,並定義根節點的自定義類名爲Explosion。點擊工具欄的粒子系統的圖標2次,來增加2個粒子系統的文件。

兩個粒子系統的參數設置如下圖所示。如果想看一下效果,你可以點擊檢查器中的Start Particles按鈕。

Creating a Level

創建一個關卡


我們完成了我們所有的遊戲物體。唯一還沒做的界面就是關卡地圖了。創建一個新文件,請確保根節點中CCLayer和full screen的選項被選擇,選擇iPhone Portrait的分辨率,但是設置高度爲4096.

將其保存爲Level文件。設置根節點的自定義類名爲Level。我們現在有一個很大的文件來放置我們這些遊戲物體。首先先增加龍吧。將項目視圖中的Dragon.ccb拖曳到畫布區域。選擇龍並設置位置爲(160,40),如果你移動了龍,你可能需要滾動畫布區域才能看到龍。我們需要向下滾動可視化編輯器,以便你在移動進入前能看到我們添加的龍。我們希望能夠簡便地在代碼中加入龍,所以在下拉菜單總的代碼連接選項(Code Connections)中選擇Doc root var

現在,從項目視圖中拖曳並放置更多遊戲物體。在我這種情況下,第一關看起來像這樣:

在關卡的頂部放置一個“結束硬幣”。當龍接觸到“接觸硬幣”的時候,關卡結束。當你很高興的佈局你的關卡的時候,請確保所有打開的文件要保存。現在,選擇File菜單中的Publish按鈕。這將會把你的文件打包成一個非常緊湊的二進制格式文件。

遊戲編碼


現在我們已經爲遊戲創建好了所有接口文件,下一步開始編碼。

用Xcode打開項目,右鍵單擊Resources文件夾並選擇Add Files to “CocosDragon”…….確保“Create groups for any added folders”單選框被選中,並且“CocosDragon target”也被選中。將所有的圖片文件添加到資源目錄下,包括plist文件 (sprite sheets)和所有ccbi文件。你不必添加以ccb爲擴展名的文件進來,因爲他們只在CocosBuilder下使用。

下一步,我們要添加CCBReader到項目下。CCBReader在示例代碼的文件夾下。將他添加到“你項目 /cocos2d-iphone”。將CCBReader文件夾添加到你項目之後,確認Create groups for any added folders被選中,並且Copy items into destination group’s folder被選中。

Xcode下,打開Prefix.pch文件,它在Supporting Files組下。引入頭文件的代碼如下:

#ifdef __OBJC__ #import #import #import “cocos2d.h” #endif

MainMenuScene

我們現在開始編碼。讓我們一起創建一個主菜單(main menu)!選擇File菜單下的New/File。選擇Objective-C class,命名該類爲MainMenuScene並設定該類爲CCLayer的子類。

在MainMenuScene.m的最上部import CCBReader.h。我們也將實現play按鈕的回調函數,這個play按鈕是我們在ccb文件中加入的。在實現文件中(*.m)中加入如下代碼:

- (void) pressedPlay:(id)sender

{

 // Load the game scene

 CCScene* gameScene = [CCBReader sceneWithNodeGraphFromFile:@"GameScene.ccbi"];

 // Go to the game scene

 [[CCDirector sharedDirector] replaceScene:gameScene];

}

當我們按下play按鈕,我們將第一次通過ccbi文件加載遊戲場景。然後通知CCDirector去用遊戲場景 replace掉當前的場景。這部分的代碼我們需要寫到MainMenuScene裏,而且需要在遊戲開始時候加載。打開AppDelegate.m文 件,引入CCBReader.h,然後用下面的代碼替換既存的引入初始場景的代碼:

// Load the main menu scene from the ccbi-file

CCScene* mainScene = [CCBReader sceneWithNodeGraphFromFile:@"MainMenuScene.ccbi"];

// Then add the scene to the stack. The director will run it when it automatically when the view is displayed.

[director_ pushScene: mainScene];

然後,還是在AppDelegate.m文件,用如下代碼替換shouldAutorotateToInterfaceOrientation:方法:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

{

 return UIInterfaceOrientationIsPortrait(interfaceOrientation);

}

這將確保我們的遊戲以豎屏模式運行。你可以在github上找到源文件:

MainMenuScene.m

MainMenuScene.h

AppDelegate.m

GameScene

當我們按下play按鈕之後,GameScene.ccbi文件將會被加載,並創建GameScene的實例。現在我們需要創建GameScene類。創建一個新類命名爲GameScene,讓其繼承自CCLayer。

在CocosBuilder裏,我們添加了兩個成員變量(levelLayer和scoreLabel)。我們需要添加它們到文件中去。並且也需要加載等級(Level)以及動態的記錄當前的分數。在GameScene.h添加前面提到的兩個成員變量:

@interface GameScene : CCLayer

{

 CCLayer* levelLayer;

 CCLabelTTF* scoreLabel;

 CCNode* level;

 int score;

}

爲了從別的類裏更好的管理分數,我們將在GameScene類裏增加一個屬性。我們也將增加方法去管理遊戲結束以及升級的情況。

@property (nonatomic,assign) int score;

+ (GameScene*) sharedScene;

- (void) handleGameOver;

- (void) handleLevelComplete;

@end

下面我們來實現GameScene類的方法。打開GameScene.m。在頭部importCCBReader.h。在開始實現該類之前,先定義一個靜態變量以方便共享該類的實例。

static GameScene* sharedScene;

在該類的類方法中返回這個共享實例。

+ (GameScene*) sharedScene

{

 return sharedScene;

}

我也需要去synthesize這個分數屬性。

@synthesize score;

當一個ccbi文件被加載的時候,CCBReader將會調用創建每個節點的方法didLoadFromCCB。通過實現該方法,你將在文件加載完畢的時候收到一個回調函數。我們將會利用回調信息去設置當前場景以及加載等級。

- (void) didLoadFromCCB

{

 // Save a reference to the currently used instance of GameScene

 sharedScene = self;

 self.score = 0;

 // Load the level

 level = [CCBReader nodeGraphFromFile:@"Level.ccbi"];

 // And add it to the game scene

 [levelLayer addChild:level];

}

這部分代碼加載Level.ccbi文件並且將其作爲一個子節點加到我們在CocosBuilder裏創建的levelLayer上。在真實的遊戲當中我們可能會有不止一個的等級文件,並且對應玩家在遊戲中的進度選擇不同的文件。

當分數屬性改變時,我們希望更新label上分數的顯示。我們通過setScore:方法來實現。記住我們已經在CocosBuilder定義了scoreLabel。

- (void) setScore:(int)s

{

 score = s;

 [scoreLabel setString:[NSString stringWithFormat:@"%d",s]];

}

離開GameScene之前的最後一步是爲控制遊戲結束以及升級編碼。在實際遊戲中你可能做更多的事情在這些方法中,但是在該例子中,我們只是簡單的返回主菜單場景。

- (void) handleGameOver

{

 [[CCDirector sharedDirector] replaceScene:[CCBReader sceneWithNodeGraphFromFile:@"MainMenuScene.ccbi"]];

}

- (void) handleLevelComplete

{

 [[CCDirector sharedDirector] replaceScene:[CCBReader sceneWithNodeGraphFromFile:@"MainMenuScene.ccbi"]];

}

你可以在github找到源碼

 GameScene.m

 GameScene.h

GameObject

GameObject是一個抽象類,它是所有遊戲對象的父類。他讓我們可以等同對待所有的遊戲對象。創建一個CCNode的子類,命名爲GameObject。這個類包含一些基礎屬性的設置以及一些基礎的方法,以便我們在遊戲當中控制遊戲對象。如果我們想移除一個對象那麼可以設置isScheduledForRemove屬性。這個更新方法會在每個框架更新遊戲對象狀態的時候調用一次。我們將在檢測衝突的時候(在我們的遊戲當中每一個遊戲對象都視爲圓形)使用radius屬性。最後,如果兩個遊戲對象發生碰撞,兩個發生碰撞的遊戲對象的handleCollisionWith:方法將被調用。下面就是頭文件的定義代碼:

@interface GameObject : CCNode

{

 BOOL isScheduledForRemove;

}

@property (nonatomic,assign) BOOL isScheduledForRemove;

@property (nonatomic,readonly) float radius;

- (void) update;

- (void) handleCollisionWith:(GameObject*)gameObject;

@end

這個.m文件只是實現了一個空方法,因爲他是一個抽象類。

@implementation GameObject

@synthesize isScheduledForRemove;

// Update is called for every game object once every frame

- (void) update

{}

// If this game object has collided with another game object this method is called

- (void) handleCollisionWith:(GameObject *)gameObject

{}

// Returns the radius of this game object

- (float) radius

    return 0;

}

@end

源碼參見以下文件鏈接:

GameObject.m

GameObject.h

Dragon

龍是我們遊戲中最複雜的遊戲對象。它控制着玩家將要控制的這個角色的行爲,同時這也是遊戲的主要行爲。創建一個GameObject的子類命名爲Dragon。

爲了控制龍的運動,我們需要兩個變量,縱向速度ySpeed,以及橫向目標xTarget。xTarget將會在點擊iPhone上的打擊目標的時候被設置。之後變量將會被外部類設定,我們將會將他作爲一個屬性。下面是我們需要添加的頭文件:

@interface Dragon : GameObject

{

 float ySpeed;

 float xTarget;

}

@property (nonatomic,assign) float xTarget;

@end

.m文件將會更加有趣。首先,我們會整合一些其他的類進來,我們來引入他們。(我們將會在完成Dragon類之後,編寫Coin和Bomb類)

#import “Dragon.h”

#import “Coin.h”

#import “Bomb.h”

#import “GameScene.h”

#import “CCBAnimationManager.h”

下面,我們來定義幾個常量來方便對龍的行爲的控制。使用常量是一個非常不錯的選擇,因爲這樣很方便我們去從感官上控制遊戲。

#define kCJStartSpeed 8

#define kCJCoinSpeed 8

#define kCJStartTarget 160

#define kCJTargetFilterFactor 0.05

#define kCJSlowDownFactor 0.995

#define kCJGravitySpeed 0.1

#define kCJGameOverSpeed -10

#define kCJDeltaToRotationFactor 5

實現Dragon類的第一步,我們需要synthesize屬性xTarget。

@synthesize xTarget;

然後來到init方法,在這裏我們將初始化我們的成員變量。xTarget的初始值爲160,位於屏幕中心。

- (id) init

{

 self = [super init];

 if (!self) return NULL;

 xTarget = kCJStartTarget;

 ySpeed = kCJStartSpeed;

 return self;

}

我們將使用update方法讓龍在屏幕上平滑的移動。在每個frame下,update方法會被調用一次。我們將利用一 個計算原始點和目標點之間距離的過濾器方法來獲得一個新的X座標。我所說的目標點就是玩家在屏幕上觸摸的點。Y座標則是在原始座標的基礎上增加現有速度來 計算得出的。之後我們更新速度,我們不但可以通過增加常量的方式加快速度,也可以利用參數減慢速度(這將防止龍的攻擊速度過快)。我們同時依靠水平速度翹 起龍的一側。如果縱向速度向下過快,那麼遊戲結束。

- (void) update

{

 // Calculate new position

 CGPoint oldPosition = self.position;

 float xNew = xTarget * kCJTargetFilterFactor + oldPosition.x * (1-kCJTargetFilterFactor);

 float yNew = oldPosition.y + ySpeed;      self.position = ccp(xNew,yNew);

 // Update the vertical speed

 ySpeed = (ySpeed – kCJGravitySpeed) * kCJSlowDownFactor;

 // Tilt the dragon depending on horizontal speed

 float xDelta = xNew – oldPosition.x;

 self.rotation = xDelta * kCJDeltaToRotationFactor;

 // Check for game over

 if (ySpeed < kCJGameOverSpeed)

 {

 [[GameScene sharedScene] handleGameOver];

 }

}

在Dragon類裏我們也需要去控制碰撞。我們將通過判斷是碰撞了哪種對象來相應的做出動作。如果碰到了錢幣,我們增加 分數並且給龍一個向上增長的速度。如果我們碰到了炸彈,龍會降低速度並且播放在CocosBuilder裏面製作的Hit動畫。我們在 userObject裏用CCBReader保存的CCBAnimationManager,之後調用 runAnimationsForSequenceNamed:方法。

- (void) handleCollisionWith:(GameObject *)gameObject

{

 if ([gameObject isKindOfClass:[Coin class]])

 {

 // Took a coin

 ySpeed = kCJCoinSpeed;

 [GameScene sharedScene].score += 1;

 }

 else if ([gameObject isKindOfClass:[Bomb class]])

 {

 // Hit a bomb

 if (ySpeed > 0) ySpeed = 0;

 CCBAnimationManager* animationManager = self.userObject;

 NSLog(@”animationManager: %@”, animationManager);

 [animationManager runAnimationsForSequenceNamed:@"Hit"];

 }

}

最後我們要實現radius(半徑)屬性。它將用於控制碰撞。

- (float) radius

{

 return 25;

}

完整的Dragon類,請參見:

Dragon.m

Dragon.h

Coin

金幣有一個相當簡單的邏輯,金幣在碰到龍的時候會被移除。如果最後一枚金幣碰撞到了龍,該等級的任務完成。創建一個名爲 Coin的類,他是GameObject的子類。在CocosBuilder我們增加了一些自定義的屬性,isEndCoin是專門針對最後一枚金幣的, 普通金幣也使用相同的自定義類。我們需要實現這個屬性在我們的類裏,下文是頭部文件:

@interface Coin : GameObject

{

 BOOL isEndCoin;

}

@property (nonatomic,assign) BOOL isEndCoin;

@end

.m文件,我們首先要synthesize屬性isEndCoin。

@synthesize isEndCoin;

我們不必移動金幣,所以我們不用實現update方法。但是,當背龍碰撞的時候我們想移除它。並且,如果是最後一枚金幣的話,我們想升級。

- (void) handleCollisionWith:(GameObject *)gameObject

{

 if ([gameObject isKindOfClass:[Dragon class]])

 {

 if (isEndCoin)

 {

 // Level is complete!

 [[GameScene sharedScene] handleLevelComplete];

 }

 self.isScheduledForRemove = YES;

 }

}

最後,讓我們來設定金幣的半徑。

- (float) radius

{

 return 15;

}

完整的代碼,參見下方:

Coin.m

Coin.h

Bomb

炸彈是我們遊戲當中的一個障礙物。創建名爲Bomb的類,他是GameObject的子類。當炸彈碰撞到玩家的時候,它 會爆炸。這個效果是通過移除炸彈並且動態的加載爆炸效果來實現的。我們沒有添加任何新的屬性進來,所以頭文件不需要修改。在.m文件中,我們需要實現 handleCollisionsWith:方法。

- (void) handleCollisionWith:(GameObject *)gameObject

{

 if ([gameObject isKindOfClass:[Dragon class]])

 {

 // Collided with the dragon, remove object and add an explosion instead

 self.isScheduledForRemove = YES;

 CCNode* explosion = [CCBReader nodeGraphFromFile:@"Explosion.ccbi"];

 explosion.position = self.position;

 [self.parent addChild:explosion];

 }

}

之後,我們需要設定炸彈的半徑。

- (float) radius

{

 return 15;

}

完整的代碼,如下:

Bomb.m

Bomb.h

Explosion

最後一個遊戲對象,我們將會實現爆炸(Explosion)。爆炸不會影響其他的任何遊戲對象。但是我們會在它完成播放 之後移除調它。爲此我們必須實現CCBAnimationManagerDelegate。在頭文件,首先引入 CCBAnimationManagerDelegate.h,然後將其作爲一個協議加進到Explosion。

#import “CCBAnimationManager.h”

@interface Explosion : GameObject

@end

.m文件,我們將分配Explosion類作爲CCBActionManager的代理,這步的創建將發生在爆炸加載的時候。我們將在didLoadFromCCB:方法來實現這步。

- (void) didLoadFromCCB

{

 // Setup a delegate method for the animationManager of the explosion

 CCBAnimationManager* animationManager = self.userObject;

 animationManager.delegate = self;

}

至此,當動畫播放完畢我們將收到回調函數completedAnimationSequenceNamed:,實現該回調並增加一個移除爆炸的定時器。

- (void) completedAnimationSequenceNamed:(NSString *)name

{

 // Remove the explosion object after the animation has finished

 self.isScheduledForRemove = YES;

}

完整的代碼見下方:

Explosion.m

Explosion.h

Level

我們就還剩一個Level類沒有完成。Level將會控制所有的玩家輸入,並且負責更新和移除我們的遊戲對象。創建名爲Level的類,它是CCLayer的子類。在CocosBuilder裏,我們添加了一個成員變量dragon,所以我們要把它加到頭文件。

@class Dragon;  @interface Level : CCLayer

{

 Dragon* dragon;

}

@end

.m文件,我們將引入計劃訪問的類。

#import “Dragon.h”

#import “GameObject.h”

我們也將定義兩個常量用於層的滾動。因爲龍需要是一直可見的。

#define kCJScrollFilterFactor 0.1

#define kCJDragonTargetOffset 80

我們使用onEnter方法,在每個frame之前,去提供一個回調函數update:。在onExit我們移除這個回調。

- (void) onEnter

{

 [super onEnter];

 // Schedule a selector that is called every frame

 [self schedule:@selector(update:)];

 // Make sure touches are enabled

 self.isTouchEnabled = YES;

}

- (void) onExit

{

 [super onExit];

 // Remove the scheduled selector

 [self unscheduleAllSelectors];

}

在update:方法我們將更新所有遊戲對象。記住,在CocosBuilder裏我們增加的遊戲對象都是level的 子對象。之後,遊戲對象更新以及發生位置改變的時候我們將檢測是否有碰撞。在這個遊戲裏我們只檢測與龍之間的碰撞,因爲只有他是移動的。在其他的遊戲裏, 你可能需要寫更多更復雜的代碼去檢測碰撞,或者有可能用到諸如Chipmunk,Box2d的物理引擎。因爲所有的碰撞都是可控的,我們將會遍歷遊戲的所 有對象去看哪些對象被定時移除了。我們爲這些對象創建一個數組,使用這個隊列來移除他們。最後,我們調整層的位置,所以龍總是可見的。當調整位置的時候我 們使用過濾器代理去確保移動的平滑。

- (void) update:(ccTime)delta

{

 // Iterate through all objects in the level layer

 CCNode* child;

 CCARRAY_FOREACH(self.children, child)

 {

 // Check if the child is a game object

 if ([child isKindOfClass:[GameObject class]])

 {

 GameObject* gameObject = (GameObject*)child;

 // Update all game objects

 [gameObject update];

 // Check for collisions with dragon

 if (gameObject != dragon)

 {

 if (ccpDistance(gameObject.position, dragon.position) < gameObject.radius + dragon.radius)

 {

 // Notify the game objects that they have collided

 [gameObject handleCollisionWith:dragon];

 [dragon handleCollisionWith:gameObject];

 }

 }

 }

 }

 // Check for objects to remove

 NSMutableArray* gameObjectsToRemove = [NSMutableArray array];

 CCARRAY_FOREACH(self.children, child)

 {

 if ([child isKindOfClass:[GameObject class]])

 {

 GameObject* gameObject = (GameObject*)child;

 if (gameObject.isScheduledForRemove)

 {

 [gameObjectsToRemove addObject:gameObject];

 }

 }

 }

 for (GameObject* gameObject in gameObjectsToRemove)

 {

 [self removeChild:gameObject cleanup:YES];

 }

 // Adjust the position of the layer so dragon is visible

 float yTarget = kCJDragonTargetOffset – dragon.position.y;

 CGPoint oldLayerPosition = self.position;

 float xNew = oldLayerPosition.x;

 float yNew = yTarget * kCJScrollFilterFactor + oldLayerPosition.y * (1.0f – kCJScrollFilterFactor);

 self.position = ccp(xNew, yNew);

}

最後我們需要去做些事情來響應玩家的觸摸。我們實現了ccTouchesBegan:withEvent:和ccTouchesMoved:withEvent:方法去獲取觸摸位置,以及設定龍的xTarget屬性。

- (void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

{

 UITouch* touch = [touches anyObject];

 CGPoint touchLocation = [touch locationInView: [touch view]];

 dragon.xTarget = touchLocation.x;

}

- (void) ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

{

 UITouch* touch = [touches anyObject];

 CGPoint touchLocation = [touch locationInView: [touch view]];

 dragon.xTarget = touchLocation.x;

}

完整的代碼請參見:

Level.m

Level.h

總結

用所有的CocosBuilder文件爲遊戲創建的類,你應該可以在虛擬機或者真機上編譯運行。很感謝花時間讀這個教程,祝你編碼愉快!


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