cocos creator 小游戏区域截图功能实现
截图是游戏中非常常见的一个功能,在cocos中可以通过摄像机和 RenderTexture 可以快速实现一个截图功能,具体API可参考:https://docs.cocos.com/creator/manual/zh/render/camera.html?h=%E6%88%AA%E5%9B%BE,其中官方也提供了比较完整的例子。
实际上不用官网提供的全屏截图的例子,一般在网页中我们也能将页面截图保存,比如通过htmltocanvas,cocos开发的小游戏在网页中打开实际就是一个canvas,前端是可以通过将canvas保存为图片的,这里就不细说了。
我们还是来看下如何把屏幕中某一区域的内容生成图片并保存到本地。
1、创建RenderTexture
//新建一个 RenderTexture,并且设置 camera 的 targetTexture 为新建的 RenderTexture,这样 camera 的内容将会渲染到新建的 RenderTexture 中。
let texture = new cc.RenderTexture();
let gl = cc.game._renderContext;
//如果截图中不含mask组件可以不加第三个参数,不过建议加上
texture.initWithSize(this.node.width, this.node.height, gl.STENCIL_INDEX8);//这里的宽高直接决定了截图的宽高,如果是全屏截图就是cc.visibleRect.width, cc.visibleRect.height,该处可以设置为截图目标区域的宽高
this.camera = this.node.addComponent(cc.Camera); this.camera.targetTexture = texture; this.texture = texture;
2、绘制canvas
createSprite() {
let width = this.texture.width;
let height = this.texture.height;
//截图的本质是创建一个canvas,然后通过canvas生成图片材质
if (!this._canvas) {
this._canvas = document.createElement('canvas');
this._canvas.width = width;
this._canvas.height = height;
} else {
this.clearCanvas();
}
let ctx = this._canvas.getContext('2d');
this.camera.render();//相机绘制,将屏幕上的内容更新到renderTexture中
let data = this.texture.readPixels();//读取renderTexture中的数据
let rowBytes = width * 4;
for (let row = 0; row < height; row++) {
let srow = height - 1 - row;
let imageData = ctx.createImageData(width, 1);
let start = srow * width * 4;
for (let i = 0; i < rowBytes; i++) {
imageData.data[i] = data[start + i];
}
ctx.putImageData(imageData, 0, row);
}
return this._canvas;
},
上述代码中用到了canvas 的createImageData() 和putImageData()方法,createImageData() 方法创建新的空白 ImageData 对象,putImageData() 方法将图像数据(从指定的 ImageData 对象)放回画布上。
3、获取图片
initImage(img) {
// return the type and dataUrl
var dataURL = this._canvas.toDataURL("image/png");
var img = document.createElement("img");
img.src = dataURL;
return img;
},
生成canvas就可以通过canvas.toDataURL()方法将canvas转换为图片
4、生成截图效果,将上一步生成的图片当做材质挂载到新建的node
showSprite(img) {
let y = this.getTargetArea().y;
let x = this.getTargetArea().x;
let rect = new cc.Rect(x, y, 770, 800)
let texture = new cc.Texture2D();
texture.initWithElement(img);
let spriteFrame = new cc.SpriteFrame();
spriteFrame.setTexture(texture);
spriteFrame.setRect(rect)
let node = new cc.Node();
let sprite = node.addComponent(cc.Sprite);
sprite.spriteFrame = spriteFrame;
node.zIndex = cc.macro.MAX_ZINDEX;
node.parent = cc.director.getScene();
// set position
let width = cc.winSize.width;
let height = cc.winSize.height;
node.x = width / 2;
node.y = height / 2;
node.on(cc.Node.EventType.TOUCH_START, () => {
node.parent = null;
node.destroy();
});
this.captureAction(node, width, height);
},
5、截图动画(类似手机截图,截图后有个缩略图动画)
captureAction(capture, width, height) {
let scaleAction = cc.scaleTo(1, 0.3);
let targetPos = cc.v2(width - width / 6, height / 4);
let moveAction = cc.moveTo(1, targetPos);
let spawn = cc.spawn(scaleAction, moveAction);
let finished = cc.callFunc(() => {
capture.destroy();
})
let action = cc.sequence(spawn, finished);
capture.runAction(action);
},
6、下载图片到本地,动态生成a标签,模拟点击后移除
downloadImg() {
this.createSprite();
var img = this.initImage();
this.showSprite(img)
var dataURL = this._canvas.toDataURL("image/png")
var a = document.createElement("a")
a.href = dataURL;
a.download = "image";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
},
完整代码如下:
cc.Class({
extends: cc.Component,
properties: {
_canvas: null,
targetNode: cc.Node
},
onLoad() {
this.init();
},
init() {
let texture = new cc.RenderTexture();
let gl = cc.game._renderContext;
texture.initWithSize(this.node.width, this.node.height, gl.STENCIL_INDEX8);
this.camera = this.node.addComponent(cc.Camera);
this.camera.targetTexture = texture;
this.texture = texture;
},
// create the img element
initImage(img) {
// return the type and dataUrl
var dataURL = this._canvas.toDataURL("image/png");
var img = document.createElement("img");
img.src = dataURL;
return img;
},
// create the canvas and context, filpY the image Data
createSprite() {
let width = this.texture.width;
let height = this.texture.height;
if (!this._canvas) {
this._canvas = document.createElement('canvas');
this._canvas.width = width;
this._canvas.height = height;
} else {
this.clearCanvas();
}
let ctx = this._canvas.getContext('2d');
this.camera.render();
let data = this.texture.readPixels();
// write the render data
let rowBytes = width * 4;
for (let row = 0; row < height; row++) {
let srow = height - 1 - row;
let imageData = ctx.createImageData(width, 1);
let start = srow * width * 4;
for (let i = 0; i < rowBytes; i++) {
imageData.data[i] = data[start + i];
}
ctx.putImageData(imageData, 0, row);
}
return this._canvas;
},
getTargetArea() {
let targetPos = this.targetNode.convertToWorldSpaceAR(cc.v2(0, 0))
let y = cc.winSize.height - targetPos.y - this.targetNode.height / 2;
let x = cc.winSize.width - targetPos.x - this.targetNode.width / 2;
return {
x,
y
}
},
downloadImg() {
this.createSprite();
var img = this.initImage();
this.showSprite(img)
var dataURL = this._canvas.toDataURL("image/png")
var a = document.createElement("a")
a.href = dataURL;
a.download = "image";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
},
// show on the canvas
showSprite(img) {
let y = this.getTargetArea().y;
let x = this.getTargetArea().x;
let rect = new cc.Rect(x, y, 770, 800)
let texture = new cc.Texture2D();
texture.initWithElement(img);
let spriteFrame = new cc.SpriteFrame();
spriteFrame.setTexture(texture);
spriteFrame.setRect(rect)
let node = new cc.Node();
let sprite = node.addComponent(cc.Sprite);
sprite.spriteFrame = spriteFrame;
node.zIndex = cc.macro.MAX_ZINDEX;
node.parent = cc.director.getScene();
// set position
let width = cc.winSize.width;
let height = cc.winSize.height;
node.x = width / 2;
node.y = height / 2;
node.on(cc.Node.EventType.TOUCH_START, () => {
node.parent = null;
node.destroy();
});
this.captureAction(node, width, height);
},
// sprite action
captureAction(capture, width, height) {
let scaleAction = cc.scaleTo(1, 0.3);
let targetPos = cc.v2(width - width / 6, height / 4);
let moveAction = cc.moveTo(1, targetPos);
let spawn = cc.spawn(scaleAction, moveAction);
let finished = cc.callFunc(() => {
capture.destroy();
})
let action = cc.sequence(spawn, finished);
capture.runAction(action);
},
clearCanvas() {
let ctx = this._canvas.getContext('2d');
ctx.clearRect(0, 0, this._canvas.width, this._canvas.height);
}
});
cocos creator 小游戏区域截图功能实现的更多相关文章
- Cocos开发小游戏如何实现微信排行榜
当游戏开发进入尾声,要引入微信数据的时候,需要了解和微信相关的接口了. 关系数据链 开放数据域 相关接口如下: wx.getFriendCloudStorage() 获取当前用户也玩该小游戏的好友的用 ...
- Cocos Creator采坑:原来使用Cocos Creator做游戏,是有服务器!!!
我傻傻的以为,我们没有服务器. 今天上传测试代码,测试才发现! 原来我们真的是有服务器的!只不过是一个本地的服务器~!需要服务器打开,然后,扫码才能访问!! 为了证明我们是有服务器的,我做了一下测试 ...
- Cocos Creator经典游戏制作之:信使(The Messenger)
版权声明: 本文原创发布于博客园"优梦创客"的博客空间(网址:http://www.cnblogs.com/raymondking123/)以及微信公众号"优梦创客&qu ...
- cocos 微信小游戏切后台卡住
1.cocos 安装目录下搜索以下代码并注掉opts["preserveDrawingBuffer"] = true;”2.CocosCreator\resources\engin ...
- 新编辑器Cocos Creator发布:对不起我来晚了!
1月19日,由Cocos创始人王哲亲手撰写的一篇Cocos Creator新品发布稿件在朋友圈被行业人士疯狂转载,短短数小时阅读量突破五位数.Cocos Creator被誉为“注定将揭开Cocos开发 ...
- cocos creator主程入门教程(一)—— 初识creator
五邑隐侠,本名关健昌,10年游戏生涯,现隐居五邑.本系列文章以TypeScript为介绍语言. 我们在cocos creator新建一个Hello TypeScript项目,都会有一个assets/S ...
- cocos creator 入门理解点
简单解释, [来源:官方文档] Cocos是触控科技推出的游戏开发一站式解决方案,包含了从新建立项.游戏制作.到打包上线的全套流程.开发者可以通过cocos快速生成代码.编辑资源和动画,最终输出适合于 ...
- 一个js小游戏----总结
花了大概一天左右的功夫实现了一个js小游戏的基本功能,类似于“雷电”那样的小游戏,实现了随即怪物发生器,碰撞检测,运动等等都实现了,下一个功能是子弹轨迹,还有其他一些扩展功能,没有用库,也没有用web ...
- h5小球走迷宫小游戏源码
无意中找到的一个挺有意思的小游戏,关键是用h5写的,下面就分享给大家源码 还是先来看小游戏的截图 可以用键盘的三个键去控制它,然后通关 下面是源代码 <!doctype html> < ...
随机推荐
- 《Windows via C/C++》学习笔记 —— 设备I/O之“同步的设备I/O”(系列文章)
前面曾经讲过,设备I/O的方式有两种:同步和异步.本篇介绍一下同步设备I/O.主要涉及到两个函数:ReadFile和WriteFile. 不要被这两个函数的名称迷惑,不仅可以将这两个作用于文件,也可以 ...
- Understand the Qt containers(有对应表)
Container classes are one of the cornerstones of object-oriented programming, invaluable tools that ...
- [android自动化构建]之centos安装gradle
这是android自动化构建系列之环境配置 这里只记录部分gradle相关的配置 下载并解压 下载地址参考这里:https://services.gradle.org/distributions/,未 ...
- 有效地查找SAP增强点
找SAP增强点一直都是SAP开发的重点难点,增强开发的代码一般不会很多,但是需要花费比较多的时间在查找增强点上 网上也流传了很多查找SAP增强的方法: 1.利用TCODE寻找增强 2.利用系统函数寻找 ...
- 用node.js(socket.io)实现数据实时推送
在做商品拍卖的时候,要求在商品的拍卖页面需要实时的更新当前商品的最高价格.实现的方式有很多,比如: 1.setInterval每隔n秒去异步拉取数据(缺点:更新不够实时) 2. AJAX轮询方式方式推 ...
- ABP开发框架前后端开发系列---(4)Web API调用类的封装和使用
在前面随笔介绍ABP应用框架的项目组织情况,以及项目中领域层各个类代码组织,以及简化了ABP框架的各个层的内容,使得我们项目结构更加清晰.上篇随笔已经介绍了字典模块中应用服务层接口的实现情况,并且通过 ...
- React躬行记(4)——生命周期
组件的生命周期(Life Cycle)包含三个阶段:挂载(Mounting).更新(Updating)和卸载(Unmounting),在每个阶段都会有相应的回调方法(也叫钩子)可供选择,从而能更好的控 ...
- 【JAVA NIO】java NIO
本文是博主深入学习Netty前的一些铺垫,之前只是使用Netty,用的很粗暴,导包,上网找个DEMO就直接用,对Netty中的组件了解并不深入. 于是再此总结下基础,并对一些核心组件作如下记录: 1. ...
- Asp.net HttpClient Proxy(Fiddler)
<system.net> <defaultProxy> <proxy bypassonlocal="False" usesystemdefault=& ...
- Python中的函数及函数参数的使用
函数:一个工具,随调随用 降级代码冗余 增加代码的复用性,提高开发效率,为了不成为cv战士 提高程序扩展性 函数有两个阶段:定义阶段,调用阶段. 定义时:只检查函数体内代码语法,不执行函数体内代码. ...