这次就不用物理链条了换一种方式实现。
回顾在 物理挖洞-优化篇 和 物理挖洞-实现篇 中介绍了一种用多边形链条组件(cc.PhysicsChainCollider)实现物理挖洞的方法。这次打算用多边形碰撞组件(cc.PhysicsPolygonCollider)去实现物理挖洞。
建议先看前两篇的讲解有助于更快理解这篇文章。
效果预览微信小游戏-ios-端效果预览
实现步骤整体思路是先用 Clipper 去计算多边形接着用 poly2tri 将多边形分割成多个三角形最后用多边形刚体填充。
引入第三方库
Clipper
Clipper 是一个强大的用于多边形计算的运算库。前往下面这个地址下载并作为插件导入 creator 。
http://jsclipper.sourceforge.net
为什么这次不用 物理挖洞-实现篇 中的 PolyBool 呢
经测试发现 Clipper 的效率会比 PolyBool 高并且 Clipper 内置了一个方法可以明确知道哪些多边形是洞。
poly2tri
poly2tri 是一个把多边形分割成三角形的库。下载地址如下
https://github.com/r3mi/poly2tri.js
poly2tri 的使用有一些要注意的大致就是不能有重复的点不能有相交的形状。
初始化准备
先在场景中添加一个物理节点一个绘图组件(用来画图)。
接着把物理引擎打开监听触摸事件。
// onLoad() {// 多点触控关闭cc.macro.ENABLE_MULTI_TOUCH false;cc.director.getPhysicsManager().enabled true;this.node_dirty.on(cc.Node.EventType.TOUCH_START, this._touchMove, this);this.node_dirty.on(cc.Node.EventType.TOUCH_MOVE, this._touchMove, this);// }
扩展多边形碰撞的组件
为了方便管理多边形碰撞组件新建一个脚本 PhysicsPolygonColliderEx.ts。
初始化
因为物理碰撞体需要物理刚体我们可以加一些限制并把这个菜单指向物理碰撞体的菜单中。
const { ccclass, property, menu, requireComponent } cc._decorator;ccclassmenu("i18n:MAIN_MENU.component.physics/Collider/PolygonEX-lamyoung.com")requireComponent(cc.RigidBody)export default class PhysicsPolygonColliderEx extends cc.Component {}
我们就可以在刚体节点中添加这个插件脚本了。
既然要用到多边形碰撞体就定义一个多边形碰撞体数组。
private _physicsPolygonColliders: cc.PhysicsPolygonCollider[] [];
因为 Clipper 中计算的结构是 {X,Y}。
所以加个变量记录多边形顶点信息。
private _polys: { X: number, Y: number }[][] [];
因为不同的库用的数据结构不同所以添加两个转换方法。
private _convertVecArrayToClipperPath(poly: cc.Vec2[]) {return poly.map((p) > { return { X: p.x, Y: p.y } });}private _convertClipperPathToPoly2triPoint(poly: { X: number, Y: number }[]) {return poly.map((p) > { return new poly2tri.Point(p.X, p.Y) });}
加一个初始化数据的接口。
init(polys: cc.Vec2[][]) {this._polys polys.map((v) > { return this._convertVecArrayToClipperPath(v) });}
计算多边形
参考 Clipper 中的使用例子写一个多边形差集调用。
//polyDifference(poly: cc.Vec2[]) {const cpr new ClipperLib.Clipper();const subj_paths this._polys;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_polytree new ClipperLib.PolyTree();cpr.Execute(ClipperLib.ClipType.ctDifference, solution_polytree, subject_fillType, clip_fillType);const solution_expolygons ClipperLib.JS.PolyTreeToExPolygons(solution_polytree);this._polys ClipperLib.Clipper.PolyTreeToPaths(solution_polytree);
分割多边形并添加刚体
参考 poly2tri 中的使用写一个多边形分割成三角形的调用。记得要把上面返回的数据转成 poly2tri 中可以使用的数据格式。
// polyDifference(poly: cc.Vec2[]) {let _physicsPolygonColliders_count 0;for (const expolygon of solution_expolygons) {const countor this._convertClipperPathToPoly2triPoint(expolygon.outer);const swctx new poly2tri.SweepContext(countor);const holes expolygon.holes.map(h > { return this._convertClipperPathToPoly2triPoint(h) });swctx.addHoles(holes);swctx.triangulate();const triangles swctx.getTriangles();// 逐一处理三角形...}
然后再逐一处理分割好的三角形修改 cc.PhysicsPolygonCollider 的 points 属性。
// 逐一处理三角形...for (const tri of triangles) {let c this._physicsPolygonColliders[_physicsPolygonColliders_count];if (!c) {//没有的话就创建c this.addComponent(cc.PhysicsPolygonCollider);c.friction 0;c.restitution 0;this._physicsPolygonColliders[_physicsPolygonColliders_count] c;}c.points tri.getPoints().map((v, i) > {return cc.v2(v.x, v.y)});c.apply();_physicsPolygonColliders_count;}// 剩余不要用的多边形清空。this._physicsPolygonColliders.slice(_physicsPolygonColliders_count).forEach((v > {if (v.points.length) {v.points.length 0;v.apply();}}));
绘制泥土
只要在遍历三角形的时候逐点画线就行了。
if (i 0) ctx.moveTo(v.x, v.y);else ctx.lineTo(v.x, v.y);
添加命令队列
为了不让每帧计算量过多添加一个命令队列。
private _commands: { name: string, params: any[] }[] [];pushCommand(name: string, params: any[]) {this._commands.push({ name, params });}
在每次更新的时候取出几个命令去执行。
lateUpdate(dt: number) {if (this._commands.length) {// 每帧执行命令队列for (let index 0; index < 2; index) {const cmd this._commands.shift();if (cmd)this[cmd.name](...cmd.params);elsebreak;}}}
涂抹地形
整体思路和 物理挖洞-优化篇 和 物理挖洞-实现篇 差不多。不清楚的话可以回看这两篇文章。
这次不同的是加了一个涂抹步长控制当涂抹间隔太小的时候就不参与计算。
private _touchStartPos: cc.Vec2;private _touchStart(touch: cc.Touch) {this._touchStartPos undefined;this._touchMove(touch);}private _touchMove(touch: cc.Touch) {const regions: cc.Vec2[] [];const pos this.graphics.node.convertToNodeSpaceAR(touch.getLocation());const count DIG_FRAGMENT;if (!this._touchStartPos) {// 画一个圆其实是多边形for (let index 0; index 25) {// 这里是合并成一个顺滑的图形 详细上一篇文章const startPos this._touchStartPos;for (let index 0; index 0) {x pos.x vec_x;y pos.y vec_y;} else {x startPos.x vec_x;y startPos.y vec_y;}regions.push(this._optimizePoint([x, y]));}this._touchStartPos pos;}}if (regions.length)this.polyEx.pushCommand(polyDifference, [regions, this.graphics]);}private _touchEnd(touch: cc.Touch) {this._touchStartPos undefined;}小结
以上为白玉无冰使用 Cocos Creator v2.3.3 开发"物理挖洞之多边形碰撞体挖洞"的技术分享。如果对你有点帮助欢迎分享给身边的朋友。
视频讲解感谢各位看官的支持如果这篇文章能给你带来一点点的帮助白玉无冰感到非常愉快。如果可以点个在看的话我会非常振奋开心。当然请白玉无冰喝一杯奶茶的话我会感到更加的满足。
其实写这一篇图文花了一整天的时间不算上之前的查阅资料及代码的实现但是看到一篇文章的完成富有满满的成就感。
不懂大家是否理解了这种实现方式不知道是否需要补充一个视频讲解。
这样吧如果这篇文章在看超过30我就补录一篇视频讲解
准备去研究新东西喽冲呀大家一定要多多实践练习
更
多
精
彩
讲一讲这个公众号吧附原创精选整理
小游戏-不停歇的球技术分享源码相送
物理挖洞涂抹地形! 优化篇
物理流体的一种实现
物理挖洞链条实现篇
Javascript 中的三位一体物理挖洞-涂抹地形之优化视频讲解!
shader 动画之 loading 特效!
物理挖洞 链条实现篇-视频讲解
欢乐水杯(happy glass)的流体实现 视频讲解
转载请保留文末二维码和完整代码获取方式
点击“阅读原文”查看更多精彩
“在看”是最大的鼓励▼
【本文由:香港云服务器 http://www.558idc.com/ne.html 复制请保留原URL】