Mandala/assets/Script/Game.ts
2024-10-30 15:19:32 +08:00

289 lines
10 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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) {
}
}