cocos2d-x完成游戏后的一些锦上添花修饰

移动开发 iOS Android 游戏开发
经过前面几段的介绍,各位开发者可以利用cocos2d-x完成一款简单的游戏基本功能了,但是我们可以在其中加入一些修饰,让它显得更专业一些。

在这一章里,我们将会添加新的场景。当你干掉一定数量的怪物时,在屏幕上显示“You Win”,而当有怪物逃出屏幕左侧时,显示“You Lose”。

下面我们在类目录里新建两个文件,GameOverScene.cpp 和GameOverScene.h。

GameOverScene.h的内容

1#ifndef _GAME_OVER_SCENE_H_

2#define _GAME_OVER_SCENE_H_

3

4#include "cocos2d.h"

5

6class GameOverLayer : public cocos2d::CCLayerColor

7{

8public:

9 GameOverLayer():_label(NULL) {};

10 virtual ~GameOverLayer();

11 bool init();

12 LAYER_NODE_FUNC(GameOverLayer);

13

14 void gameOverDone();

15

16 CC_SYNTHESIZE_READONLY(cocos2d::CCLabelTTF*, _label, Label);

17};

18

19class GameOverScene : public cocos2d::CCScene

20{

21public:

22 GameOverScene():_layer(NULL) {};

23 ~GameOverScene();

24 bool init();

25 SCENE_NODE_FUNC(GameOverScene);

26

27 CC_SYNTHESIZE_READONLY(GameOverLayer*, _layer, Layer);

28};

29

30#endif // _GAME_OVER_SCENE_H_

1#import "cocos2d.h"

2@interface GameOverLayer : CCLayerColor

3{

4 CCLabel *_label;

5}

6

7@property (nonatomic, retain) CCLabel *label;

8@end

9

10@interface GameOverScene : CCScene

11{

12 GameOverLayer *_layer;

13}

14@property (nonatomic, retain) GameOverLayer *layer;

15@end

转换要点:

1. 在objc的头文件中,可以不声明类成员函数,而直接在.m文件里实现。cpp不允许这样做。所以我们会多个bool init();

2. 由于cpp里没有self这种强大的关键字,所以CCLayer::node()和CCScene::node()方法的都需要派生类自己实现一份,不能像objc那样直接从父类继承下来靠self关键字变成指向自己的对象。node()方法很方便,集合了new,init,autorelease等方法,可以减少调用者的代码量。但由于每份node方法的代码都类似,我们就做了两个宏来方便大家 LAYER_NODE_FUNC和SCENE_NODE_FUNC. 如果想使用这两个宏,就必须在派生类里实现bool init()方法。

3. 关于构造函数和init方法。cocos2d-x在从objc改写为cpp时,并不是直接把init的内容翻到C++构造函数里面,主要出于这样的考虑:C++构造函数有个天生缺陷——没有返回值。这就导致C++构造函数依赖try-catch来捕捉逻辑异常。而一般try-catch用的人不多,开启try-catch支持会使编译后的二进制程序增加不少体积,而且android NDK上也是彻底不支持try-catch。所以我们采取现在比较流行的“二阶段构造”的方法,即使用时先调构造函数,再调用init处理初始化逻辑。这种思路不论是在苹果iOS的接口设计(比如[[NSString alloc] init],即二阶段构造)、还是在samsung bada操作系统使用C++类时都是如此。

4. objc中的@synthesize实现了_label和_layer两个属性的具体setter和getter。我们在cocos2dx\include\Cocos2dDefine.h中实现了一系列的宏定义,来模仿实现@property和@synthesize的功能。在上面代码中,我们用CCX_SYNTHESIZE_READONLY宏来实现了只读的类成员变量,只有getter没有setter。由于VC++的规则是inline函数只能在头文件里实现,所以@synthesize就从objc的.m文件里移动到cpp的.h文件里,和成员变量声明一并实现了

GameOverScene.cpp的内容

1// cpp with cocos2d-x

2#include "GameOverScene.h"

3#include "HelloWorldScene.h"

4

5using namespace cocos2d;

6

7bool GameOverScene::init()

8{

9 if( CCScene::init() )

10 {

11 this->_layer = GameOverLayer::node();

12 this->_layer->retain();

13 this->addChild(_layer);

14

15 return true;

16 }

17 else

18 {

19 return false;

20 }

21}

22

23GameOverScene::~GameOverScene()

24{

25 if (_layer)

26 {

27 _layer->release();

28 _layer = NULL;

29 }

30}

31

32bool GameOverLayer::init()

33{

34 if ( CCLayerColor::initWithColor( ccc4(255,255,255,255) ) )

35 {

36 CCSize winSize = CCDirector::sharedDirector()->getWinSize();

37 this->_label = CCLabelTTF::labelWithString("","Artial", 32);

38 _label->retain();

39 _label->setColor( ccc3(0, 0, 0) );

40 _label->setPosition(ccp(winSize.width/2, winSize.height/2));

41 this->addChild(_label);

42

43 this->runAction( CCSequence::actions(

44 CCDelayTime::actionWithDuration(3),

45 CCCallFunc::actionWithTarget(this,

46 callfunc_selector(GameOverLayer::gameOverDone)),

47 NULL));

48

49 return true;

50 }

51 else

52 {

53 return false;

54 }

55}

56

57void GameOverLayer::gameOverDone()

58{

59 CCDirector::sharedDirector()->replaceScene(HelloWorld::scene());

60}

61

62GameOverLayer::~GameOverLayer()

63{

64 if (_label)

65 {

66 _label->release();

67 _label = NULL;

68 }

69}

1// objc with cocos2d-iphone

2#import "GameOverScene.h"

3#import "HelloWorldScene.h"

4

5@implementation GameOverScene

6@synthesize layer = _layer;

7

8- (id)init

9{

10 if ((self = [super init]))

11 {

12 self.layer = [GameOverLayer node];

13 [self addChild:_layer];

14 }

15 return self;

16}

17

18- (void)dealloc

19{

20 [_layer release];

21 _layer = nil;

22 [super dealloc];

23}

24

25@end

26@implementation GameOverLayer

27@synthesize label = _label;

28

29-(id) init

30{

31 if( (self=[super initWithColor:ccc4(255,255,255,255)] ))

32 {

33 CGSize winSize = [[CCDirector sharedDirector] winSize];

34 self.label = [CCLabel

35 labelWithString:@"" fontName:@"Arial" fontSize:32];

36

37 _label.color = ccc3(0,0,0);

38 _label.position = ccp(winSize.width/2, winSize.height/2);

39 [self addChild:_label];

40

41 [self runAction:[CCSequence actions:

42 [CCDelayTime actionWithDuration:3],

43 [CCCallFunc actionWithTarget:self

44 selector:@selector(gameOverDone)],

45 nil]];

46 }

47 return self;

48}

49

50- (void)gameOverDone

51{

52 [[CCDirector sharedDirector]

53 replaceScene:[HelloWorld scene]];

54}

55

56- (void)dealloc

57{

58 [_label release];

59 _label = nil;

60 [super dealloc];

61}

62

63@end

注意,上面GameOverScene.cpp里有两个对象,一个场景(scene)和一个图层(layer),场景可以包含多个图层,而这个图层只在屏幕正中间放了一个文字标签(label),显示3秒种后返回到HelloWorldScene中。

转换要点

1. 再次注意GameOverLayer._label和GameOverScene._layer两个属性。这两个属性在objc的头文件里被声明为@property (nonatomic, retain),也就是被retain了一次,所以在dealloc里才要调用release方法。同样地,我们在~GameOverLayer()和~GameOverScene()析构函数里分别release()了这两个属性,但这个release需要和一个retain对应,所以在两个init方法里都分别添加了_label->retain()和_layer->retain();

2. 关于NSAutoReleasePool, cocos2d-x里也有个模仿实现,这个简单的垃圾回收机制对C++编程来说是个福音;它使用起来和iOS上的NSAutoReleasePool原则一样,参考苹果的文档 http://developer.apple.com/library/ios/#documentation/cocoa/reference/foundation/Classes/NSAutoreleasePool_Class/Reference/Reference.html

简而言之就是,在使用cocos2d-x中继承自NSObject类的对象指针时,以下两种情况是需要用户多调一个release

 类对象是用户自己new出来的。比如CCSprite *sprite = new CCSprite();

 类对象是通过某个静态函数建立并返回的,比如CCSprite *sprite = CCSprite::spriteWithFile(...),这种情况不需要用户release;但如果你接着调用了sprite->retain(), 那么就需要一个sprite->release()对应

之后回到问题上来,GameOverScene应该在某些条件下被调用:一定数量的怪物被干掉或者有怪物跳掉了。

我们在HelloWorldScene里加入一个变量,用来计算英雄杀掉了多少个怪物。

11 // cpp with cocos2d-x

22 protected:

33 int _projectilesDestroyed;

11 // objc with cocos2d-iphone

22

33 int _projectilesDestroyed;

并在HelloWorld::HelloWorld()中初始化它,

1 // cpp with cocos2d-x

2_projectilesDestroyed = 0;

在HelloWorldScene.cpp中包含GameOverScene.h

1// cpp with cocos2d-x

2#include "GameOverScene.h"

1// objc with cocos2d-iphone

2#import "GameOverScene.h"

在HelloWorld::update方法中的removeChild(target)后面的targetsToDelete循环中增加计数并检查获胜条件,获胜了就显示"You Win!"界面

1// cpp with cocos2d-x

2_projectilesDestroyed++;

3if (_projectilesDestroyed > 30)

4{

5 GameOverScene *gameOverScene = GameOverScene::node();

6 gameOverScene->getLayer()->getLabel()->setString("You Win!");

7 CCDirector::sharedDirector()->replaceScene(gameOverScene);

8}

1

2// objc with cocos2d-iphone

3_projectilesDestroyed++;

4if (_projectilesDestroyed > 30)

5{

6 GameOverScene *gameOverScene = [GameOverScene node];

7 [gameOverScene.layer.label setString:@"You Win!"];

8 [[CCDirector sharedDirector] replaceScene:gameOverScene];

9}

与之匹配的是失败条件:任何一个怪物穿越了屏幕的最左边,你就挂了。于是修改spriteMoveFinished方法,在if (sprite->getTag() == 1)条件里面增加“You Lose”的代码:

1// cpp with cocos2d-x

2GameOverScene *gameOverScene = GameOverScene::node();

3gameOverScene->getLayer()->getLabel()->setString("You Lose :[");

4CCDirector::sharedDirector()->replaceScene(gameOverScene);

1// objc with cocos2d-iphone

2GameOverScene *gameOverScene = [GameOverScene node];

3[gameOverScene.layer.label setString:@"You Lose :["];

4[[CCDirector sharedDirector] replaceScene:gameOverScene];

现在,万事俱备,请编译并运行,所有类型的效果都会显示出来,怪物、子弹满屏飞,很H的背景音乐,并在你输或赢时显示一个提示界面。

整个游戏现在已经全部完成了,恭喜!

iPhone

android

win32

wophone

责任编辑:佚名 来源: cocos2d-x
相关推荐

2012-04-17 13:12:00

2011-12-12 10:40:08

Cocos2d-X游戏开发开发环境

2012-04-19 10:03:12

Cocos2d-x

2013-05-22 15:49:46

2012-02-19 20:10:23

Cocos2d-x fCocos2dWindows Pho

2012-04-17 12:44:38

cocos2d-x

2012-04-17 12:38:46

cocos2d-x

2015-07-17 10:38:21

教程COCOS射箭游戏

2014-08-13 10:07:02

游戏引擎

2013-12-03 10:58:50

Cocos2D-X砖块地图

2012-04-17 10:06:08

cocos2d-x

2012-04-17 10:59:31

cocos2d-x

2013-04-16 10:02:47

cocos2d-x懒人Android开发

2014-04-21 14:58:27

触控Cocos2d-x触控科技

2015-07-21 16:25:24

2014-07-31 16:57:30

2013-06-03 17:04:20

CocoStudioCocos2D-X添加CocoStudi

2013-05-22 14:38:44

iOS开发Cocos2d-x坐标系统

2012-04-17 12:58:44

Cocos2D-X

2012-04-17 13:09:13

Cocos2d-x
点赞
收藏

51CTO技术栈公众号