Alan 最近開始研究跨平台的 Mobile 開發引擎,最後選定 Cocos2D-x 作為目前最符合自己的 2D 遊戲開發引擎。
而這篇文章針對會移動的近景,遠景還有里程數做一些練習記錄與分享,先來看一下想做的範例成品大概的樣子,以 JadeNija (勾玉忍者) 為例。
先來看看此遊戲畫面可能的分層 (Layer) :
1. Background Layer (會移動的背景, 背景特效)
2. Gameplay Layer (主角, 敵人, 攻擊特效)
3. HUD layer (血條, 里程數, 暫停, 金錢, 武器, 技能...)(註:HUD = Heads-up display)
(遊戲分層的原因在於方便管理程式碼和多人開發時的工作分配)
針對背景層在做分解,在遊戲背景中至少含有三張 Sprites :
1. 遠景 * 2 (竹林還有分近跟遠的圖層)
2. 近景 * 1
依此架構製做的範例成品呈現如下:(背景一樣使用了三張 Sprite 圖檔 = 星空, 灰色房屋, 黑色房屋)
會向左移動的背景加入一架不會動的飛機,看起來就像是飛機在城市中飛行!加上里程數的計算就像極了市面上的跑酷遊戲的玩法。
移動的背景原理如下:(範例中的 City sprite 定位點設定在左下角)
1. 上圖的中央部分 Scene 為我們在手機上會看到的畫面,最左邊 X 坐標為 (- sceneSize.width,0),Scene 的最右邊 X 坐標為 (sceneSize.width,0),同一張 City sprite 要在程式中建立兩張,City sprite 的 width 要等於 sceneSize.width。
2. 在自行定義的 updateFrame 方法中不斷的判斷 sprite 的 X 坐標是否小於等於 - sceneSize.width,沒有的話則 sprite position X 向左移動 delta 單位,當 sprite1 移動到最左邊碰觸到 - sceneSize.width 的時候,將 sprite1 的 posiiton X 設為 sceneSize.width,sprite1 會剛好跑到 sprite2 的右方,畫面呈現如下圖:
3. 依此循環,就成功地製造出無限循環的移動背景的感覺,利用不同的圖層和不同的移動速度便可以製造出有遠景跟近景的幻象!
範例製作流程如下:
1. 以 Xcode 開啟 Cocos2D-x template (教學,有看不懂的朋友在跟我說,我來寫個中文的 xD)
2. 刪除一些不必要的程式碼
3. 加入我們會用到的 Assets : 背景圖*2, 飛機圖*1, 最後面那張星空是Alan網路上隨便找的
4. 在 Scene 場景中加入我們會用到的 CCLayer class : BackgroundLayer, GameplayLayer, HudLayer
5. 註冊 schedule_selector(updateFrame) 到需要在每個 frame 做畫面處理的的 Layer 中:因為我們移動背景的方式是在 updateFrame 的時候去調整背景圖層的位置,這裡設定 1.0f/60.0f 代表每秒執行 updateFrame 方法 60次。
// 註冊 updateFrame 方法每秒執行60次 this->schedule(schedule_selector(BackgroundLayer::updateFrame), 1.0f/60.f); |
6. 加入相關 Sprite : 背景圖加到 BackgroundLayer, 飛機圖加到 GameplayLayer
7. 撰寫 updateFrame 方法:
// 定義背景要移動的速度 float deltaA = -2 |
/* 每次執行此方法時判斷 Sprite 的 X 位置是否小於銀幕寬度的 -width,小於 -width 的話就將 Sprite 的位置移到 X = 螢幕 width 的位置,否則就將 Sprite 的 X 加 deltaA。 在此範例 deltaA 為負值所以 Sprite 會不斷往左邊移動直到 pSprite.x <= -width,此公式有個前提是 Sprite 的 AnchorPoint (定位點) 要設定在左下角,圖片的 width 要等於畫面的 width。 Cocos2D-x 中預設的圖片定位點是 AnchorPoint(0.5,0.5) 也就是圖片的正中央,而整個畫面的原點 (0,0) 設定在左下角, 和 Objective-c 的坐標系不同。 */ if (pSprite->getPositionX() <= -size.width) { pSprite->setPositionX(size.width); } else { pSprite->setPositionX(pSprite->getPositionX()+deltaA); } // 其他的部分依此類推 |
8. 里程數的計算:在 HudLayer 中 updateFrame 方法,利用一個變數 score 不斷累加得到里程數,範例中是使用 CCLabelTTF 來顯示里程數。
void HudLayer::updateFrame(CCTime time) { // 設定里程數累計的速度,基準值 0.3 * 每秒更新 60 次 = 18,意思是里程數每秒會多 18 M 如果想要調整里程數增加的速度可以藉由調整基準值的設定。 score = score + 0.3; /* 使用 createWithFormat 方法將數字轉為 CCString, 在此使用 int 的格式 是希望取得整數當作里程數。 */ CCString *pString = CCString::createWithFormat("%d",(int)score); // 使用 getCString() 方法將 CCString 轉成 CCLabelTTF 可以吃的 char 格式 pScoreLabel->setString(pString->getCString()); } |
9. 微調各 Sprite 和 Label 的位置:
// 取得畫面的大小 CCSize size = CCDirector::sharedDirector()->getWinSize(); // 根據畫面大小設定 label 的位置 pLabel->setPosition( ccp(size.width * 4 / 5 -80, size.height * 7 / 8) ); // 設定物件的定位點,預設為中心點 (0.5,0.5) 在此範例中Alan設定為左下角 (0,0) pLabel->setAnchorPoint(ccp(0,0)); |
此範例製作到此,Alan 為 Cocos2D-x 的初學者,假如有任何建議或不清楚的地方也請大家多指教,感謝。
(此範例運行的 Cocos2D-x 版本為 2.1.1)
--------------------------
參考資料:
勾玉忍者開發者 Blog:猴子靈藥
Asset 來源 : C
範例原始碼下載:https://www.dropbox.com/sh/aft261ltnsejnp6/_JqKSTxSqd?m
--------------------------
筆者:Alan Feng
大學由資管系畢業後便投入職場,先後擔任程式設計師,系統設計師,系統分析師,專案管理師等職務。
曾服務於資訊服務業,電子代工設計公司,目前在內湖一間遊戲公司擔任專案管理師~
持有國際 PMP 證照並努力學習 Scrum 敏捷式開發框架中。
留言列表