暂停功能的做法有很多,拿我原来的例子来说吧,是弹出一个层,然后这个层屏蔽了下层的触摸事件,然后在这个层上实现一些逻辑,这个也是一般暂停功能的做法。或者你可以直接使用pause函数,但是这样做的话触摸是不能屏蔽的,就会导致一个bug使游戏不完善。今天为了玩下截屏,我用这个来做一个暂停功能,熟悉一下3.0的RenderTexture的用法。原理是这样的,当玩家按下了暂停按钮的时候我们截取一下当前场景的屏幕,把图片保存起来,然后跳转到一个新的场景,在这个场景中添加上刚才保存的图片,再添加一个恢复按钮,为了美观还可以添加一些其他的动画,按下恢复按钮弹出刚才的场景,这样做最后是可以实现的,但是要注意在新场景中的东西不要太多,因为旧的场景是push到栈中的,太多游戏就卡了。在使用renderTexture的过程中,真是遇到了不少的问题,比如截取了图片在切换新场景以后报错说是没有这张图片,原因有俩个,一个是3.0截屏需要在截完屏的下一帧才能处理RenderTexture,这样的话在这一帧就切换场景的话肯定是不行的,另一个是路径不对,这个问题使用FileUtils来解决。最后还有一个问题是第一次暂停完全是ok的,以后暂停的话使用的却是第一次用的图片,这是因为第一次使用了图片以后就放在了缓存中了,下次用的时候直接会从缓存中取,这样的话虽然截屏的图片改变了但是用的却是原来的图片,解决方法是改变图片的文件名,新场景使用的图片文件名,每次都不同,但是原来的文件记得要删除,否则就占用了太多的磁盘空间了。好了说了这么多,看代码吧!

#ifndef _UILAYER_H_
#define _UILAYER_H_
#include "cocos2d.h"
//暂停场景
#include "Pause.h"

USING_NS_CC;

//UI层
class UILayer : public Layer
{
public:
	UILayer(void);
	~UILayer(void);
public:
	bool init();
	CREATE_FUNC(UILayer);
public:
	//按钮的回调函数
	void menuCallback(Ref * ref);
};

#endif
#include "UILayer.h"

UILayer::UILayer(void)
{
}

UILayer::~UILayer(void)
{
}

bool UILayer::init()
{
	if(!Layer::init())
		return false;

	auto size = Director::getInstance()->getWinSize();

	//从xml文件中读取中文显示出来
	auto dictionary = Dictionary::createWithContentsOfFile("font/text.xml");
	auto score_label = Label::createWithTTF(((__String *)(dictionary->objectForKey("score")))->getCString(),"font/DFPShaoNvW5-GB.ttf",40);
	score_label->setPosition(score_label->getContentSize().width/2,
		size.height-score_label->getContentSize().height/2);
	this->addChild(score_label);

	//添加游戏暂停和开始的开关菜单
	auto toggle1 = MenuItemImage::create();
	toggle1->setNormalSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("pause_button.png"));
	auto toggle2 = MenuItemImage::create();
	toggle2->setNormalSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("resume_button.png"));
	auto menuToggle = MenuItemToggle::createWithCallback(CC_CALLBACK_1(UILayer::menuCallback,this),toggle1,toggle2,NULL);
	//刚开始设置选择的index是0,如果点击了暂停设置index为1,toggle中的index是从0开始的,第一个添加进去的
	//item的index为0
	menuToggle->setSelectedIndex(0);
	auto menu = Menu::create(menuToggle,NULL);
	menu->setPosition(Point(size.width*0.95,size.height*0.97));
	this->addChild(menu);

	return true;
}

void UILayer::menuCallback(Ref * ref)
{
	auto toggle = (MenuItemToggle *)ref;
	//根据用户选择的不同做不同的处理,刚开始我们设置的时候是0,一点击系统就进行了切换,将index设置为了1
	if(toggle->getSelectedIndex() == 1)
	{
		//可以直接使用pause方法暂停当前的场景,但是这样做有一个bug,就是不能够屏蔽触摸事件,所以采用截图的方法
		//Director::getInstance()->pause();

		/*截取当前场景的图片并且保存*/

		auto size = Director::getInstance()->getWinSize();
		//RenderTexture是一个纹理渲染类,我们需要把要渲染的当前场景放进去,这是初始化它的大小
		auto render = RenderTexture::create(size.width,size.height);
		//开始获取内容
		render->begin();
		//是用节点的visit方法加入到渲染中
		Director::getInstance()->getRunningScene()->visit();
		//结束
		render->end();

		//这里要特别的说明一下,如果保存的文件的名称不变,那在第二次以后暂停的时候用的图片还是第一次的图片
		//虽然路径下的图片发生了改变,但是第一次的图片已经放到了缓存中,所以使用如下的方法解决
		auto index = UserDefault::getInstance()->getIntegerForKey("index",0);
		UserDefault::getInstance()->setIntegerForKey("index",index+1);
		auto str = __String::createWithFormat("pause%d.png",index);

		//我们每次截图都改变了图片的名称,这样在设备上会有很多的图片,所以要把之前的图片删除掉
		if(index != 0)
		{
			auto str = __String::createWithFormat("pause%d.png",index-1);
			auto fullPath = FileUtils::getInstance()->getWritablePath() + str->getCString();
			if(FileUtils::getInstance()->isFileExist(fullPath))
			{
				remove(fullPath.c_str());
			}
		}

		//保存图片为PNG格式,当我们想要获取这个文件的时候使用
		//FileUtils::getInstance()->getWritablePath() + "pause.png";,通过这个方法就可以取得我们保存的图片啦
		render->saveToFile(str->getCString(),Image::Format::PNG);

		//对声音的处理
		// SimpleAudioEngine::getInstance()->pauseBackgroundMusic();

		//3.0截屏需要在截完屏的下一帧才能处理RenderTexture,这点要注意
		auto _schedule = this->getScheduler();
		auto replaceScene = [](float tm)
		{
			//最后切换场景
			Director::getInstance()->pushScene(Pause::createScene());
		};
		 _schedule->schedule(replaceScene, this, 0.0f,0,0.0f, false, "screenshot");

		 toggle->setSelectedIndex(0);
	}
}
#ifndef _PAUSE_H_
#define _PAUSE_H_
#include "cocos2d.h"

USING_NS_CC;

class Pause : public Layer
{
public:
	Pause(void);
	~Pause(void);
public:
	bool init();
	static Scene * createScene();
	CREATE_FUNC(Pause);
};

#endif
#include "Pause.h"

Pause::Pause(void)
{
}

Pause::~Pause(void)
{
}

Scene * Pause::createScene()
{
	auto scene = Scene::create();
	auto layer = Pause::create();
	scene->addChild(layer);

	return scene;
}

bool Pause::init()
{
	if(!Layer::init())
		return false;

	auto size = Director::getInstance()->getWinSize();

	auto index = UserDefault::getInstance()->getIntegerForKey("index");
	auto str = __String::createWithFormat("pause%d.png",index-1);
	//CCFileUtils::sharedFileUtils()->getWritablePath();提供了一个可以存储的路径
	auto fullPath = FileUtils::getInstance()->getWritablePath() + str->getCString();
	//这里把截屏的那张图片做为背景图片
	auto background = Sprite::create(fullPath);
	background->setPosition(Point(size.width/2,size.height/2));
	this->addChild(background);

	//添加恢复游戏的按钮
	auto resume = MenuItemImage::create();
	resume->setNormalSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("resume_button.png"));
	auto callback = [](Ref * ref)
	{
		//弹出保存的场景
		Director::getInstance()->popScene();
	};
	resume->setCallback(callback);
	auto menu = Menu::create(resume,NULL);
	menu->setPosition(Point(size.width*0.95,size.height*0.97));
	this->addChild(menu);

	//loading的动画效果
	Vector<SpriteFrame *> vector;
	for(int i=0;i<6;i++)
	{
		auto str = __String::createWithFormat("loading_%d.png",i+1);
		auto spriteFrame = SpriteFrameCache::getInstance()->getSpriteFrameByName(str->getCString());
		vector.pushBack(spriteFrame);
	}
	auto animation = Animation::createWithSpriteFrames(vector,0.2f,-1);
	auto animate = Animate::create(animation);
	//设置用来执行动画的loading图片
	auto loading = Sprite::createWithSpriteFrameName("loading_1.png");
	loading->setPosition(Point(size.width*0.85,size.height*0.1));
	this->addChild(loading);

	loading->runAction(animate);

	return true;
}

用3.0实现飞机大战——通过截屏实现暂停功能