zoukankan      html  css  js  c++  java
  • 物理挖洞之分块 !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)
    原创文章导航

  • 相关阅读:
    Sqlserver 迁移数据库批量迁移作业(Job)
    在VS2010开发的MVC3 应用程序中设定默认的浏览器
    创建继承自System.Web.UI.WebControls.WebControl基类的控件类
    遍历页面控件
    @fontface
    加密配置节点
    视图状态的程序分块
    BlogEngine.NET 1.5的BlogProvider、DbBlogProvider
    避免target特性
    SCOPE_IDENTITY、IDENT_CURRENT 、@@IDENTITY
  • 原文地址:https://www.cnblogs.com/lamyoung/p/13151315.html
Copyright © 2011-2022 走看看