圖文+視頻講解 | 物理挖洞!塗抹地形! 小鱷魚愛洗澡!百戰天蟲 !Cocos Creator !

終於來挖坑了!老規矩!圖文+視頻講解!

效果預覽

實現步驟

整體思路是先使用 PolyBool 計算多邊形,接着使用 cc.PhysicsChainCollider 將多邊形圍起來,最後使用 cc.Graphics 將整個地形繪製出來。

引入 PolyBool

PolyBool是什麼?對多邊形(並集,交集,差,異或)進行運算。(Boolean operations on polygons (union, intersection, difference, xor).)

前往 https://github.com/voidqk/polybooljs 下載。並作爲插件腳本。

這個倉庫有個 PR 提供了一個聲明文件,因爲我用的是 TypeScript ,我就把它拿來改改用了。

參考這個庫的示例,裏面有一個 regions 三維數組記錄多邊形的信息。

我們也用個三維數組記錄當前多邊形的形狀的數據,並初始化爲一個長方形吧!

private _regions: number[][][] = [];
reset() {
    this._regions = [
        [[-480, -320], [-480, 250], [480, 250], [480, -320]]
    ];
}

添加物理鏈條

先在場景中添加物理節點。

爲這個節點初始化一些 cc.PhysicsChainCollider ,並開啓物理引擎,順便開啓物理調試模式,方便看效果。

//onLoad() {
cc.director.getPhysicsManager().enabled = true;
cc.director.getPhysicsManager().debugDrawFlags = 1;
for (let index = 0; index < 100; index++) {
    const c = this.node_dirty.addComponent(cc.PhysicsChainCollider);
    c.loop = true;
    c.enabled = false;
}

接着根據_regions的數值,把points傳給物理鏈條。

// draw() {
const chains = this.node_dirty.getComponents(cc.PhysicsChainCollider);
chains.forEach((c) => {
    c.enabled = false;
})
for (let index = 0; index < this._regions.length; index++) {
    const pos = this._regions[index];
    let poly = chains[index];
    if (!poly) {
        poly = this.node_dirty.addComponent(cc.PhysicsChainCollider);
        poly.loop = true;
    }
    poly.points.length = 0;
    poly.points = pos.map((v, i) => {
        const v2 = cc.v2(v[0], v[1])
        return v2;
    });
    poly.enabled = true;
}

看看效果。

開始挖洞!

監聽一個節點的觸摸事件。

// onLoad() {
this.node_dirty.on(cc.Node.EventType.TOUCH_START, this._touchMove, this);
this.node_dirty.on(cc.Node.EventType.TOUCH_MOVE, this._touchMove, this);

在觸摸點周圍圈一個多邊形(類似畫一個圈,不清楚的話可以參考上一篇中的把圓圍成一個圈),並使用差集的方法計算新的多邊形,計算後再重寫畫物理鏈條。

// const DIG_RADIUS = 50;
// const DIG_FRAGMENT = 12;
// _touchMove(touch: cc.Touch) {
const regions = [[]];
const pos = this.node_dirty.convertToNodeSpaceAR(touch.getLocation());

const count = DIG_FRAGMENT;
for (let index = 0; index < count; index++) {
    const r = 2 * Math.PI * index / count;
    const x = pos.x + DIG_RADIUS * Math.cos(r);
    const y = pos.y + DIG_RADIUS * Math.sin(r);
    regions[0].push([x, y]);
}

const result = PolyBool.difference({
    regions: this._regions,
    inverted: false
}, {
    regions,
    inverted: false
});
this._regions = result.regions;
this.draw();

看看效果。

填充顏色

先畫一個多邊形,只需先移動到起點,然後逐一劃線,就可以了。

// private _drawPoly(ctx, poly) {
poly.forEach((pos, i) => {
    if (i === 0)
        ctx.moveTo(pos.x, pos.y);
    else
        ctx.lineTo(pos.x, pos.y);
    ctx.close();
});

填充思路是基於 canvas 中的 evenodd 規則。

與上面不一樣的地方是,我是計算這個多邊形被幾個大的多邊形包圍,當是偶數的時候填充泥土的顏色,當是奇數時,填充背景的顏色。

當然,需要注意的是,計數越大的要越後畫,這樣才能達到最終效果。

// draw() {
const enabled_chains_points=[]
for (let index = 0; index < this._regions.length; index++) {
    // 省略與上面相同 draw
    enabled_chains_points[index] = poly.points;
}
this.graphics.clear(true);
const enabled_chains_points_sort = enabled_chains_points.map((curPoly, curPoly_i) => {
    const count = enabled_chains_points.reduce((pre, nextPoly, nextPoly_i) => {
        if ((curPoly_i != nextPoly_i)) {
            const length = curPoly.length;
            for (let i = 0; i < length; ++i) {
                const p0 = curPoly[i];
                if (!cc.Intersection.pointInPolygon(p0, nextPoly))
                    return pre;
            }
            return pre + 1;
        }
        return pre;
    }, 0);

    return { curPoly, count };
}).sort((a, b) => {
    return a.count - b.count;
})
enabled_chains_points_sort.forEach(({ curPoly, count }) => {
    this.graphics.fillColor = count % 2 === 0 ? cc.Color.ORANGE : cc.Color.BLACK;
    this._drawPoly(this.graphics, curPoly);
    this.graphics.fill();
})

順便吐槽一下,canvas 中的 fill 可以帶evenodd 的參數, 而 cc.Graphics 中不能帶這個參數,可能是因爲 creator 中的 webgl 畫圖不方便實現吧!(試圖從源碼中看看有沒方案,最終還是自己多次填充了,而且webgl中的實現會不停創建buffer )。

好吧,看看效果如何!

優化

< 未完待續 > 關注 白玉無冰 第一時間獲取最新進展!

小結

動手實踐!在實踐中成長!在模仿中學習!

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

視頻講解

視頻講解


參考文章

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