
const { ccclass, property } = cc._decorator;interface Point {x: number;y: number;
}
@ccclass
export default class NewClass extends cc.Component {@property(cc.Graphics)graphics: cc.Graphics = null;@property(cc.Node)touchNode: cc.Node = null;@property(cc.Node)cutNode: cc.Node = null;@property(cc.Node)root: cc.Node = null;@property(cc.EditBox)maxCountEditBox: cc.EditBox = null;_startPos: cc.Vec2 = null_cutCount: number = 0lineArr: Array<{ a: Point, b: Point }> = []totalCount = 2;pointsArr: Array<Point[]> = []start() {this.reset()this.touchNode.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);this.touchNode.on(cc.Node.EventType.MOUSE_MOVE, this.onTouchMove, this);this.touchNode.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);this.touchNode.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);const manager = cc.director.getCollisionManager();manager.enabled = true;}drawLine(point?) {this.graphics.clear();this.graphics.lineWidth = 10for (let i = 0; i < this.lineArr.length; i++) {const element = this.lineArr[i];const ws1 = this.cutNode.convertToWorldSpaceAR(cc.v2(element.a));const pos1 = this.graphics.node.convertToNodeSpaceAR(ws1);const ws2 = this.cutNode.convertToWorldSpaceAR(cc.v2(element.b));const pos2 = this.graphics.node.convertToNodeSpaceAR(ws2);this.graphics.moveTo(pos1.x, pos1.y);this.graphics.lineTo(pos2.x, pos2.y);this.graphics.stroke()}if (point) {const ws1 = this.cutNode.convertToWorldSpaceAR(cc.v2(point.a));const pos1 = this.graphics.node.convertToNodeSpaceAR(ws1);const ws2 = this.cutNode.convertToWorldSpaceAR(cc.v2(point.b));const pos2 = this.graphics.node.convertToNodeSpaceAR(ws2);this.graphics.moveTo(pos1.x, pos1.y);this.graphics.lineTo(pos2.x, pos2.y);this.graphics.stroke()}}onTouchStart(event) {if (this._cutCount >= this.totalCount) returnconst touchPos = event.getLocation();const pos = this.cutNode.convertToNodeSpaceAR(cc.v2(touchPos));this._startPos = pos;this.drawLine({ a: pos, b: pos })}onTouchMove(event) {if (!this._startPos) returnconst touchPos = event.getLocation();const pos = this.cutNode.convertToNodeSpaceAR(cc.v2(touchPos));this.drawLine({ a: this._startPos, b: pos })}onTouchEnd(event) {if (!this._startPos) returnthis._cutCount++;const touchPos = event.getLocation();const pos2 = this.cutNode.convertToNodeSpaceAR(cc.v2(touchPos));let line = { a: this._startPos, b: pos2 }this.lineArr.push(line)this._startPos = nullthis.drawLine()if (this._cutCount < this.totalCount) returnlet collider = this.cutNode.getComponent(cc.PolygonCollider)if (!collider) returnlet points = collider.pointslet arr: any = [points]let newPointArr = this.cut(arr, this.lineArr)this.lineArr = []let i = 0let colorArr = ["#C1B7B7", "#D42E2E", "#2E95D4", "#A9D42E", "#45D42E", "#7DA97D", "#7DA3A9", "#817DA9"]newPointArr.forEach(points => {let node = this.root.children[i] || cc.instantiate(this.cutNode)node.parent = this.rootnode.active = truenode.y = 0;this.pointsArr[i] = pointsnode.children[0].color = new cc.Color().fromHEX(colorArr[i % colorArr.length])let x = -300 + i * 150this.upDateBox()node.stopAllActions()cc.tween(node).delay(1).call(() => {this.onClickFly()this.upDateBox()}).start()i++});this.cutNode.active = false}upDateBox() {this.graphics.clear();for (let i = 0; i < this.pointsArr.length; i++) {const node = this.root.children[i];if (!cc.isValid(node)) returnlet points = this.pointsArr[i]if (!points.length) returnlet mask: any = node.getComponent(cc.Mask);let stencil = mask._graphics;stencil.clear();stencil.moveTo(points[0]);points.forEach(point => {stencil.lineTo(point.x, point.y);});stencil.fill();}}reset(): void {this.graphics.clear();if (this.maxCountEditBox) {let count = Number(this.maxCountEditBox.string)if (!isNaN(count)) {this.totalCount = Math.max(count, 1)this.maxCountEditBox.string = this.totalCount + ""}else {this.maxCountEditBox.string = this.totalCount + ""}}this.lineArr = []this.pointsArr = []this.root.children.forEach((value) => {value.active = falsevalue.x = 0value.y = 0})this.cutNode.active = truethis._cutCount = 0let collider = this.cutNode.getComponent(cc.PolygonCollider)if (!collider) returnlet points = []collider.points.forEach((value) => {points.push({ x: value.x, y: value.y })})let mask: any = this.cutNode.getComponent(cc.Mask);let stencil = mask._graphics;stencil.clear();stencil.moveTo(points[0]);for (let index = 0; index < points.length; index++) {const point = points[index];stencil.lineTo(point.x, point.y);}stencil.fill();}cut(cutNodePointsArr: Array<Point[]> = [], lineArr: Array<{ a: Point, b: Point }> = []) {let newPointArr = []for (let k = 0; k < lineArr.length; k++) {let line = lineArr[k]let arr = []if (k == 0) {cutNodePointsArr.forEach((value) => {let arr2 = []value.forEach((value2) => { arr2.push({ x: value2.x, y: value2.y }) })arr.push(arr2)})}else {newPointArr.forEach((value) => {let arr2 = []value.forEach((value2) => { arr2.push({ x: value2.x, y: value2.y }) })arr.push(arr2)})newPointArr = []}for (let j = 0; j < arr.length; j++) {const points = arr[j];let newArr = this.cutOneBox(points, line)newPointArr = newPointArr.concat(newArr)}}return newPointArr;}cutOneBox(points, line) {let newPointArr = [];let crossPoints = []let newBoxs = []let boxIndex = 0for (let i = 0; i < points.length; i++) {let point = points[i];const nextPoint = points[i + 1] || points[0];let crossPoint = this.getIntersectionPoint(point, nextPoint, line.a, line.b)if (!crossPoint) {if (!newBoxs[boxIndex]) newBoxs[boxIndex] = []newBoxs[boxIndex].push(point)}else {if (!newBoxs[boxIndex]) newBoxs[boxIndex] = []newBoxs[boxIndex].push(point)newBoxs[boxIndex].push(crossPoint)crossPoints.push(crossPoint)boxIndex++if (!newBoxs[boxIndex]) newBoxs[boxIndex] = []newBoxs[boxIndex].push(crossPoint)}}if (crossPoints.length !== 2 || newBoxs.length < 2) {if (points.length) newPointArr.push(points)return newPointArr}let box1 = newBoxs[0]if (newBoxs[2]) box1 = box1.concat(newBoxs[2])let box2 = newBoxs[1]newPointArr.push(box1)newPointArr.push(box2)return newPointArr;}getIntersectionPoint(a: Point, b: Point, c: Point, d: Point): Point | null {if (!a || !b || !c || !d) return nullconst ab = { x: b.x - a.x, y: b.y - a.y };const cd = { x: d.x - c.x, y: d.y - c.y };const ac = { x: c.x - a.x, y: c.y - a.y };const crossAbCd = this.crossProduct(ab, cd);const crossAcCd = this.crossProduct(ac, cd);const crossAcAb = this.crossProduct(ac, ab);if (crossAbCd === 0) {return null;}const t = crossAcCd / crossAbCd;const u = crossAcAb / crossAbCd;if (t >= 0 && t <= 1 && u >= 0 && u <= 1) {return {x: a.x + t * ab.x,y: a.y + t * ab.y};}return null;}crossProduct(v1: { x: number; y: number }, v2: { x: number; y: number }): number {return v1.x * v2.y - v1.y * v2.x;}onClickFly() {for (let i = 0; i < this.pointsArr.length; i++) {let center = this.getPolygonCenter(this.pointsArr[i]);let node = this.root.children[i]let dir = center.normalize();node.setPosition(cc.v2(dir.x * 100, dir.y * 100))}}onClickReset() {for (let i = 0; i < this.pointsArr.length; i++) {let node = this.root.children[i]this.root.children[i].stopAllActions()cc.tween(node).to(1, { x: 0, y: 0 }).call(() => {if (i === this.pointsArr.length - 1) {this.reset()}}).start();}}private getPolygonCenter(polygon) {let x = 0, y = 0;for (let i = 0; i < polygon.length; i++) {x += polygon[i].x;y += polygon[i].y;}x = x / polygon.length;y = y / polygon.length;return cc.v2(x, y)}
}