更舒适的阅读体验,请关注公众号:
实在是懒得整理格式了
截图是游戏中一个非常常见的需求,通过摄像机和 RenderTexture 我们可以快速实现一个截图功能
对于截图功能,在 example-cases 中有完整的测试用例,代码示例可参考 07_capture_texture
对于摄像机的介绍,请阅读官方文档:
https://docs.cocos.com/creator/manual/zh/render/camera.html
官方的测试用例中只提供了对屏幕的截图功能,但很多时候,我们只想对某个 node 进行截图
下面提供了两种方法,都可以实现该需求,两种实现方式虽然都是用 Camera 和 RenderTexture ,但还是有些区别,具体的优缺点在哪里,同学们可以自己思考
实现原理在代码中有详细的注释,这里就不再赘述
// 演示 //
// 实现 //
1 渲染屏幕,读取 node 区域的像素
captureNode(nodeCapture: cc.Node) {
let nodeCamera = new cc.Node();
nodeCamera.parent = cc.find("Canvas");
let camera = nodeCamera.addComponent(cc.Camera);
let width = nodeCapture.width;
let height = nodeCapture.height;
let texture = new cc.RenderTexture();
texture.initWithSize(cc.visibleRect.width, cc.visibleRect.height, cc.gfx.RB_FMT_S8);
camera.targetTexture = texture;
let canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
let ctx = canvas.getContext('2d');
camera.render();
// 指定需要读取的区域的像素
let size = nodeCapture.getContentSize();
let pixels = new Uint8Array(size.width * size.height * 4);
let x = texture.width / 2 - nodeCapture.width / 2;
let y = texture.height / 2 - nodeCapture.height / 2;
let w = nodeCapture.width;
let h = nodeCapture.height;
let data = texture.readPixels(pixels, x, y, w, h);
// 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);
}
let dataURL = canvas.toDataURL("image/png");
let img = document.createElement("img");
img.src = dataURL;
let texture2D = new cc.Texture2D();
texture2D.initWithElement(img);
let spriteFrame = new cc.SpriteFrame();
spriteFrame.setTexture(texture2D);
let node = new cc.Node();
let sprite = node.addComponent(cc.Sprite);
sprite.spriteFrame = spriteFrame;
return node;
}
// 插个小广告 //
江湖救急,因为业务需求,公司急招 creator 的小伙伴们,不出意外的话,咱们就一起写代码了~
为了让 渡鸦 少掉几根鸦毛,或者早点下班多点空余时间分享笔记,恳请大佬们将简历发我个人邮箱:valiancer@126.com 或者 投递到下方二维码
工作职责:
1.、负责作业帮核心业务游戏化内容开发;
2、 负责游戏内容的性能优化及体验优化;
3、使用Cocos Creator 开发教育游戏与互动课件
4、负责具体的系统功能与游戏课件的开发;
5、持续优化产品性能、功能逻辑和用户体验。
薪资范围好像是20K~50K(柠檬树上柠檬果,柠檬树下你和我[image])
2渲染 node
renderNode(nodeCapture: cc.Node) {
let nodeCamera = new cc.Node();
nodeCamera.parent = cc.find("Canvas");
let camera = nodeCamera.addComponent(cc.Camera);
let position = nodeCapture.getPosition();
let width = nodeCapture.width;
let height = nodeCapture.height;
// 当 alignWithScreen 为 true 的时候,摄像机会自动将视窗大小调整为整个屏幕的大小。如果想要完全自由地控制摄像机,则需要将 alignWithScreen 设置为 false。(v2.2.1 新增)
camera.alignWithScreen = false;
// 设置摄像机的投影模式是正交(true)还是透视(false)模式
camera.ortho = true;
// 摄像机在正交投影模式下的视窗大小。该属性在 alignWithScreen 设置为 false 时生效。
camera.orthoSize = height / 2;
let texture = new cc.RenderTexture();
// 如果截图内容中不包含 Mask 组件,可以不用传递第三个参数
texture.initWithSize(width, height, cc.gfx.RB_FMT_S8);
// 如果设置了 targetTexture,那么摄像机渲染的内容不会输出到屏幕上,而是会渲染到 targetTexture 上。
camera.targetTexture = texture;
// 创建画布
let canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
let ctx = canvas.getContext('2d');
nodeCapture.setPosition(cc.Vec2.ZERO);
// 渲染一次摄像机,即更新一次内容到 RenderTexture 中
camera.render(nodeCapture);
nodeCapture.setPosition(position);
// 从 render texture 读取像素数据,数据类型为 RGBA 格式的 Uint8Array 数组。
// 默认每次调用此函数会生成一个大小为 (长 x 高 x 4) 的 Uint8Array。
let data = texture.readPixels();
// write the render data
// PNG 中 1 像素 = 32 bit(RGBA),1 byte = 8 bit,所以 1 像素 = 4 byte
// 每行 width 像素,即 width * 4 字节
let rowBytes = width * 4;
for (let row = 0; row < height; row++) {
// RenderTexture 得到的纹理是上下翻转的
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);
}
let dataURL = canvas.toDataURL("image/png");
let img = document.createElement("img");
img.src = dataURL;
nodeCamera.destroy();
let texture2D = new cc.Texture2D();
texture2D.initWithElement(img);
let spriteFrame = new cc.SpriteFrame();
spriteFrame.setTexture(texture2D);
let node = new cc.Node();
let sprite = node.addComponent(cc.Sprite);
sprite.spriteFrame = spriteFrame;
return node;
}