查看原文
其他

Cocos Creator 物理挖洞教程!

COCOS 2022-06-10

The following article is from 白玉无冰 Author lamyoung

效果预览


实现步骤


整体思路是先使用 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();
})
看看效果如何!

视频讲解


小结


动手实践,在实践中成长,在模仿中学习。
以上就是今天的教程详解
再次感谢 白玉无冰 的倾情分享
欢迎点击【阅读原文】关注作者获取最新进展哦
 
如果您在使用 Cocos Creator 2D/3D 的过程中
 get 了独到的开发心得、见解或是方法
欢迎随时向我们投稿
帮助更多开发者们解决技术问题
让游戏开发更简单~
期待您与我们联系~
更多精彩:

腾讯光子《最强魔斗士》3D开发经验分享

新书推荐|零基础入门小游戏开发

你还在熬夜加班写 bug? 让小秘书来帮你

Cocos 插件开发者的福音来了,余额提现秒到账

Creator 2.3.3 更新说明,效率即是一切!

Creator 3D 官方中文视频教程,附素材源码

如何在 Creator 中优雅地嵌套 Prefab?

如何打通用户获取与变现的闭环实现稳定增长?

Analytics自定义事件功能详解,埋点分析利器

Cocos Creator 开发原生游戏体验如何

原生 3D 游戏《弹无虚发》是如何炼成的?

微信小游戏首包超出4M之后

技巧:微信如何设置星标??

前端开发者入门 Cocos Creator 必读


记得点亮星标哟!
有帮助的话点个在看呗▼

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存