【3D技术宅公社】XR数字艺术论坛  XR技术讨论 XR互动电影 定格动画

 找回密码
 立即注册

QQ登录

只需一步,快速开始

调查问卷
论坛即将给大家带来全新的技术服务,面向三围图形学、游戏、动画的全新服务论坛升级为UTF8版本后,中文用户名和用户密码中有中文的都无法登陆,请发邮件到324007255(at)QQ.com联系手动修改密码

3D技术论坛将以计算机图形学为核心,面向教育 推出国内的三维教育引擎该项目在持续研发当中,感谢大家的关注。

查看: 1836|回复: 1

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

[复制链接]
发表于 2013-8-8 14:12:44 | 显示全部楼层 |阅读模式
在这一章里,我们将会添加新的场景。当你干掉一定数量的怪物时,在屏幕上显示“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 selectorselector(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/libra ... ence/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
发表于 2014-4-25 23:39:57 | 显示全部楼层
好好的教程
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|3D数字艺术论坛 ( 沪ICP备14023054号 )

GMT+8, 2024-4-29 20:07

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表