CocosBuilder
http://www.cocoachina.com/gamedev/2013/0515/6210.html
圖文并茂使用CocosBuilder制作Cocos2D游戲
發布于:2013-05-15 13:30閱讀數:21358
本文由Zynga 工程師原創,Iven、張作宸以及Butterfly翻譯 手把手教你使用CocosBuilder一次性導出Cocos2d-html5,Cocos2d-x和Cocos2d-iPhone的游戲資源文件。這個游戲90%的工作量是用工具完成。
“” 閱讀器CocosBuilder Cocos2D
本文由Zynga 工程師原創,Iven、張作宸以及Butterfly翻譯。
?
手把手教你使用CocosBuilder一次性導出Cocos2d-html5,Cocos2d-x和Cocos2d-iPhone的游戲資源文件。這個游戲90%的工作量是用工具完成。
?
CocosBuilder2.1 泰然下載地址 CocosDragon完整工程GitHub地址 在線Cocos2d-HTML5版本試玩地址
這篇教程將會展示如何使用??CocosBuilder和cocos2d-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 <UIKit/UIKit.h> #import <Foundation/Foundation.h> #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 <CCBAnimationManagerDelegate>
@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文件為游戲創建的類,你應該可以在虛擬機或者真機上編譯運行。很感謝花時間讀這個教程,祝你編碼愉快!
?
來源:ityran?
CocoaChina是全球最大的蘋果開發中文社區,官方微信每日定時推送各種精彩的研發教程資源和工具,介紹app推廣營銷經驗,最新企業招聘和外包信息,以及Cocos2d引擎、Cocos Studio開發工具包的最新動態及培訓信息。關注微信可以第一時間了解最新產品和服務動態,微信在手,天下我有!
請搜索微信號“CocoaChina”關注我們!
總結
以上是生活随笔為你收集整理的CocosBuilder的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网站优化 14条--雅虎十四条优化原则
- 下一篇: 计算机系统要素-从零开始构建现代计算机-