Cocos2D-X SimpleGame cocos2d-x完成游戏后的一些锦上添花修饰 (6) ----版本cocos2d-2.0-x-2.0.3 .

很高兴,我们基本已经完成了这个小游戏,很开心!!

最后我们帮它加上结果把!!

当你干掉一定数量的怪物时,在屏幕上显示“You Win”,而当有怪物逃出屏幕左侧时,显示“You Lose”。

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

GameOverScene.h的内容

#ifndef __GAME_OVER_SCENE_H__
#define __GAME_OVER_SCENE_H__

#include "cocos2d.h"

class GameOverLayer : public cocos2d::CCLayerColor
{
public:
	GameOverLayer():_label(NULL){}
	~GameOverLayer();

	bool init();
	void gameOverDone();

	CREATE_FUNC(GameOverLayer);
	CC_SYNTHESIZE_READONLY(cocos2d::CCLabelTTF*, _label, Label);


};



class GameOverScene : public cocos2d::CCScene
{
public:
	GameOverScene():_layer(NULL){};
	~GameOverScene();

	bool init();
	
	CREATE_FUNC(GameOverScene);
	CC_SYNTHESIZE_READONLY(GameOverLayer*, _layer, Layer);

};

#endif

要点:

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

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

#include "GameOverScene.h"
#include "HelloWorldScene.h"

USING_NS_CC;

//Class GameOverScene
//
GameOverScene::~GameOverScene(void)
{
	if (_layer)
	{
		_layer->release();
		_layer = NULL;
	}
}

bool GameOverScene::init()
{
	if( CCScene::init() )
	{
		this->_layer = GameOverLayer::create();
		this->_layer->retain();
		this->addChild(_layer);

		return true;
	}
	else
	{
		return false;
	}
}



//Class GameOverLayer
//
bool GameOverLayer::init()
{
	if ( CCLayerColor::initWithColor( ccc4(255,255,255,255) ) )
	{
		CCSize winSize = CCDirector::sharedDirector()->getWinSize();
		this->_label = CCLabelTTF::create("","Artial", 32);
		_label->retain();
		_label->setColor( ccc3(0, 0, 0) );
		_label->setPosition( ccp(winSize.width/2, winSize.height/2) );
		this->addChild(_label);

		this->runAction( CCSequence::create(
			CCDelayTime::create(3),
			CCCallFunc::create(this, 
			callfunc_selector(GameOverLayer::gameOverDone)),
			NULL));

		return true;
	}
	else
	{
		return false;
	}
}

void GameOverLayer::gameOverDone()
{
	CCDirector::sharedDirector()->replaceScene( HelloWorld::scene() );
}

GameOverLayer::~GameOverLayer()
{
	if (_label)
	{
		_label->release();
		_label = NULL;
	}
}

 

注意,上面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::create(...),这种情况不需要用户release;但如果你接着调用了sprite->retain(), 那么就需要一个sprite->release()对应

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

 

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

protected:

	cocos2d::CCArray* _targers;
	cocos2d::CCArray* _projectiles;

	int _peojectileDestroyed;

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

HelloWorld::HelloWorld()
{
	_peojectileDestroyed = 0;
}

在HelloWorldScene.cpp中包含GameOverScene.h

#include "GameOverScene.h"

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

		for (unsigned int jt = 0; jt<targetsToDelete->count(); jt++)
		{
			CCSprite* target = (CCSprite*)(targetsToDelete->objectAtIndex(jt));
			_targers->removeObject(target);
			this->removeChild(target, true);

			_peojectileDestroyed++;
			if (_peojectileDestroyed > 5)
			{
				GameOverScene* gameOverScene = GameOverScene::create();
				gameOverScene->getLayer()->getLabel()->setString("You Win!");
				CCDirector::sharedDirector()->replaceScene(gameOverScene);
			}
			
		}

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

//敌人移动结束
void HelloWorld::spriteMoveFinished(CCNode* sender)
{
	CCSprite* sprite = (CCSprite *)sender;
	this->removeChild(sprite, true);

	if (sprite->getTag() == 1)
	{
		_targers->removeObject(sprite);

		GameOverScene* gameOverScene = GameOverScene::create();
		gameOverScene->getLayer()->getLabel()->setString("You Lose!");
		CCDirector::sharedDirector()->replaceScene(gameOverScene);


	}else if (sprite->getTag() == 2)
	{
		_projectiles->removeObject(sprite);
	}
	
	
}


Yes!整个游戏完成了,迈出了游戏开发第一步了,希望大家多多指教,加油!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值