在Cocos2d-X 3.x里面,已经集成了截屏功能,单独放在utils命名空间里,实现在base/ccUtils.h文件里面。看下函数申明
/** Capture the entire screen * To ensure the snapshot is applied after everything is updated and rendered in the current frame, * we need to wrap the operation with a custom command which is then inserted into the tail of the render queue. * @param afterCaptured, specify the callback function which will be invoked after the snapshot is done. * @param filename, specify a filename where the snapshot is stored. This parameter can be either an absolute path or a simple * base filename ("hello.png" etc.), don't use a relative path containing directory names.("mydir/hello.png" etc.) * @since v3.2 */
简单看下,就是自定义一个渲染命令,加入到渲染队列尾部。
函数参数有两个,,第一个是截屏完成后的操作函数回调,一个事自定义的截屏图片名字。
回调函数有两个固定参数,一个是 bool型,用来判断截屏是否成功,另外一个是filename,实际上就是第二个参数会传入该回掉函数。
void captureScreen(const std::function<void(bool, const std::string&)>& afterCaptured, const std::string& filename);
有一个很重要的问题就是:上面函数的参数filename需要加上图片格式,例如:screenshot.png。因为,在函数实现内部使用过后缀来确定保存类型的,这个略坑,建议使用jpg,毕竟图片会小很多。
我的工程是直接用的helloword,在helloscene上添加一个label,用来做截屏点击按钮,效果如图:
现在呢,对于Capture这个label来说,我们有两种方法给他添加响应函数,
1、把这个label加入menu,这样可以很简单的添加回掉函数,这种方法很通用,就不细说了。
2、另一种就是使用触摸点击来给这个label添加响应函数。
首先,需要添加一个aftercapture函数,在这个函数里面呢,将截屏的图片显示出来,具体做法就是重新创建一个scene,将图片放上去,通过导演切换到这个scene。看代码:
void HelloWorld::afterCaptureScreen(bool issuccess, const std::string &filename) //这个函数参数是固定的,不能写错了 { auto size = Director::getInstance()->getWinSize(); if (issuccess) { auto scene = Scene::create(); auto sp = Sprite::create(filename); sp->setScale(0.8f); sp->setPosition(Vec2(size.width/2, size.height/2)); scene->addChild(sp); auto lb = LabelTTF::create(); lb->setString("capture success!"); lb->setColor(ccc3 (255, 0, 0)); lb->setFontSize(40); lb->setAnchorPoint(Vec2(0.5f, 1.0f)); lb->setPosition(Vec2(size.width/2, size.height)); scene->addChild(lb); Director::getInstance()->replaceScene(scene); } else { auto scene = Scene::create(); auto lb = Label::create(); lb->setString("Capture Failed!"); lb->setTextColor(ccc4(255, 0, 0, 255)); lb->setPosition(Vec2(size.width / 2, size.height/2)); scene->addChild(lb); Director::getInstance()->replaceScene(scene); } }
接下来再添加一个函数,用于在在Capture这个label的touch ended里面调用,代码如下:
void HelloWorld::capturesc(std::string &filename) { Director::getInstance()->getTextureCache()->removeTextureForKey(filename); //这里最好加上这句,因为如果你需要重复点击这个按钮进行截屏操作的话,TextureCache里面不清除,会导致截屏失败 utils::captureScreen(CC_CALLBACK_2(HelloWorld::afterCaptureScreen, this), filename); //在这里调用cocos2d已经实现好的captureScreen函数,将我们写好的aftercapture函数和我们需要的图片名称穿进去,图片名称的初始化必须在这个函数调用之前完成 }
最后完成label触摸事件写好就OK了,当然,lambda表达式用上:
auto *ev = EventListenerTouchOneByOne::create(); //filename = "capturesc.png"; //filename可以在这里初始化 ev->onTouchBegan = [](Touch* t, Event* e){ cocos2d::log("touch begin!"); return true; }; ev->onTouchMoved = [](Touch* t, Event* e){}; ev->onTouchEnded = [&,caplb](Touch* t, Event* e){ auto pos = t->getLocation(); auto rect = caplb->getBoundingBox(); auto cpos = caplb->convertToNodeSpace(pos); if (rect.containsPoint (cpos)) { cocos2d::log("caplb is touched!!"); filename = "scpic.jpg"; //初始化filename,后缀很重要 caplb->setVisible(false);//将Capture这个label隐藏 capturesc(filename); //截屏 } };
这段代码写在HelloWord的init函数里面。
这样就完成了,截屏操作,相对于2.x的截屏好像简单了,这个就仁者见仁智者见智了。在2.x版本里面的截屏操作需要注意的是再创建Render的时候,需要传入渲染颜色深度,否则会导致visit函数渲染时无法正确进行各个对象之间的遮挡关系计算,看下最后的效果图:
那么最后呢,可能截屏并不是我们的最终目的,可能为了游戏的宣传,我们还需要给这张截图添上游戏的宣传边框,这时候,我们就需要在截图之后再次创建一个场景scene,将宣传边框和截图摆好位置,再次截屏,这样就得到一张完整的游戏宣传截图,可以拿来分享到其他社交软件平台上。