289 lines
10 KiB
TypeScript
289 lines
10 KiB
TypeScript
// Learn TypeScript:
|
||
// - https://docs.cocos.com/creator/manual/en/scripting/typescript.html
|
||
// Learn Attribute:
|
||
// - https://docs.cocos.com/creator/manual/en/scripting/reference/attributes.html
|
||
// Learn life-cycle callbacks:
|
||
// - https://docs.cocos.com/creator/manual/en/scripting/life-cycle-callbacks.html
|
||
|
||
import DrawingBoard from "./DrawingBoard";
|
||
|
||
const { ccclass, property } = cc._decorator;
|
||
|
||
enum GameState {
|
||
drawing = 1,
|
||
erasing = 2,
|
||
}
|
||
|
||
@ccclass
|
||
export default class Game extends cc.Component {
|
||
@property(cc.Node)
|
||
drawNode: cc.Node = null;
|
||
|
||
@property(cc.Camera)
|
||
captureCamera: cc.Camera = null;
|
||
|
||
@property(cc.Camera)
|
||
mainCamera: cc.Camera = null;
|
||
|
||
private targetCamera: cc.Camera;
|
||
private db: DrawingBoard = null;
|
||
private gameState: GameState = GameState.drawing;
|
||
private texture: cc.RenderTexture = null;
|
||
private prePos: cc.Vec2 = cc.Vec2.ZERO;
|
||
private startPos: cc.Vec2 = cc.Vec2.ZERO;
|
||
private lastColor: cc.Color = cc.Color.BLUE;
|
||
private errColor: cc.Color = cc.Color.RED;
|
||
private lastLineWidth: number = 1;
|
||
private history: any[] = [];
|
||
private touchId = -1;
|
||
private touchScale = false;
|
||
|
||
|
||
start() {
|
||
this.initDb();
|
||
this.initTexture();
|
||
this.initRead();
|
||
|
||
setTimeout(() => {
|
||
this.drawNode.on("touchstart", this.onTouchStart, this);
|
||
this.drawNode.on("touchmove", this.onTouchMove, this);
|
||
this.drawNode.on("touchend", this.onTouchEnd, this);
|
||
this.drawNode.on("touchcancel", this.onTouchEnd, this);
|
||
}, 2000);
|
||
}
|
||
|
||
initDb() {
|
||
//创建一个画板(需传入画板尺寸,将自动初始化)
|
||
this.db = new DrawingBoard(this.drawNode.width, this.drawNode.height);
|
||
//设置画板的绘图颜色(每次绘制前都可以重新设置)
|
||
this.lastLineWidth = 15;
|
||
this.db.setLineWidth(this.lastLineWidth);
|
||
// this.db.setColor(this.lastColor.r, this.lastColor.g, this.lastColor.b, this.lastColor.a);
|
||
//线条端点以圆角结尾
|
||
this.db.setLineCircleEnd(true);
|
||
}
|
||
|
||
initTexture() {
|
||
this.texture = new cc.RenderTexture();
|
||
this.texture.initWithSize(this.drawNode.width, this.drawNode.height, cc.RenderTexture.DepthStencilFormat.RB_FMT_S8);
|
||
let spf: cc.SpriteFrame = new cc.SpriteFrame(this.texture);
|
||
this.drawNode.getComponent(cc.Sprite).spriteFrame = spf;
|
||
}
|
||
|
||
initRead(){
|
||
this.targetCamera = this.node.getChildByName("tagCamera").getComponent(cc.Camera);
|
||
var rander = new cc.RenderTexture();
|
||
rander.initWithSize(this.node.width, this.node.height, cc.RenderTexture.DepthStencilFormat.RB_FMT_S8);
|
||
this.targetCamera.targetTexture = rander;
|
||
this.targetCamera.render();
|
||
console.log("完成");
|
||
}
|
||
|
||
onTouchStart(e: cc.Event.EventTouch) {
|
||
//将触摸位置作为线条的起点
|
||
//画板中使用的坐标系,与图片坐标系一样,原点在左上角,X轴向右为正,Y轴向下为正
|
||
//所以Y轴坐标应反过来, 这里用getLocationInView而不是getLocation
|
||
|
||
this.touchId = e.getID();
|
||
if(this.touchId == 1){
|
||
this.touchScale = true;
|
||
return;
|
||
}
|
||
|
||
let pos = e.getLocation();
|
||
this.prePos = this.convertToDrawNodePos(pos);
|
||
this.startPos = this.convertToDrawNodePos(pos);
|
||
this.db.moveTo(this.prePos.x, this.prePos.y);
|
||
|
||
}
|
||
|
||
onTouchMove(e: cc.Event.EventTouch) {
|
||
let touches = e.getTouches();
|
||
var touch1 = touches[0]
|
||
var delta1 = touch1.getDelta();
|
||
let pos = e.getLocation();
|
||
|
||
let pos1 = this.convertToDrawNodePos(touch1.getLocation());
|
||
let dst = this.startPos.sub(pos1).mag()
|
||
// this.label.string = touches.length + "";
|
||
if(touches.length == 1 && this.touchId < 1 && !this.touchScale && dst > 7){
|
||
// alert("不该进来");
|
||
this.prePos = this.convertToDrawNodePos(pos);
|
||
var jg = this.pd(e);
|
||
this.changeColor(jg)
|
||
if (this.gameState == GameState.drawing) {
|
||
//从上一次绘制线条后的终点开始向鼠标当前位置绘制线条
|
||
this.db.lineTo(this.prePos.x, this.prePos.y);
|
||
} else if (this.gameState == GameState.erasing) {
|
||
// 橡皮擦
|
||
this.db.circle(this.prePos.x, this.prePos.y, 10);
|
||
}
|
||
//每次画板中的数据有变化后,及时将数据应用到贴图上,在屏幕上显示出来
|
||
this.drawToImg();
|
||
}
|
||
else if(touches.length == 2){
|
||
var touch1 = touches[0], touch2 = touches[1];
|
||
var delta1 = touch1.getDelta(), delta2 = touch2.getDelta();
|
||
var touchPoint1 = this.node.parent.convertToNodeSpaceAR(touch1.getLocation());
|
||
var touchPoint2 = this.node.parent.convertToNodeSpaceAR(touch2.getLocation());
|
||
|
||
var distance = touchPoint1.sub(touchPoint2);
|
||
var delta = delta1.sub(delta2);
|
||
var scale = 1;
|
||
|
||
if(Math.abs(distance.x) > Math.abs(distance.y)){
|
||
scale = (distance.x + delta.x) / distance.x * this.node.scale;
|
||
}
|
||
else{
|
||
scale = (distance.y + delta.y) / distance.y * this.node.scale;
|
||
}
|
||
if(scale > 2 ) scale = 2;
|
||
this.node.scale = scale <= 0.1 ? 0.1: scale;
|
||
}
|
||
}
|
||
|
||
onTouchEnd(e: cc.Event.EventTouch) {
|
||
this.touchId = e.getID();
|
||
if(this.touchId == 1) this.touchScale = false;
|
||
this.addHistory();
|
||
}
|
||
|
||
pd(event){
|
||
let cha = 2;
|
||
var pos = event.getLocation();
|
||
var jg = false;
|
||
for(let i=-cha; i<cha;i++){
|
||
let postion = cc.v2();
|
||
postion.x = pos.x + i;
|
||
for(let j =-cha; j<cha; j++){
|
||
postion.y = pos.y + j;
|
||
// console.log("检测点:",postion.x,postion.y);
|
||
let img = this.getGraphisData(postion);
|
||
if((img[0] != 255 && img[1]!=255 && img[2]!=255)){
|
||
jg = true;
|
||
j = 10000; i = 10000;
|
||
}
|
||
}
|
||
|
||
}
|
||
//
|
||
return jg;
|
||
|
||
}
|
||
|
||
convertToDrawNodePos(worldPos: cc.Vec2) {
|
||
let pos = this.drawNode.convertToNodeSpaceAR(worldPos);
|
||
pos.x += this.drawNode.width * this.drawNode.anchorX;
|
||
pos.y += this.drawNode.height * this.drawNode.anchorY;
|
||
pos.y = this.drawNode.height - pos.y;
|
||
return pos;
|
||
}
|
||
|
||
addHistory() {
|
||
let copy = this.db.copyData();
|
||
let ucopy = new Uint8Array(copy);
|
||
this.history.push({ data: ucopy });
|
||
// cc.log('历史步骤: ', this.history.length);
|
||
}
|
||
|
||
drawToImg() {
|
||
//获取画板中绘制的图案数据
|
||
let data: Uint8Array = this.db.getData();
|
||
//将数据传递给贴图对象
|
||
this.texture.initWithData(data, cc.Texture2D.PixelFormat.RGBA8888, this.db.width, this.db.height);
|
||
}
|
||
|
||
changeColor(red){
|
||
if(!red) this.db.setColor(this.errColor.r, this.errColor.g, this.errColor.b, this.errColor.a)
|
||
else this.db.setColor(this.lastColor.r, this.lastColor.g, this.lastColor.b, this.lastColor.a);
|
||
}
|
||
|
||
getGraphisData(point){
|
||
let Uint8 = new Uint8Array(4);
|
||
Uint8 = this.targetCamera.targetTexture.readPixels(Uint8,point.x,point.y,1,1);
|
||
|
||
return Uint8;
|
||
}
|
||
|
||
|
||
onBtnDraw() {
|
||
this.db.setLineWidth(this.lastLineWidth);
|
||
this.db.setColor(this.lastColor.r, this.lastColor.g, this.lastColor.b, this.lastColor.a);
|
||
this.gameState = GameState.drawing;
|
||
}
|
||
|
||
onBtnErase() {
|
||
this.db.setLineWidth(this.lastLineWidth * 3);
|
||
// 橡皮擦的颜色不能是(0,0,0,0),因为这样会和DrawingBoard里的默认颜色相同导致绘制跳过
|
||
this.db.setColor(255, 255, 255, 0);
|
||
this.gameState = GameState.erasing;
|
||
|
||
}
|
||
|
||
onBtnClear() {
|
||
this.db.reset();
|
||
this.drawToImg();
|
||
this.history.splice(0, this.history.length);
|
||
}
|
||
|
||
onBtnRevoke() {
|
||
this.history.pop();
|
||
if (this.history.length) {
|
||
let data: Uint8Array = this.history[this.history.length - 1].data;
|
||
this.db.setData(data.buffer);
|
||
this.texture.initWithData(this.db.getData(), cc.Texture2D.PixelFormat.RGBA8888, this.db.width, this.db.height);
|
||
} else {
|
||
this.onBtnClear();
|
||
}
|
||
cc.log('历史记录剩余: ', this.history.length);
|
||
}
|
||
|
||
onBtnSave() {
|
||
if (cc.sys.isBrowser) {
|
||
let width = this.drawNode.width;
|
||
let height = this.drawNode.height;
|
||
|
||
this.captureCamera.enabled = true;
|
||
let texture = new cc.RenderTexture();
|
||
texture.initWithSize(width, height, cc.RenderTexture.DepthStencilFormat.RB_FMT_S8);
|
||
this.captureCamera.targetTexture = texture;
|
||
|
||
let canvas: HTMLCanvasElement = document.createElement('canvas');
|
||
canvas.width = width;
|
||
canvas.height = height;
|
||
let ctx = canvas.getContext('2d');
|
||
this.captureCamera.render();
|
||
let data = 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);
|
||
}
|
||
//
|
||
let dataUrl = canvas.toDataURL('image/png');
|
||
// cc.log('iamge-base64:', dataUrl);
|
||
let saveLink: any = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
|
||
saveLink.href = dataUrl;
|
||
saveLink.download = String(Date.now()) + '.png';
|
||
let event = document.createEvent('MouseEvents');
|
||
event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
|
||
saveLink.dispatchEvent(event);
|
||
this.scheduleOnce(t => {
|
||
this.captureCamera.enabled = false;
|
||
}, 0.1);
|
||
} else {
|
||
cc.warn('暂时只支持web端保存图片');
|
||
}
|
||
}
|
||
|
||
update (dt) {
|
||
|
||
}
|
||
}
|