截圖是游戲中非常常見的一個功能,在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);
}
});
網絡釋義
RenderTexture: 渲染紋理
