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

802 lines
28 KiB
TypeScript
Raw 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.

/**
* 画板:
* 可使用任意颜色绘制矩形,三角形,圆,直线,并统计每种颜色的像素个数
* 擦除图案时,设置画板的颜色为透明色再进行绘制即可
* @href https://forum.cocos.org/t/topic/89902
*/
export default class DrawingBoard {
private _witdh: number;
/**画板宽度 */
public get width(): number { return this._witdh; }
private _height: number;
/**画板高度 */
public get height(): number { return this._height; }
/**记录每个像素点的颜色值的数组颜色值用十六进制表示RGBA格式 */
private pointColor: number[][];
/**记录每个像素点能否绘制0表示不能绘制1表示能绘制 */
private maskPoint: number[][];
/**存储像素数据的内存块 */
private buffer: ArrayBuffer;
/**颜色分量一维数组,供渲染使用 */
private pixelColor: Uint8Array;
/**记录各种颜色的像素的数量 */
private colorCount: { [key: number]: number };
/**记录最近一次绘制像素的颜色(十六进制颜色值),调用绘制函数且未指定颜色值时,将使用该值 */
private curColor: number;
/**临时存储的颜色值 */
private tempColor: number;
private tempR: number;
private tempG: number;
private tempB: number;
private tempA: number;
/**
* 可对每个像素点绘制的画板画板使用的坐标系原点为左下角X轴向右为正Y轴向上为正
* @param width 画板宽度
* @param height 画板高度
* @param data 指定画板初始内容,参数为记录颜色分量的一维数组,不传入参数时,画板中全部像素为透明
*/
public constructor(width: number, height: number, data?: ArrayBuffer) {
this.init(width, height, data);
}
//#region 初始化
/**
* 对画板进行初始化,会清空已绘制的所有内容
* @param width 画板宽度
* @param height 画板高度
* @param data 指定画板初始内容,参数为记录颜色分量的一维数组,不传入参数时,画板内容为全部透明的矩形
*/
public init(width: number, height: number, data?: ArrayBuffer) {
this.tempColor = this.tempR = this.tempG = this.tempB = this.tempA = 0;
this.curColor = 0;
this._witdh = Math.round(width);
this._height = Math.round(height);
this.initPointColor();
this.initMaskPoint();
this.initPixelColor();
this.initLineData();
if (!!data) {
this.setData(data);
}
}
private initPointColor() {
if (!this.pointColor) {
this.pointColor = [];
}
for (let x = 0; x < this.width; ++x) {
if (!this.pointColor[x]) {
this.pointColor[x] = [];
}
for (let y = 0; y < this.height; ++y) {
this.pointColor[x][y] = 0;
}
}
this.colorCount = {};
this.colorCount[0] = this.width * this.height;
}
private initMaskPoint() {
if (!this.maskPoint) {
this.maskPoint = [];
}
for (let x = 0; x < this.width; ++x) {
if (!this.maskPoint[x]) {
this.maskPoint[x] = [];
}
for (let y = 0; y < this.height; ++y) {
this.maskPoint[x][y] = 1;
}
}
}
private initPixelColor() {
this.buffer = new ArrayBuffer(this.width * this.height * 4);
this.pixelColor = new Uint8Array(this.buffer);
this.pixelColor.fill(0);
}
//#endregion
//#region 重置内容
/**重置画板,画板的宽高不变,但会清空已绘制的所有内容,恢复至透明状态 */
public reset() {
this.resetPointColor();
this.resetMaskPoint();
this.resetPixelColor();
}
private resetPointColor() {
for (let x = this.width - 1; x >= 0; --x) {
for (let y = this.height - 1; y >= 0; --y) {
this.pointColor[x][y] = 0;
}
}
for (let key in this.colorCount) {
this.colorCount[key] = 0;
}
}
private resetMaskPoint() {
for (let x = this.width - 1; x >= 0; --x) {
for (let y = this.height - 1; y >= 0; --y) {
this.maskPoint[x][y] = 1;
}
}
}
private resetPixelColor() {
this.pixelColor.fill(0);
}
//#endregion
/**
* 传入图像的像素数据,直接设置画板的内容,图像尺寸必须与画板一致,若需要重新设置画板大小,请使用 init() 函数
* @param data 记录各像素颜色分量的一维数组
*/
public setData(data: ArrayBuffer) {
let pixelData = new Uint8Array(data);
if (pixelData.length != this.width * this.height * 4) {
console.warn("画板设置数据失败,数据长度与画板大小不一致。");
return;
}
this.setPixelColorByRGBA(pixelData);
this.setPointColorByRGBA(pixelData);
}
/**
* 记录各像素颜色分量
* @param data 颜色分量一维数组
*/
private setPixelColorByRGBA(data: Uint8Array) {
this.pixelColor.set(data);
}
/**
* 按像素点的坐标记录像素点的颜色值
* @param data 颜色分量一维数组
*/
private setPointColorByRGBA(data: Uint8Array) {
this.colorCount = {};
for (let y = 0; y < this.height; ++y) {
let i = y * this.height;
for (let x = 0; x < this.width; ++x) {
let color = this.convertToNumber(data[i++], data[i++], data[i++], data[i++]);
this.pointColor[x][y] = color;
if (!this.colorCount[color]) {
this.colorCount[color] = 1;
} else {
this.colorCount[color] += 1;
}
}
}
}
/**
* 设置不能绘制图案的像素区域
* @param data 像素坐标为索引0表示不能绘制1表示能绘制
*/
public setMask(data: number[][]) {
for (let x = this.width - 1; x >= 0; --x) {
if (!!data[x]) {
for (let y = this.height - 1; y >= 0; --y) {
if (undefined != data[x][y]) {
this.maskPoint[x][y] = data[x][y];
}
}
}
}
}
/**
* 设置画板为全部区域都不能绘制
*/
public setDisable() {
for (let x = this.width - 1; x >= 0; --x) {
for (let y = this.height - 1; y >= 0; --y) {
this.maskPoint[x][y] = 0;
}
}
}
/**
* 在现有可绘制区域的基础上添加可以绘制的像素点区域。
* 此方法不会禁用画板当前可绘制的像素点区域,只会添加新的可绘制区域
* @param data 像素坐标为索引0表示不能绘制1表示能绘制
*/
public addEnablePoints(data: number[][]) {
for (let x = this.width - 1; x >= 0; --x) {
if (!!data[x]) {
for (let y = this.height - 1; y >= 0; --y) {
if (!!data[x][y]) {
this.maskPoint[x][y] = data[x][y];
}
}
}
}
}
/**
* 获取画板中的数据
* @param data 用于接收数据的数组
* @returns {number[]} 返回存储各像素点颜色分量的一维数组
*/
public copyData(data?: number[]): number[] {
if (undefined === data) {
data = [];
}
for (let i = 0, count = this.pixelColor.length; i < count; ++i) {
data[i] = this.pixelColor[i];
}
return data;
}
/**
* 获取画板中记录每个像素的颜色分量的数据
* @returns 将直接返回画板内部的数组;注:若使用者需要对该数据进行修改,请使用 copyData 方法获取,以免影响画板的像素个数计数功能
*/
public getData(): Uint8Array {
return this.pixelColor;
}
/**获取画板内部使用的内存块,若仅需要获取像素数据,不进一步处理,使用 getData 即可 */
public getBuffer(): ArrayBuffer {
return this.buffer;
}
public getPointData(): number[][] {
return this.pointColor;
}
/**
* 获取指定颜色的像素的个数
* @param r 颜色的r分量
* @param g 颜色的g分量
* @param b 颜色的b分量
* @param a 颜色透明度默认为255
*/
public getColorCount(r: number, g: number, b: number, a: number = 255): number {
let c = this.convertToNumber(r, g, b, a);
return this.colorCount[c];
}
/**
* 设置画板绘制图案使使用的颜色
* @param r 包含RGBA分量的颜色对象或者颜色的r分量
* @param g 颜色的g分量
* @param b 颜色的b分量
* @param a 颜色透明度默认为255
*/
public setColor(r: number, g: number, b: number, a: number = 255) {
this.curColor = this.convertToNumber(r, g, b, a);
if (!this.colorCount[this.curColor]) {
this.colorCount[this.curColor] = 0;
}
this.tempColor = this.curColor;
this.tempR = r;
this.tempG = g;
this.tempB = b;
this.tempA = a;
}
/**清空所有已绘制的内容 */
public clear() {
this.reset();
}
//#region 绘制:直线
//直线
/**上一次绘制的直线的终点 */
private previousLineEndPos: Vec2;
private previousLineEndPosT: Vec2;
private previousLineEndPosB: Vec2;
/**上一次绘制的直线的端点样式 */
private previousLineCircleEnd: boolean;
/**上一次绘制的直线的宽度 */
private previousLineWidth: number;
private initLineData() {
this.previousLineEndPos = new Vec2();
this.previousLineEndPosT = new Vec2();
this.previousLineEndPosB = new Vec2();
this.previousLineCircleEnd = true;
this.previousLineWidth = 1;
}
/**
* 移动画笔到指定的位置,调用 lineTo 函数时将使用该点作为直线的起点
* @param x 坐标X
* @param y 坐标Y
*/
public moveTo(x: number, y: number) {
x = Math.round(x);
y = Math.round(y);
this.previousLineEndPos.set(x, y);
this.previousLineEndPosT.set(x, y);
this.previousLineEndPosB.set(x, y);
}
/**
* 设置线宽
*/
public setLineWidth(w: number) {
this.previousLineWidth = w;
}
/**
* 设置线段端点样式
* @param b 线段端点是否为圆形
*/
public setLineCircleEnd(b: boolean) {
this.previousLineCircleEnd = b;
}
/**
* 绘制直线,使用默认的颜色、线宽和线段端点样式
* @param x1 起点坐标X
* @param y1 起点坐标Y
* @param x2 终点坐标X
* @param y2 终点坐标Y
*/
public line(x1: number, y1: number, x2: number, y2: number) {
x1 = Math.round(x1);
x2 = Math.round(x2);
y1 = Math.round(y1);
y2 = Math.round(y2);
if (x1 == x2 && y1 == y2) return;
let width = this.previousLineWidth;
let circleEnd = this.previousLineCircleEnd;
this.previousLineEndPos.set(x2, y2);
let offsetX = 0;
let offsetY = 0;
let rateK = 1;
if (x1 == x2) {
offsetX = Math.round(width * 0.5);
} else if (y1 == y2) {
offsetY = Math.round(width * 0.5);
} else {
let k = (y2 - y1) / (x2 - x1);
rateK = Math.sqrt(k * k + 1);
offsetY = width * 0.5 / rateK;
offsetX = Math.round(offsetY * k);
offsetY = Math.round(offsetY);
}
this.previousLineEndPosT.set(x2 - offsetX, y2 + offsetY);
this.previousLineEndPosB.set(x2 + offsetX, y2 - offsetY);
let p1 = new Vec2(x1, y1);
let p2 = new Vec2(x2, y2);
if (x1 > x2) {
p1.x = x2;
p1.y = y2;
p2.x = x1;
p2.y = y1;
}
this._drawLine(p1, p2, width, offsetX, offsetY, rateK);
if (circleEnd) {
this._drawCircle(x1, y1, width * 0.5);
this._drawCircle(x2, y2, width * 0.5);
}
}
/**
* 绘制到指定坐标的直线,起点为上一次绘制的直线的终点,使用默认的颜色、宽度和线段端点样式
* @param x 终点坐标X
* @param y 终点坐标Y
*/
public lineTo(x: number, y: number) {
x = Math.round(x);
y = Math.round(y);
if (this.previousLineEndPos.x == x && this.previousLineEndPos.y == y) return;
let width = this.previousLineWidth;
let circleEnd = this.previousLineCircleEnd;
let x1 = this.previousLineEndPos.x;
let y1 = this.previousLineEndPos.y;
let x2 = x;
let y2 = y;
if (x1 > x2) {
x1 = x2;
y1 = y2;
x2 = this.previousLineEndPos.x;
y2 = this.previousLineEndPos.y;
}
let offsetX = 0;
let offsetY = 0;
let rateK = 1;
if (x1 == x2) {
offsetX = Math.round(width * 0.5);
} else if (y1 == y2) {
offsetY = Math.round(width * 0.5);
} else {
let k = (y2 - y1) / (x2 - x1);
rateK = Math.sqrt(k * k + 1);
offsetY = width * 0.5 / rateK;
offsetX = Math.round(offsetY * k);
offsetY = Math.round(offsetY);
}
if (!circleEnd) {
if (this.previousLineEndPos.x != this.previousLineEndPosT.x
|| this.previousLineEndPos.y != this.previousLineEndPosT.y) {
let p1 = new Vec2(this.previousLineEndPos.x - offsetX, this.previousLineEndPos.y + offsetY);
let p2 = new Vec2(this.previousLineEndPos.x + offsetX, this.previousLineEndPos.y - offsetY);
this._drawTriangle([p1, p2, this.previousLineEndPosT]);
this._drawTriangle([p1, p2, this.previousLineEndPosB]);
}
} else {
this._drawCircle(x1, y1, width * 0.5);
this._drawCircle(x2, y2, width * 0.5);
}
this._drawLine(new Vec2(x1, y1), new Vec2(x2, y2), width, offsetX, offsetY, rateK);
this.previousLineEndPos.set(x, y);
this.previousLineEndPosT.set(x - offsetX, y + offsetY);
this.previousLineEndPosB.set(x + offsetX, y - offsetY);
}
/**
* 绘制直线,不包含线段端点样式
* @param p1 线段起点坐标
* @param p2 线段终点坐标
* @param width 线段宽度
* @param color 线段颜色
*/
private _drawLine(p1: Vec2, p2: Vec2, width: number, offsetX: number, offsetY: number, slopeRate: number) {
if (p1.y == p2.y) {
//水平直线
let x = p1.x < p2.x ? p1.x : p2.x;
this._drawRect(new Vec2(x, Math.round(p1.y - width * 0.5)), Math.abs(p1.x - p2.x), width);
} else if (p1.x == p2.x) {
//垂直直线
let y = p1.y < p2.y ? p1.y : p2.y;
this._drawRect(new Vec2(Math.round(p1.x - width * 0.5), y), width, Math.abs(p1.y - p2.y));
} else {
//倾斜直线
let inverseK = (p1.x - p2.x) / (p1.y - p2.y);
let p1t = new Vec2(p1.x - offsetX, p1.y + offsetY);
let p1b = new Vec2(p1.x + offsetX, p1.y - offsetY);
let p2t = new Vec2(p2.x - offsetX, p2.y + offsetY);
let p2b = new Vec2(p2.x + offsetX, p2.y - offsetY);
let p1c = new Vec2();
let p2c = new Vec2();
let height = Math.round(width * slopeRate);
if (p2.y > p1.y) {
if (p1b.x < p2t.x) {
p1c.x = p1b.x;
p1c.y = p1b.y + height;
p2c.x = p2t.x;
p2c.y = p2t.y - height;
this._drawVerticalTriangle(p1c, p1b, p1t);
this._drawParallelogram(p1b, p2c, height);
this._drawVerticalTriangle(p2t, p2c, p2b);
} else {
p1c.x = p1b.x;
p1c.y = Math.round(p2t.y - (p1c.x - p2t.x) * inverseK);
p2c.x = p2t.x;
p2c.y = Math.round(p1b.y + (p1b.x - p2c.x) * inverseK);
this._drawVerticalTriangle(p2t, p2c, p1t);
this._drawParallelogram(p2c, p1b, p2t.y - p2c.y);
this._drawVerticalTriangle(p1c, p1b, p2b);
}
} else {
if (p1t.x < p2b.x) {
p1c.x = p1t.x;
p1c.y = p1t.y - height;
p2c.x = p2b.x;
p2c.y = p2b.y + height;
this._drawVerticalTriangle(p1t, p1c, p1b);
this._drawParallelogram(p1c, p2b, height);
this._drawVerticalTriangle(p2c, p2b, p2t);
} else {
p1c.x = p1t.x;
p1c.y = Math.round(p2b.y - (p1c.x - p2b.x) * inverseK);
p2c.x = p2b.x;
p2c.y = Math.round(p1t.y + (p1t.x - p2c.x) * inverseK);
this._drawVerticalTriangle(p2c, p2b, p1b);
this._drawParallelogram(p2b, p1c, p1t.y - p1c.y);
this._drawVerticalTriangle(p1t, p1c, p2t);
}
}
}
}
//#endregion
//#region 绘制:矩形
/**
* 绘制矩形
* @param x 矩形左下角的坐标X
* @param y 矩形左下角的坐标Y
* @param w 矩形宽度
* @param h 矩形高度
*/
public rect(x: number, y: number, w: number, h: number) {
x = Math.round(x);
y = Math.round(y);
this._drawRect(new Vec2(x, y), w, h);
}
/**
* 绘制矩形
* @param p 矩形左下顶点的坐标
* @param w 矩形宽度
* @param h 矩形高度
* @param color 矩形填充的颜色
*/
private _drawRect(p: Vec2, w: number, h: number) {
let minX = this.clampX(p.x);
let maxX = this.clampX(p.x + w);
let minY = this.clampY(p.y);
let maxY = this.clampY(p.y + h);
// for (let x = minX; x <= maxX; ++x) {
// for (let y = minY; y <= maxY; ++y) {
// this._drawPixel(x, y);
// }
// }
for (let y = minY; y <= maxY; ++y) {
this._drawRowPixel(minX, maxX, y);
}
}
/**
* 绘制平行四边形平行四边形的左右两边与Y轴平行
* @param p1 左下顶点坐标
* @param p2 右下顶点坐标
* @param height 垂直边高度
* @param color 颜色
*/
private _drawParallelogram(p1: Vec2, p2: Vec2, height: number) {
if (p1.x == p2.x) return;
let k = (p2.y - p1.y) / (p2.x - p1.x);
let minX = this._minX(p1.x);
let maxX = this._maxX(p2.x);
for (let x = minX; x <= maxX; ++x) {
let minY = p1.y + Math.round((x - p1.x) * k);
let maxY = minY + height;
minY = this._minY(minY);
maxY = this._maxY(maxY);
this._drawColPixel(minY, maxY, x);
// for (let y = minY; y <= maxY; ++y) {
// this._drawPixel(x, y);
// }
}
}
//#endregion
//#region 绘制:三角形
/**
* 绘制三角形
* @param x1 顶点1坐标X
* @param y1 顶点1坐标Y
* @param x2 顶点2坐标X
* @param y2 顶点2坐标Y
* @param x3 顶点3坐标X
* @param y3 顶点3坐标Y
*/
public triangle(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number) {
x1 = Math.round(x1);
y1 = Math.round(y1);
x2 = Math.round(x2);
y2 = Math.round(y2);
x3 = Math.round(x3);
y3 = Math.round(y3);
let pList: Vec2[] = [];
pList.push(new Vec2(x1, y1));
pList.push(new Vec2(x2, y2));
pList.push(new Vec2(x3, y3));
this._drawTriangle(pList);
}
/**
* 绘制任意三角形
* @param p1 顶点坐标
* @param p2
* @param p3
* @param color 填充颜色
*/
private _drawTriangle(pList: Vec2[]) {
pList.sort((a, b) => {
return a.x - b.x;
});
let p1 = pList[0];
let p2 = pList[1];
let p3 = pList[2];
if (p1.x == p2.x) {
if (p1.x == p3.x) return;
if (p1.y < p2.y) {
p1 = pList[1];
p2 = pList[0];
}
this._drawVerticalTriangle(p1, p2, p3);
return;
}
let k = (p3.y - p1.y) / (p3.x - p1.x);
let p4 = new Vec2(p2.x, Math.round(p1.y + (p2.x - p1.x) * k));
if (p4.y == p2.y) return;
if (p4.y < p2.y) {
this._drawVerticalTriangle(p2, p4, p1);
this._drawVerticalTriangle(p2, p4, p3);
} else {
this._drawVerticalTriangle(p4, p2, p1);
this._drawVerticalTriangle(p4, p2, p3);
}
}
/**
* 绘制一条边与Y轴平行的三角形
* @param p1 三角形垂直边的 上 顶点坐标
* @param p2 三角形垂直边的 下 顶点坐标
* @param p3 三角形 左侧或右侧 顶点坐标
* @param color 要绘制的颜色
*/
private _drawVerticalTriangle(p1: Vec2, p2: Vec2, p3: Vec2) {
if (p3.x == p1.x) return;
let k1 = (p3.y - p1.y) / (p3.x - p1.x);
let k2 = (p3.y - p2.y) / (p3.x - p2.x);
let maxX = p3.x, minX = p1.x;
if (maxX < minX) {
maxX = p1.x;
minX = p3.x;
}
minX = this._minX(minX);
maxX = this._maxX(maxX);
for (let x = minX; x <= maxX; ++x) {
let maxY = this.clampY(Math.round(p1.y + (x - p1.x) * k1));
let minY = this.clampY(Math.round(p2.y + (x - p2.x) * k2));
this._drawColPixel(minY, maxY, x);
// for (let y = minY; y <= maxY; ++y) {
// this._drawPixel(x, y);
// }
}
}
//#endregion
//#region 绘制:圆
/**
* 绘制一个圆
* @param x 圆心坐标x
* @param y 圆心坐标y
* @param radius 圆的半径
*/
public circle(x: number, y: number, radius: number) {
x = Math.round(x);
y = Math.round(y);
this._drawCircle(x, y, radius);
}
private _drawCircle(x: number, y: number, radius: number) {
radius = Math.round(radius);
if (radius == 0) return;
//三角形的斜边的平方
let dis = radius * radius;
// let minX = this._minX(x - radius);
// let maxX = this._maxX(x + radius);
// for (let i = minX; i <= maxX; ++i) {
// let r = x - i;
// r = Math.round(Math.sqrt(dis - r * r));
// let minY = this._minY(y - r);
// let maxY = this._maxY(y + r);
// for (let j = minY; j <= maxY; ++j) {
// this._drawPixel(i, j);
// }
// }
let minY = this.clampY(y - radius);
let maxY = this.clampY(y + radius);
for (let j = minY; j <= maxY; ++j) {
let r = j - y;
r = Math.round(Math.sqrt(dis - r * r));
let minX = this.clampX(x - r);
let maxX = this.clampX(x + r);
this._drawRowPixel(minX, maxX, j);
}
}
//#endregion
//#region 内部绘制方法
private _minX(x: number): number {
return x >= 0 ? x : 0;
}
private _maxX(x: number): number {
return x < this.width ? x : this.width - 1;
}
private _minY(y: number): number {
return y >= 0 ? y : 0;
}
private _maxY(y: number): number {
return y < this.height ? y : this.height - 1;
}
private clampX(x: number): number {
if (x < 0) return 0;
if (x >= this.width) return this.width - 1;
return x;
}
private clampY(y: number): number {
if (y < 0) return 0;
if (y >= this.height) return this.height - 1;
return y;
}
/**绘制一个像素点的颜色 */
private _drawPixel(x: number, y: number) {
x = Math.round(x);
y = Math.round(y);
if (this.maskPoint[x][y] == 0) return;
if (this.pointColor[x][y] == this.tempColor) return;
let index = (y * this.width + x) * 4;
this.pixelColor[index] = this.tempR;
this.pixelColor[index + 1] = this.tempG;
this.pixelColor[index + 2] = this.tempB;
this.pixelColor[index + 3] = this.tempA;
let c = this.pointColor[x][y];
this.colorCount[c]--;
this.colorCount[this.tempColor]++;
this.pointColor[x][y] = this.tempColor;
}
/**
* 连续绘制一行中的像素点
* @param startX 起点X坐标
* @param endX 终点X坐标
* @param y Y坐标
*/
private _drawRowPixel(startX: number, endX: number, y: number) {
let index = (y * this.width + startX) * 4;
for (let x = startX; x <= endX; ++x) {
if ((this.maskPoint[x][y] != 0 && this.pointColor[x][y] != this.tempColor) || this.pixelColor[index + 3] != 255) {
this.pixelColor[index] = this.tempR;
this.pixelColor[index + 1] = this.tempG;
this.pixelColor[index + 2] = this.tempB;
this.pixelColor[index + 3] = this.tempA;
cc.tween(this.pixelColor)
.delay(5)
.to(0.5,{[index + 3]:0})
.start();
let c = this.pointColor[x][y];
this.colorCount[c]--;
this.colorCount[this.tempColor]++;
this.pointColor[x][y] = this.tempColor;
}
index += 4;
}
}
/**
* 连续绘制一列中的像素点
* @param startY 起点Y坐标
* @param endY 终点Y坐标
* @param x X坐标
*/
private _drawColPixel(startY: number, endY: number, x: number) {
let index = (startY * this.width + x) * 4;
for (let y = startY; y <= endY; ++y) {
if ((this.maskPoint[x][y] != 0 && this.pointColor[x][y] != this.tempColor) || this.pixelColor[index + 3] != 255 ) {
this.pixelColor[index] = this.tempR;
this.pixelColor[index + 1] = this.tempG;
this.pixelColor[index + 2] = this.tempB;
this.pixelColor[index + 3] = this.tempA;
cc.tween(this.pixelColor)
.delay(5)
.to(0.5,{[index + 3]:0})
.start();
let c = this.pointColor[x][y];
this.colorCount[c]--;
this.colorCount[this.tempColor]++;
this.pointColor[x][y] = this.tempColor;
}
index += this.width * 4;
}
}
/**
* 将RGBA颜色分量转换为一个数值表示的颜色颜色分量为0~255之间的值
* @param r
* @param g
* @param b
* @param a
*/
private convertToNumber(r: number, g: number, b: number, a: number = 255): number {
//颜色值将用于数组索引不能为负数故红色分量为奇数时将减1变为偶数
return ((r & 0xfe) << 23) | (g << 16) | (b << 8) | a;
}
/**将十六进制的颜色转换为RGBA分量表示的颜色 */
private convertToRGBA(color: number): { r: number, g: number, b: number, a: number } {
//颜色值将用于数组索引不能为负数故红色分量为奇数时将减1变为偶数
return {
r: (color & 0xef000000) >> 23,
g: (color & 0x00ff0000) >> 16,
b: (color & 0x0000ff00) >> 8,
a: (color & 0x000000ff),
};
}
//#endregion
}
class Vec2 {
public x: number;
public y: number;
constructor(x: number = 0, y: number = 0) {
this.x = x;
this.y = y;
}
public set(p: number | Vec2, y?: number) {
if (typeof p === "number") {
this.x = p;
this.y = y;
} else {
this.x = p.x;
this.y = p.y;
}
}
}