美文网首页
Creator 原生无感截图

Creator 原生无感截图

作者: Jaymz_2b11 | 来源:发表于2020-07-23 11:04 被阅读0次

    接到需求,需要在原生中生成带二维码的海报,于是有了这篇记录
    原生中不像微信小游戏那样,有离屏画布,所以必须要采用其他的方案来做

    思路如下,使用双相机实现无感截图
    主相机展示 UI界面,新增截图相机来做截图
    具体实现,在需要截图的界面新增一个相机,同时新增一个sceneShot的层,截图相机渲染Group为sceneShot的元素
    主相机渲染剔除sceneShot层,同时设置相机深度,sceneShot优先级比主相机优先级高即可

    截图相机属性


    image.png

    主相机属性


    image.png

    后续就使用 cc.RenderTexture 组件,将截图相机中的内容送进来,然后使用RenderTexture实例 调用readPixels方法完成截图,截图时需要把二维码挂在上面所以,有一个等待机制,假设code 没加载出来,那么这截图没有任何意义,因为截图时间长,所以我做了缓存,做了缓存以后,发现需要更新截图的时候不方便(比如海报变动,或者code变动),我又做了版本比对,游戏启动会去读取配置信息,根据配置信息中的shareBgVersion 与 本地存储的shareBgVersion 进行对比,若服务器版本高且图片存在,那么会删除图片重新截图,同时把服务器版本保存到本地,
    以备下一次更新,代码如下

    
    const {ccclass, property} = cc._decorator;
    
    @ccclass
    export default class UISharePanel extends UI 
    {
    
        @property(cc.Node) btn_close : cc.Node = null;
    
        @property(cc.Node) btn_friend : cc.Node = null;
    
        @property(cc.Node) btn_circle : cc.Node = null;
    
        @property(cc.Sprite) bg_shot : cc.Sprite = null;
    
        @property(cc.Camera) camera : cc.Camera = null;
    
        @property(cc.Sprite) headIcon : cc.Sprite = null;
    
        @property(cc.Sprite) inviteCodeImage : cc.Sprite = null;
    
        @property(cc.Node) content : cc.Node = null;
    
        @property(cc.Node) item : cc.Node = null;
    
        @property(cc.Node) loading : cc.Node = null;
    
        @property(cc.PageView) pageView : cc.PageView = null;
    
        private texture : cc.RenderTexture = null;
    
        private prefixPath = "";
    
        private width = 720;
    
        private height = 1280;
    
        private curIdx = 0; //当前索引
    
        private shotIdx = 1;
    
        private shotComplete : Function = null;
    
        private picDataList = [];
    
        private isCanShot = false; //是否可以截图
    
        private isNeedShot = false; //是否需要截图
    
        private pageSize = null;
    
        private shareBgList:string[] = 
        [
            "share_1.png",
            "share_2.png",
        ]
    
        public Init()
        {
            if(!CC_JSB)
            {
                return;
            }
            this.prefixPath = jsb.fileUtils.getWritablePath();
            if(cc.sys.os == cc.sys.OS_ANDROID)
            {
                this.prefixPath = '/sdcard/';
            }
            this.pageSize = this.item.getContentSize();
            this.texture = new cc.RenderTexture();
            let gl = cc.game._renderContext;
            this.texture.initWithSize(this.width,this.height,gl.STENCIL_INDEX8);
            this.camera.targetTexture = this.texture;
            this.UpdateShareInfo();
            this.pageView.setCurrentPageIndex(this.curIdx);
            this.curIdx ++;
        }
    
        //更新邀请信息
        public UpdateShareInfo()
        {
            //this.inviteCodeLabel.string = "<b><color=#000000>我的邀请码:"+ Player.Instance.playerInfo.invitationCode +"</c>";
            this.LoadImage(this.inviteCodeImage,Player.Instance.playerInfo.codeUrl,this.LoadFinished.bind(this));  
            this.LoadImage(this.headIcon,Player.Instance.playerInfo.hearImg,this.LoadFinished.bind(this));
        }
    
        private idx = 0;
        public LoadFinished()
        {
            this.idx ++;
            console.log("LoadFinished : " + this.idx);
            if(this.idx>=2)
            {
                console.error("图片加载完毕 可以截图");
                this.isCanShot = true;
                if(this.isNeedShot)
                {
                    console.error("检测要需要截图,开始截图");
                    this.ShotFunc();
                }
            }
        }    
    
        public LoadImage(image:cc.Sprite, url:string,callback:Function)
        {
            if(!url || url == "")
            {
                console.log("URL 为 null");
                return;
            }
            console.log("开始下载图片 : " + url);
            cc.loader.load({url: url, type: 'png'},(err,res)=>{
                if(err != null)
                {
                    console.error("加载Image Error : " +JSON.stringify(err));
                    return;
                }
                console.log("加载图片成功 : URL : " + url);
                image.spriteFrame = new cc.SpriteFrame(res);
                if(callback)
                {
                    callback();
                }
            });
        }
    
        // 监听事件
        public OnPageEvent(sender, eventType) 
        { 
            // 翻页事件
            if (eventType !== cc.PageView.EventType.PAGE_TURNING) {
                return;
            }
            console.log("当前所在的页面索引:" + sender.getCurrentPageIndex());
            this.curIdx = sender.getCurrentPageIndex() + 1;
        }
    
        public GetCurShareURL()
        {
            return this.prefixPath + this.shareBgList[this.curIdx-1];
        }
    
        //检查分享背景图版本
        //返回值是否需要重新截图
        public CheckUpdateShareBg():boolean
        {
            let curVersion = cc.sys.localStorage.getItem("shareBgVersion");
            let serverVersion = HeroGame.Instance.GameConfigInfo.shareBgVersion;
            if(!curVersion)
            {
                return true;
            }
            else
            {
                if(serverVersion >= curVersion)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }
    
        public DeleteShareBg()
        {
            for(let i = 0;i<this.shareBgList.length;++i)
            {
                if (jsb.fileUtils.isFileExist(this.prefixPath + this.shareBgList[i])) 
                {
                    console.error("删除图片 Path: " + this.prefixPath + this.shareBgList[i]);
                    jsb.fileUtils.removeFile(this.prefixPath + this.shareBgList[i]);
                    //cc.loader.releaseRes(this.prefixPath + this.shareBgList[i]);      
                }
            }
        }
    
        public CheckShareBgExist()
        {
            let isExist = true;
            for(let i = 0;i<this.shareBgList.length;++i)
            {
                if (!jsb.fileUtils.isFileExist(this.prefixPath + this.shareBgList[i])) 
                {
                    isExist = false;
                    break;
                }
            }
            return isExist;
        }
    
        //开始截图
        public StartSceneShot()
        {
            if(!CC_JSB)
            {
                this.loading.active = false;
                UIItem.InitList(this.content);
                return;
            }
    
            this.loading.active = true;
            UIItem.InitList(this.content);
            //首先检测一下是否图片已经存在 若存在直接读取
            let isExist = this.CheckShareBgExist();
            let isUpdate = this.CheckUpdateShareBg(); //检测是否需要更新
            if (isUpdate && isExist) 
            {
                console.error("图片存在且需要更新");
                this.DeleteShareBg();
                isExist = false;
            }
            
            if(isExist)
            {
                console.log("图片已经存在,直接读取");
                UIItem.InitList(this.content);
                this.pageView.removeAllPages();
                //读取展示
                for(let i = 0;i<this.shareBgList.length;++i)
                {   
                    let sprite :cc.SpriteFrame = null;
                    console.log(this.prefixPath+this.shareBgList[i]);
                    cc.loader.load(this.prefixPath+this.shareBgList[i],(err,res)=>
                    {
                        if(err)
                        {
                            console.error(err);
                            return;
                        }
                        else
                        {
                            console.log("加载成功");
                            sprite = new cc.SpriteFrame();
                            sprite.setTexture(res);
                            let node = cc.instantiate(this.item);
                            console.log(node.getContentSize());
                            node.name = "share_"+i;
                            this.pageView.addPage(node);
                            let Image = node.getComponent(cc.Sprite);
                            Image.spriteFrame = sprite;
                            node.active = true;
                        }
                    })
                }
                let size = this.content.getContentSize();
                this.content.setContentSize(cc.size(200 + this.shareBgList.length* 534,size.height));
                this.loading.active = false;
            }
            else
            {
                console.log("图片不存在,需要重新截图");
                //图片不存在重新截图保存
                this.shotComplete = ()=>
                {
                    console.log("截图全部完成");
                    cc.sys.localStorage.setItem("shareBgVersion",HeroGame.Instance.GameConfigInfo.shareBgVersion+1); //更新背景标识
                    UIItem.InitList(this.content);
                    this.pageView.removeAllPages();
                    //读取展示
                    for(let i = 0;i<this.picDataList.length;++i)
                    {
                        let picData = this.picDataList[i];
                        let texture = new cc.Texture2D();
                        
                        texture.initWithData(picData,32,this.width,this.height);
                        //创建主相机列表展示
                        let sprite = new cc.SpriteFrame(texture);
                        let node = cc.instantiate(this.item);
                        node.setContentSize(this.pageSize);
                        console.log("node size : " + node.getContentSize());
                        node.name = "share_"+i;
                        this.pageView.addPage(node);
                        let Image = node.getComponent(cc.Sprite);
                        Image.spriteFrame = sprite;
                        node.active = true;
                    }
                    let size = this.content.getContentSize();
                    this.content.setContentSize(cc.size(200 + this.shareBgList.length* 534,size.height));
                    this.loading.active = false;
                }
                this.isNeedShot = true;
                if(this.isCanShot)
                {
                    console.error("调用截图时 图片已经加载完毕,可以截图");
                    this.ShotFunc();
                }
                else
                {
                    console.error("调用截图时 图片未加载完毕,需要等待");
                }
            }
        }
    
        public ShotFunc()
        {
            this.scheduleOnce(()=>
            {
                console.log("开始截图");
                let picData = this.InitImage();
                this.picDataList.push(picData);
                this.SaveFile(picData,this.shotIdx); //保存
                this.shotIdx++;
                if(this.shotIdx<this.shareBgList.length+1)
                {
                    console.log("换背景继续截图 : " + this.shotIdx);
                    cc.loader.loadRes("UI/Static/texture/share_"+this.shotIdx,cc.SpriteFrame,(err,res)=>
                    {
                        if(err)
                        {
                            console.error("load share bg err : " + err);
                        }
                        else
                        {
                            this.bg_shot.spriteFrame = res;
                            this.ShotFunc();
                        }
                    })
                }
                else
                {
                    if(this.shotComplete)
                    {
                        this.shotComplete();
                    }
                }
            },0); //等一帧再次截图
        }
    
        private _width = 0;
        private _height = 0;
    
        public InitImage() : Uint8Array
        {
            let data = this.texture.readPixels();
            this._width =  this.texture.width;
            this._height = this.texture.height;
            let picData = this.filpYImage(data,this._width,this._height);
            return picData;
        }
    
        public filpYImage (data:Uint8Array, width:number, height:number) :Uint8Array
        {
            let picData = new Uint8Array(width * height * 4);
            let rowBytes = width * 4;
            for (let row = 0; row < height; row++) {
                let srow = height - 1 - row;
                let start = srow * width * 4;
                let reStart = row * width * 4;
                // save the piexls data
                for (let i = 0; i < rowBytes; i++) {
                    picData[reStart + i] = data[start + i];
                }
            }
            return picData;
        }
    
        public SaveFile(picData:Uint8Array,idx:number)
        {
            if(CC_JSB)
            {
                let filePath = this.prefixPath + 'share_'+idx+'.png';
                let success = jsb.saveImageData(picData, this._width, this._height, filePath)
                if (success)
                {
                    cc.log("save image data success, file: " + filePath);
                }
                else 
                {
                    cc.error("save image data failed!");
                }
            }
        }
        
    }
    

    相关文章

      网友评论

          本文标题:Creator 原生无感截图

          本文链接:https://www.haomeiwen.com/subject/jqfsxktx.html