Alan 最近开始研究跨平台的 Mobile 开发引擎,最后选定 Cocos2D-x 作为目前最符合自己的 2D 游戏开发引擎。

而这篇文章针对会移动的近景,远景还有里程数做一些练习记录与分享,先来看一下想做的范例成品大概的样子,以 JadeNija (勾玉忍者) 为例。

Photo Feb 26, 5 47 27 PM  

先来看看此游戏画面可能的分层 (Layer) :

1. Background Layer (会移动的背景, 背景特效)

2. Gameplay Layer (主角, 敌人, 攻击特效)

3. HUD layer (血条, 里程数, 暂停, 金钱, 武器, 技能...)(注:HUD = Heads-up display)

(游戏分层的原因在于方便管理程式码和多人开发时的工作分配)

针对背景层在做分解,在游戏背景中至少含有三张 Sprites :

1. 远景 * 2 (竹林还有分近跟远的图层)

2. 近景 * 1 

依此架构制做的范例成品呈现如下:(背景一样使用了三张 Sprite 图档 = 星空, 灰色房屋, 黑色房屋)

Screen Shot 2013-03-02 at 上午10.56.39    

会向左移动的背景加入一架不会动的飞机,看起来就像是飞机在城市中飞行!加上里程数的计算就像极了市面上的跑酷游戏的玩法。

移动的背景原理如下:(范例中的 City sprite 定位点设定在左下角)

MovingBuildings1   

1. 上图的中央部分 Scene 为我们在手机上会看到的画面,最左边 X 坐标为 (- sceneSize.width,0),Scene 的最右边 X 坐标为 (sceneSize.width,0),同一张 City sprite 要在程式中建立两张,City sprite 的 width 要等于 sceneSize.width。

MovingBuildings2    

2. 在自行定义的 updateFrame 方法中不断的判断 sprite 的 X 坐标是否小于等于 - sceneSize.width,没有的话则 sprite position X 向左移动 delta 单位,当 sprite1 移动到最左边碰触到 - sceneSize.width 的时候,将 sprite1 的 posiiton X 设为 sceneSize.width,sprite1 会刚好跑到 sprite2 的右方,画面呈现如下图:

MovingBuildings3  

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->setPositionccp(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 来源 :  Corona SDK Game Tutorial - Part 1 (of 14)

范例原始码下载:https://www.dropbox.com/sh/aft261ltnsejnp6/_JqKSTxSqd?m

--------------------------

Thinking.jpg  

笔者:Alan Feng

大学由资管系毕业后便投入职场,先后担任程式设计师,系统设计师,系统分析师,专案管理师等职务。

曾服务于资讯服务业,电子代工设计公司,目前在内湖一间游戏公司担任专案管理师~

持有国际 PMP 证照并努力学习 Scrum 敏捷式开发框架中。


相关文章