在cocos2d-x中,Director类自带pause()方法用来暂停整个游戏,相应的resume()方法用来返回游戏。但当我们使用pause()方法时却会让游戏显得很卡,有时即使resume了,游戏还是会卡。而且现在大多数游戏在按暂停键的时候都会弹出一个Resume的Scene用来提示玩家一些信息,并且带有一个Resume按钮用来点击返回游戏。结合这两点,这里采用另外一种策略来暂停游戏。
1. 取得点击暂停那一瞬间的屏幕截屏
2. 创建一个ResumeScene, 在ResumeScene上加入获得的截屏
3. 在ResumeScene上加上一个不可碰触的,黑色半透明的ColorLayer用来阻拦用户的操作。
4. 在ResumeScene上加上一个Resume按钮用来返回游戏。
1. 取得点击暂停那一瞬间的屏幕截屏
3.0的截屏和2.x的截屏基本上相同,都是利用RenderTexture来处理,在渲染之前调用call函数,然后调用Cocos的场景visit函数对其进行渲染,渲染结束后调用end函数即可。只是3.0截屏需要在截完屏的下一帧才能处理RenderTexture,这点要注意。
在这里我们另外写一个工具类ScreenShoter
void ScreenShoter::saveScreenshot( const std::string& fileName, const std::function< void ( const std::string& ) >& callback ) {
Image::Format format;
//进行后缀判断
if(std::string::npos != fileName.find_last_of(".")){
auto extension = fileName.substr(fileName.find_last_of("."),fileName.length());
if (!extension.compare(".png")) {
format = Image::Format::PNG;
} else if(!extension.compare(".jpg")) {
format = Image::Format::JPG;
} else{
CCLOG("cocos2d: the image can only be saved as JPG or PNG format");
return;
}
} else {
CCLOG("cocos2d: the image can only be saved as JPG or PNG format");
return ;
}
//获取屏幕尺寸,初始化一个空的渲染纹理对象
auto director = Director::getInstance();
auto renderTexture = RenderTexture::create( director->getWinSize().width, director->getWinSize().height, Texture2D::PixelFormat::RGBA8888);
//清空并开始获取
renderTexture->beginWithClear(0.0f, 0.0f, 0.0f, 0.0f);
//遍历场景节点对象,填充纹理到RenderTexture中
director->getRunningScene()->visit();
//结束获取
renderTexture->end();
//保存文件
renderTexture->saveToFile(fileName , format);
//3.0截屏需要在截完屏的下一帧才能处理RenderTexture
//使用schedule在下一帧中调用callback函数
auto fullPath = FileUtils::getInstance()->getWritablePath() + fileName;
auto scheduleCallback = [&,fullPath,callback](float dt){
callback(fullPath);
};
auto _schedule = director->getRunningScene()->getScheduler();
_schedule->schedule(scheduleCallback, director, 0.0f,0,0.0f, false, "screenshot");
}
2. 创建一个ResumeScene, 在ResumeScene上加入获得的截屏
我们在按钮的callBack函数中调用此函数即可 :
void OptionLayer::pauseBtnCallBack( Ref* ref ) {
auto callback = [&]( const std::string& fullPath ) {
auto screenShotSprite = Sprite::create( fullPath );
auto resumeScene = ResumeScene::create();
resumeScene->setBackground( screenShotSprite );
//将Scene转变为ResumeScene
Director::getInstance()->replaceScene( resumeScene );
};
ScreenShoter::saveScreenshot( "screenShot.png", callback );
}
3. 在ResumeScene的setBackground方法中加上一个不可碰触的,黑色半透明的ColorLayer,用来阻拦用户的操作。
void ResumeScene::setBackground( Sprite* iBackground ) {
auto winSize = Director::getInstance()->getWinSize();
this->resumeLayer = Layer::create();
this->addChild( resumeLayer );
iBackground->setPosition( winSize.width / 2, winSize.height / 2 );
this->resumeLayer->addChild( iBackground );
}
4. 在ResumeScene的init()方法中便可以加入Resume按钮,只用设置Zorder优先级为3即可。
总结:
通过简单的几步就可以做出一个效果相当不错的暂停效果,但由于RenderTexture在截屏后需要在下一帧才能处理Texture,在按下暂停按钮到进入ResumeScene之间有一帧的延迟,对于大多数游戏都是可以接受的。