在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,将宣传边框和截图摆好位置,再次截屏,这样就得到一张完整的游戏宣传截图,可以拿来分享到其他社交软件平台上。