【cocos creator】多边形图片切割,读取PolygonCollider点集,加遮罩实现
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 = 0
/**画的线数据 */
lineArr: Array<{ a: Point, b: Point }> = []
/**划x条线后开始判定(切割) */
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;
// manager.enabledDebugDraw = true;
// manager.enabledDrawBoundingBox = true;
}
drawLine(point?) {
this.graphics.clear();
this.graphics.lineWidth = 10
for (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) return
const 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) return
const touchPos = event.getLocation();
const pos = this.cutNode.convertToNodeSpaceAR(cc.v2(touchPos));
this.drawLine({ a: this._startPos, b: pos })
}
onTouchEnd(event) {
if (!this._startPos) return
this._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 = null
this.drawLine()
if (this._cutCount < this.totalCount) return
let collider = this.cutNode.getComponent(cc.PolygonCollider)
if (!collider) return
let points = collider.points
let arr: any = [points]
let newPointArr = this.cut(arr, this.lineArr)
this.lineArr = []
let i = 0
let 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.root
node.active = true
node.y = 0;
this.pointsArr[i] = points
node.children[0].color = new cc.Color().fromHEX(colorArr[i % colorArr.length])
let x = -300 + i * 150
this.upDateBox()
node.stopAllActions()
cc.tween(node)
.delay(1)
.call(() => {
this.onClickFly()
this.upDateBox()
})
.start()
i++
});
this.cutNode.active = false
}
/**
* 更新切割后图像位置
* @returns
*/
upDateBox() {
this.graphics.clear();
for (let i = 0; i < this.pointsArr.length; i++) {
const node = this.root.children[i];
if (!cc.isValid(node)) return
let points = this.pointsArr[i]
if (!points.length) return
let 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();
}
}
/**
* 初始化
* @returns
*/
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 = false
value.x = 0
value.y = 0
})
this.cutNode.active = true
this._cutCount = 0
let collider = this.cutNode.getComponent(cc.PolygonCollider)
if (!collider) return
let points = []
// points = collider.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();
}
/**
* 开始切割
* @param cutNodePointsArr 要切割图形数组
* @param lineArr 切割线数组
* @returns
*/
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 = 0
for (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;
}
/**
* 获取ab,cd两条线段的交点,没交点返回null
* @param a
* @param b
* @param c
* @param d
* @returns
*/
getIntersectionPoint(a: Point, b: Point, c: Point, d: Point): Point | null {
if (!a || !b || !c || !d) return null
const 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) {
// Lines are parallel
return null;
}
const t = crossAcCd / crossAbCd;
const u = crossAcAb / crossAbCd;
if (t >= 0 && t <= 1 && u >= 0 && u <= 1) {
// Intersection point lies on both line segments
return {
x: a.x + t * ab.x,
y: a.y + t * ab.y
};
}
// Intersection point does not lie on both line segments
return null;
}
crossProduct(v1: { x: number; y: number }, v2: { x: number; y: number }): number {
return v1.x * v2.y - v1.y * v2.x;
}
// update (dt) {}
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))
// cc.tween(node).to(2, { x: dir.x * 100, y: dir.y * 100 }).start();
}
}
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)
}
}
原文地址:https://blog.csdn.net/K86338236/article/details/144295681
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!