Cocos Creator 2D摄像机 [Lv.2] 截图

摘要

本文在Cocos Creator 2D摄像机 [Lv.1] 小视图所完成的工程的基础上进行修改,并增加截图功能。

环境

  • Cocos Creator 2.4.4

资源

准备工作

  1. Cocos Creator 2D摄像机 [Lv.1] 小视图 所完成的工程。

正式开始

对工程做一些修改

资源管理器
拷贝MiniMapDemo场景,重命名为CaptureScreenDemo
拷贝MiniMapController.js脚本,重命名为CaptureScreenController.js
在这里插入图片描述
层级管理器
在这里插入图片描述

  1. CaptureScreenController.js脚本,挂载在CaptureScreenController节点上。

之后节点相关的设置请参考工程中的设置,文中不再赘述。

如何互动

截图功能需要通过RenderTexture实现。
将摄像机照到的图像,渲染到RenderTexture上,然后从RenderTexture上读取出图像数据。
我们将通过右键点击,来触发截图功能。

通过RenderTexture + SpriteFrame来实现小视图

创建一个sprite,用来显示小视图,默认的SpriteFrame删除掉。
在这里插入图片描述 在这里插入图片描述
CaptureScreenController.js中实现功能。

...
let _texture = null		// RenderTexture

cc.Class({
    ...
    properties: {
        ...
        smallView: cc.Sprite, 	// 小视图。
    },

    onLoad () {
        ...
        _texture = new cc.RenderTexture()
        _texture.initWithSize(_canvasWidth, _canvasHeight, cc.gfx.RB_FMT_S8)
        this.camera.targetTexture = _texture	// 将摄像机的渲染重定向到 RenderTexture 上。

		// spriteFrame 的 texture 指定为 RenderTexture ,
		// 再把 spriteFrame 添加到 smallView 上,
		// 这样摄像机照到的图像就能通过 smallView 显示出来了。
        let spriteFrame = new cc.SpriteFrame()
        spriteFrame.setTexture(_texture)
        this.smallView.spriteFrame = spriteFrame
    }, 
	...
});

将节点挂载到脚本对应变量上。
在这里插入图片描述
运行起来,看看效果,
在这里插入图片描述
小视图怎么这么小,而且还倒过来了。
小视图很小是由于camera.rect发挥的作用。原先是以整个屏幕作为根本,设置的rect。现在将targetTexture定向到了smallView上,由于smallView已经设置了需要的大小,所以重置camera.rect,让其按照默认的位置和尺寸显示就可以了。
在这里插入图片描述 在这里插入图片描述
显示倒过来的问题,我们可以通过设置smallViewscaleY = -1来解决。
同时还有一点,我们要将smallView的分组设置为brush。反正不能放在default分组里,否则小视图又会被摄像机渲染出来。
在这里插入图片描述 在这里插入图片描述 在这里插入图片描述
运行起来,看看效果,
在这里插入图片描述
已经能正常显示了。但是又发现个小问题,小视图边框(黄线)的显示不太正常。
这是由于原先通过camera.rect实现时,小视图边框是通过camera.rect计算出来的。现在通过smallView来显示,我们就需要通过其Node的属性来计算小视图的边框。
CaptureScreenController.js中修改calCameraDisplayRect函数的实现。

calCameraDisplayRect: function () {
        let cameraPos = this.smallView.node.getPosition()	// 根据 smallView 的位置来计算。
        let cameraAnchor = cc.Vec2(this.smallView.node.anchorX, this.smallView.node.anchorX)
        let cameraSize = {width: this.smallView.node.width, height: this.smallView.node.height}

		// 绘制的矩形以左下角为原点。
        return new cc.Rect(cameraPos.x - cameraAnchor.x * cameraSize.width, 
                        cameraPos.y - cameraAnchor.y * cameraSize.height, 
                        cameraSize.width, 
                        cameraSize.height)
    }, 

运行起来,看看效果,
在这里插入图片描述
一切都正常了。

截图

CaptureScreenController.js中实现功能。

...
cc.Class({
    ...
    onLoad () {
        ...
        // 鼠标释放事件,通过右键点击鼠标截图。
        this.node.on(cc.Node.EventType.MOUSE_UP, this.onMouseUp, this)
		...
    }, 
    ...
    onMouseUp (event) {
        let mouseType = event.getButton()

        if (mouseType === cc.Event.EventMouse.BUTTON_RIGHT) {	// 鼠标右键释放。
            this.captureScreen()	// 截图。
        }
    }, 
    ...
    captureScreen () {
        this.camera.render()	// 手动渲染摄像机。

        let picData = _texture.readPixels()		// 从 RenderTexture 中读取图像数据。
        // 图像默认 Y 轴是颠倒的,需要翻转一下 Y 轴。
        picData = this.filpYImage(picData, _texture.width, _texture.height)
        this.saveFile(picData)	// 存储图像。
    }, 

    saveFile (picData) {
        if (CC_JSB) {
	        // 存储到可写路径下。
            let filePath = jsb.fileUtils.getWritablePath() + 'render_to_sprite_image.png'

			// 存储图像。
            let success = jsb.saveImageData(picData, _texture.width, _texture.height, filePath)
            if (success) {
                cc.log("save image data success, file: " + filePath)
            }
            else {
                cc.error("save image data failed!")
            }
        }
    }, 

    // This is a temporary solution
    filpYImage (data, width, height) {
        // create the data array
        let picData = new Uint8Array(width * height * 4)	// 每个像素 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
    }, 
})

运行起来,看看效果,
在这里插入图片描述
成功生成了截图文件。

划重点

  • 通过RenderTexture + SpriteFrame来实现小视图。
  • Camera.render() -> RenderTexture.readPixels() -> filpYImage() -> jsb.fileUtils.getWritablePath() -> jsb.saveImageData()
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值