物理挖洞之分塊 !Cocos Creator !

減少多邊形計算!畫餅分之~

效果預覽

回顧

物理挖洞之鏈條!實現!(含視頻講解) 中介紹了用 PolyBool 和鏈條組件(cc.PhysicsChainCollider)實現物理挖洞的方法。

雖說這種方案可能不是最佳方案,但裏面有一種 evenodd 的思想,覺得不錯的。

物理挖洞之鏈條!優化!(含視頻講解) 中介紹了幾個優化的地方。

其中,單位化的思想和平滑移動的思想在後續一直被使用。

不過,多邊形鏈條組件有一個問題,容易穿透。

接着,經過多次查找和分析,在物理挖洞之多邊形!實現! 中介紹用多邊形碰撞組件(cc.PhysicsPolygonCollider)去實現物理挖洞。

整體思路是,先用 Clipper 去計算多邊形 (效率比 PolyBool 高),接着用 poly2tri 將多邊形分割成多個三角形,最後用多邊形剛體填充。

但是呢,poly2tri 限制比較多,物理挖洞之多邊形!填坑! 中介紹了填坑之路。

並利用 maskgraphics 實現好看的紋理。

當然,還有羣內小夥伴們討論分享的3D效果,在上面的基礎上,修改了一個物理挖洞之3D效果,感謝各位小夥伴的分享!

image

強烈建議按順序閱讀上面幾篇文章,有助於更好的理解這篇的文章哦!

實現原理

整體思路是對區域進行分塊,點擊的時候判斷是對哪個區域塊有操作,再對這些區域塊進行多邊形計算,最後再繪製所有的多邊形。

這裏與物理挖洞之多邊形!實現! 中的區別是少了一步 poly2tri,這是怎麼做到的?

首先得明白一點,之前使用 poly2tri 是因爲會有內多邊形出現。

所以,在分塊的時候,只要滿足分塊的尺寸小於挖洞的尺寸,這樣就不會出現內多邊形了。

如何判斷點擊的是哪個區域呢?

在初始化的時候,用一個2D矩形(cc.Rect)數組記錄每一個分塊的信息。

private _rects: cc.Rect[] = [];

當點擊的時候會生成一個多邊形(參考物理挖洞之鏈條!優化! 中的觸摸平滑連續)數據。

對於這個多邊形的每個點,計算出座標 xy 的最大值和最小值。

然後就可以算出這個的多邊形的矩形(aabb (Axis-Aligned Bounding Box))。

let xMin = Number.MAX_SAFE_INTEGER, xMax = Number.MIN_SAFE_INTEGER, yMin = Number.MAX_SAFE_INTEGER, yMax = Number.MIN_SAFE_INTEGER;
// 計算最小最大值
xMin = p.x < xMin ? p.x : xMin;
yMin = p.y < yMin ? p.y : yMin;
xMax = p.x > xMax ? p.x : xMax;
yMax = p.y > yMax ? p.y : yMax;
// 得出矩形
const rect_r = cc.Rect.fromMinMax(cc.v2(xMin, yMin), cc.v2(xMax, yMax));

image

再用這個矩形和初始化矩形做一次相交判斷,這樣就可以粗略的確定要計算的塊了。

for (let index = 0; index < this._rects.length; index++) {
    const rect = this._rects[index];
    if (rect.intersects(rect_r)) {
        this.polyEx.pushCommand('polyDifference', [regions, index])
    }
}

image

多邊形計算用的是 Clipper ,使用接口可以參考官網或者物理挖洞之多邊形!

// polyDifference(poly: cc.Vec2[], index: number) {
// 計算新的多邊形
// https://sourceforge.net/p/jsclipper/wiki/documentation
const cpr = new ClipperLib.Clipper(ClipperLib.Clipper.ioStrictlySimple);
const subj_paths = this._polys[index];
const clip_paths = [this._convertVecArrayToClipperPath(poly)]
cpr.AddPaths(subj_paths, ClipperLib.PolyType.ptSubject, true);
cpr.AddPaths(clip_paths, ClipperLib.PolyType.ptClip, true);
const subject_fillType = ClipperLib.PolyFillType.pftEvenOdd;
const clip_fillType = ClipperLib.PolyFillType.pftEvenOdd;
const solution = new ClipperLib.Paths();
cpr.Execute(ClipperLib.ClipType.ctDifference, solution, subject_fillType, clip_fillType);
this._polys[index] = solution || [];

在所有分塊計算之後,最後整體繪製多邊形碰撞體和紋理。

// private draw() {
ctx.clear();
for (let index = 0; index < this._polys.length; index++) {
    const polygons = this._polys[index];
    for (let index2 = 0; index2 < polygons.length; index2++) {
        const polygon = polygons[index2];
        let c = this._physicsPolygonColliders[_physicsPolygonColliders_count];
        c.points = this._convertClipperPathToVecArray(polygon);
        c.apply();

        for (let index3 = 0; index3 < c.points.length; index3++) {
            const p = c.points[index3];
            if (index3 === 0) ctx.moveTo(p.x, p.y);
            else ctx.lineTo(p.x, p.y);
        }
        ctx.close();
    }
}
ctx.fill();

當然,羣(859642112)內小夥伴 @吳先生 也實現了這個分塊,分塊計算多邊形同時,也進行分塊繪製,歡迎加羣一起討論!

小結

生命不息,挖坑不止!

以上爲白玉無冰使用 Cocos Creator v2.3.3 開發"物理挖洞之分塊!"的技術分享。如果對你有點幫助,歡迎分享給身邊的朋友。

天下事有難易乎?爲之,則難者亦易矣;不爲,則易者亦難矣。人之爲學有難易乎?學之,則難者亦易矣;不學,則易者亦難矣。 --《爲學》


原文鏈接
完整代碼(見readme)
原創文章導航

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章