1、一个游戏不能没有胜利和失败,当达到某个条件时,判断游戏胜利。或者说,当违反某个游戏规则既定次数时,游戏结束。本游戏有一个简单的场景切换来显示游戏的胜负,譬如当用户操控的小人当前的得分小于零时,游戏结束,切换到另一场景,显示一行文字:“You Lost!”;当分数达到某个值时(譬如20)显示“You Win!”。


2、显然,You Win 和 You Lost这两个场景只是文字不同,完全可以只写一个场景的类,调用时根据游戏情况,传入要显示的文字就行了。下面开始实现这个场景:

(1)新建两个类,分别别GameOverScene和GameOverLayer;

(2)在GameOverLayer的init函数中创建CCLabelTTF并设置位置为窗口正中,添加至布景层中;

(3)在GameOverLayer中为Label写一个函数,用于设置文字;

(4)因为在一个场景中不能直接访问到另一个场景的布景层,所以需要在另一个场景中写一个函数,返回另一个场景中创建的布景层的指针,这样就可以通过这个指针访问布景层了;

(5)在游戏场景中判断游戏的胜利与失败,并分别设置文字切换场景;

(6)前面的文章中有一个注释写错了,即子弹精灵数组应为_projectiles,而_targets是敌人,本文已改正;


3、贴出两个新类的代码:

GameOverLayer.h


#pragma once
#include "cocos2d.h"
class GameOverLayer : public cocos2d::CCLayerColor
{
public:
	GameOverLayer(void);
	~GameOverLayer(void);

	bool init();
	CREATE_FUNC(GameOverLayer);

	// 用于显示文字的Label
	cocos2d::CCLabelTTF *_pLabel;

	// 设置文字函数
	void SetGameOverString(const char *str);
};



GameOverLayer.cpp


#include "GameOverLayer.h"
USING_NS_CC;

GameOverLayer::GameOverLayer(void)
	:_pLabel(NULL)
{
}


GameOverLayer::~GameOverLayer(void)
{
}


bool GameOverLayer::init()
{
	bool bRct = false;

	do 
	{
		// 必须先调用父类初始化
		CC_BREAK_IF(!CCLayerColor::initWithColor(ccc4(0, 0, 0, 255)));

		// 创建Label
		_pLabel = CCLabelTTF::create("", "Arial", 34);

		// 检查
		CC_BREAK_IF(!_pLabel);

		// 设置Label位置为窗口正中
		_pLabel->setPosition( ccp(CCDirector::sharedDirector()->getWinSize().width/2, CCDirector::sharedDirector()->getWinSize().height/2) );

		// 将Label添加至布景Layer
		this->addChild(_pLabel);

		bRct = true;
	} while (0);

	return bRct;
}


void GameOverLayer::SetGameOverString(const char *str)
{
	_pLabel->setString(str);
}



GameOverScene.h


#pragma once
#include "cocos2d.h"
#include "GameOverLayer.h"
class GameOverScene : public cocos2d::CCScene
{
public:
	GameOverScene(void);
	~GameOverScene(void);

	bool init();
	CREATE_FUNC(GameOverScene);

	// 游戏结束布景层指针
	GameOverLayer *_pGameOverLayer;

	// 返回布景层的指针
	GameOverLayer* GetGameOverLayerPointer();
};



GameOverScene.cpp


#include "GameOverScene.h"
USING_NS_CC;

GameOverScene::GameOverScene(void)
	:_pGameOverLayer(NULL)
{
}


GameOverScene::~GameOverScene(void)
{
}


bool GameOverScene::init()
{
	bool bRct = false;

	do 
	{
		CC_BREAK_IF(!CCScene::init());

		// 创建GameOverLayer对象
		_pGameOverLayer = GameOverLayer::create();

		// 检查
		CC_BREAK_IF(!_pGameOverLayer);

		// 将布景添加至场景中
		this->addChild(_pGameOverLayer);

		bRct = true;
	} while (0);

	return bRct;
}

GameOverLayer* GameOverScene::GetGameOverLayerPointer()
{
	return _pGameOverLayer;
}



另外,在ShooterLayer中判断胜负,并切换场景:

ShooterLayer.h


#pragma once
#include "cocos2d.h"
class ShooterLayer : public cocos2d::CCLayerColor
{
public:
	ShooterLayer(void);
	~ShooterLayer(void);

	// 初始化函数
	bool init();
	// new一个对象,如果成功的话则调用初始化函数
	CREATE_FUNC(ShooterLayer);
	
	// 关闭菜单的回调函数
	void menuCloseCallback(CCObject *pObj);
	// 计时器的回调函数
	void update(float dt);

	// 随机创建敌方精灵
	void addTarget();

	// 敌方精灵飞出边界的回调函数
	void SpriteMoveFinished(CCNode *pObj);

	// 触摸操作(即Win32中的鼠标点击操作)响应函数
	void ccTouchesEnded(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);

	// 保存射击精灵的大小
	cocos2d::CCSize _szPlayer;

	// 碰撞检测
	void bulletCrashTest();

	// 敌人精灵数组
	cocos2d::CCArray *_targets;

	// 子弹精灵数组
	cocos2d::CCArray *_projectiles;

	// 显示击中次数(得分)
	cocos2d::CCLabelTTF* _pLabel;

	// 保存击中次数
	int _score;

	// 定义一个常量,用于设置初始的分数
	const int constInitialScore;
};



ShooterLayer.cpp


#include "ShooterLayer.h"
#include "GameOverScene.h"
USING_NS_CC;

// 标记精灵
enum
{
	TARGET,
	PROJECT
};

ShooterLayer::ShooterLayer(void)
	:_score(0)
	,constInitialScore(10)
{
	_score = constInitialScore;
	_targets = NULL;
	_projectiles = NULL;
}

ShooterLayer::~ShooterLayer(void)
{
	if (_targets)
	{
		delete _targets;
		_targets = NULL;
	}

	if (_projectiles)
	{
		delete _projectiles;
		_projectiles = NULL;
	}
}


bool ShooterLayer::init()
{
	bool bRct = false;

	// 初始化数组
	_targets = new CCArray;
	_projectiles = new CCArray;

	do 
	{
		// 1、初始化布景
		CC_BREAK_IF(!CCLayerColor::initWithColor(ccc4(255, 227, 132, 255)));

		// 2、创建窗口右下角的关闭菜单
		// 创建菜单项
		CCMenuItemImage *pCloseItem = NULL;

		pCloseItem = CCMenuItemImage::create(
			"CloseNormal.png",
			"CloseSelected.png",
			this,
			menu_selector(ShooterLayer::menuCloseCallback)); // 回调函数
		
		// 检测创建是否成功
		CC_BREAK_IF(!pCloseItem);  // create失败则返回
		// 设置菜单项位置
		pCloseItem->setPosition(CCDirector::sharedDirector()->getWinSize().width - 20, 20);	
		// 创建菜单
		CCMenu *pMenu = CCMenu::create(pCloseItem, NULL);
		// 设置菜单位置
		pMenu->setPosition(CCPointZero);
		// 将菜单添加至布景
		this->addChild(pMenu);
		//

		// 创建精灵
		CCSprite *pSprite = CCSprite::create("Player.png");
		// 获取窗口大小
		CCSize sz = CCDirector::sharedDirector()->getWinSize();
		// 设置精灵位置
		pSprite->setPosition(CCPointMake(pSprite->getContentSize().width/2, sz.height/2));
		// 将精灵添加至布景
		this->addChild(pSprite);
		// 保存精灵大小
		_szPlayer = pSprite->getContentSize();


		//
		
		// 显示分数的Label
		// Create a label and initialize with string "0".
		_pLabel = CCLabelTTF::create("Your Score:0", "Arial", 24);

		// 设置颜色
		_pLabel->setColor(ccc3(0, 0, 0));

		CC_BREAK_IF(! _pLabel);

		// Get window size and place the label upper. 
		CCSize size = CCDirector::sharedDirector()->getWinSize();
		_pLabel->setPosition(ccp(size.width - 100, size.height - 50));

		// Add the label to HelloWorld layer as a child layer.
		this->addChild(_pLabel, 1);

		//


		//
	
		// 设置计时器
		this->scheduleUpdate();
		//


		// 允许触摸(注意:很重要)
		this->setTouchEnabled(true);
		//
		bRct = true;
	} while (0);

	return bRct;
}

void ShooterLayer::menuCloseCallback(CCObject *pObj)
{
	// 退出程序
	CCDirector::sharedDirector()->end();
}

void ShooterLayer::update(float dt)
{
	static int tmpTimes = 0;
	static int tmpCount = 20;

	if (tmpTimes++ > tmpCount)
	{
		addTarget();
		tmpCount = rand() % 60 + 20;
		tmpTimes = 0;
	}

	bulletCrashTest();
}

void ShooterLayer::addTarget()
{
	// 创建精灵
	CCSprite *target = CCSprite::create("Target.png");

	// 计算敌方精灵可能出现的位置范围
	CCSize sz = CCDirector::sharedDirector()->getWinSize();
	int x = sz.width + target->getContentSize().width/2;
	int nMax = sz.height - target->getContentSize().height/2;
	int nMin = target->getContentSize().height/2;

	// 产生随机数
	int f = rand() % (nMax - nMin);
	int y = nMin + f;

	// 根据随机数,设置起始精灵位置
	target->setPosition(CCPointMake(x, y));

	// 利用计时器确定执行序列动作的速度
	float nDurMin = 2.0;
	float nDurMax = 4.0;
	float nDur = float(rand() % 100) / 100.0 + nDurMin;
	nDur = nDur > nDurMax ? nDurMax : nDur;

	// 定义两个动作(平移动作, 以及移出边界的响应)
	CCFiniteTimeAction *action = CCMoveTo::create(nDur, ccp(-target->getContentSize().width/2, y));
	CCFiniteTimeAction *actionDone = CCCallFuncN::create(this,
		callfuncN_selector(ShooterLayer::SpriteMoveFinished));  // 这里需要一个移出边界的响应函数
	
	// 添加序列动作
	CCAction *pseq = CCSequence::create(action, actionDone, NULL); 

	// 将序列动作添加至精灵,使其执行
	target->runAction(pseq);

	// 将精灵添加至布景
	this->addChild(target);

	//

	// 加入数组
	_targets->addObject(target);
	// 设置标记
	target->setTag(TARGET);
}

void ShooterLayer::SpriteMoveFinished(CCNode *pObj)
{
	// 获取移出精灵对象指针
	CCSprite *pSprite = (CCSprite*)pObj;
	// 清除
	this->removeChild(pSprite, true);

	//

	// 根据标记,释放对象
	if (pSprite->getTag() == TARGET)
	{
		_targets->removeObject(pSprite);

		_score--;

		// 通过Label显示碰撞次数(即得分)
		CCString *str = CCString::stringWithFormat("Your Score:%d", _score);
		_pLabel->setString(str->getCString());

		// 游戏失败
		if (_score < 0)
		{
			_score = constInitialScore; // 重置为初始值

			// 创建游戏失败场景
			GameOverScene *pGameOverScene = GameOverScene::create();
			pGameOverScene->GetGameOverLayerPointer()->SetGameOverString("You Lost!");

			// 切换场景
			CCDirector::sharedDirector()->replaceScene(pGameOverScene);
		}
	}
	else if (pSprite->getTag() == PROJECT)
	{
		_projectiles->removeObject(pSprite);
	}
}

void ShooterLayer::ccTouchesEnded(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent)
{
	// 获取CCTouch指针对象
	CCTouch *pTouch = (CCTouch*)pTouches->anyObject();
	// 获取视图位置
	CCPoint location = pTouch->getLocationInView();
	// 转化为OpenGL坐标
	location = CCDirector::sharedDirector()->convertToGL(location); 

	// 创建子弹精灵
	CCSprite *project = CCSprite::create("Projectile.png");
	// 窗口大小
	CCSize sz = CCDirector::sharedDirector()->getWinSize(); 
	// 子弹起点
	CCPoint pt = ccp(_szPlayer.width + project->getContentSize().width/2, sz.height/2);
	// 设置子弹起点
	project->setPosition(pt); 
	// 添加精灵至布景
	this->addChild(project);  

	//

	// 添加至数组
	_projectiles->addObject(project);
	// 添加标记
	project->setTag(PROJECT);

	//


	// 求出子弹终点坐标
	int x = sz.width + project->getContentSize().width/2;
	float yDistance = (location.y - pt.y) / (location.x - pt.x) * (sz.width - _szPlayer.width);

	// 子弹动作
	CCFiniteTimeAction *action = CCMoveTo::create(1.0, ccp(x, yDistance + sz.height/2));
	CCFiniteTimeAction *actionDone = CCCallFuncN::create(this, callfuncN_selector(ShooterLayer::SpriteMoveFinished));

	project->runAction(CCSequence::create(action, actionDone, NULL));
}

void ShooterLayer::bulletCrashTest()
{
	// 定义两个数组用于存储待删除的精灵
	CCArray * projectilesToDelete  = new CCArray;
	CCArray * targetsToDelete  = new CCArray;

	CCObject* it = NULL;
	CCObject* jt = NULL;

	CCARRAY_FOREACH(_projectiles, it)
	{
		CCSprite *projectile = dynamic_cast<CCSprite *>(it);
		CCRect projectileRect = CCRectMake(projectile->getPosition().x - 
			(projectile->getContentSize().width/2), projectile->getPosition().y - 
			(projectile->getContentSize().height/2), projectile->getContentSize().width, projectile->getContentSize().height);


		CCARRAY_FOREACH(_targets, jt)		
		{
			CCSprite *target = dynamic_cast<CCSprite*>(jt);

			CCRect targetRect = CCRectMake(target->getPosition().x - (target->getContentSize().width/2),
				target->getPosition().y - (target->getContentSize().height/2),target->getContentSize().width, target->getContentSize().height);

			// 碰撞检测
			if (/*CCRect::CCRectIntersectsRect(projectileRect, targetRect)*/projectileRect.intersectsRect(targetRect))
			{
				_score ++;  // 碰撞次数

				// 将精灵移入待删除数组
				targetsToDelete->addObject(target);
				projectilesToDelete->addObject(projectile);

				// 通过Label显示碰撞次数(即得分)
				CCString *str = CCString::stringWithFormat("Your Score:%d", _score);
				_pLabel->setString(str->getCString());

				// 胜利条件
				if (_score > 20)
				{
					_score = constInitialScore; // 重置为初始值

					// 创建游戏结束场景
					GameOverScene *pGameOverScene = GameOverScene::create();
					pGameOverScene->GetGameOverLayerPointer()->SetGameOverString("You Win!");

					// 切换场景
					CCDirector::sharedDirector()->replaceScene(pGameOverScene);
				}
			}
		}
	}

	// 释放资源

	CCARRAY_FOREACH(targetsToDelete, jt)	
	{
		CCSprite *target = dynamic_cast<CCSprite*>(jt);

		_targets->removeObject(target);
		this->removeChild(target, true);

	}

	CCARRAY_FOREACH(projectilesToDelete, it)
	{

		CCSprite* projectile = dynamic_cast<CCSprite*>(it);
		_projectiles->removeObject(projectile);
		this->removeChild(projectile, true);

	}

	projectilesToDelete->release();
	targetsToDelete->release();
}




4、游戏胜利:

Cocos2D-X射击小游戏(九)编码7 场景切换_2d


5、游戏失败:

Cocos2D-X射击小游戏(九)编码7 场景切换_#include_02


6、待续