【问题标题】:Generating Box2D body(collision map) from tilemap efficiently高效地从 tilemap 生成 Box2D body(碰撞图)
【发布时间】:2013-01-06 00:51:15
【问题描述】:

我正在开发一款使用平铺地图的平台游戏,我不知道这是否是个好主意!

我已经制作了一个简洁的瓷砖地图编辑器,其中包含用于设置生成点等的工具,但现在我希望能够在编辑地图后测试玩游戏并以备将来使用,我当然需要集成物理,我'已经完成了 LibGDX 附带的 Box2D!

我正在创建一种方法来从瓦片地图创建碰撞地图,如果瓦片是否可碰撞,该地图具有数据!

所以我想出了这个好主意:

循环遍历地图,如果我们找到一个碰撞的瓦片循环遍历它的相邻瓦片并查看它们是否也在碰撞,并且这样做直到当我们为碰撞矩形设置宽度和高度时找到非碰撞瓦片

在我们得到一堆矩形之后,我按从最大的正方形到最小的顺序对它们进行排序,这样我们就得到了最大的部分,然后我将矩形添加到最终列表中,并检查最终矩形是否与当前主体重叠,所以我不t有重叠的身体

但你知道,代码能说出 1000 多个单词,对吧?

    public void createBody() {
    List<Rectangle> allRects = new ArrayList<Rectangle>();
    for(int x = 0; x < info.getWidth(); x++) {
        for(int y = 0; y < info.getHeight(); y++) {
            if(tiles[x][y].getInfo().isColliding()) {
                int width = 1;
                int height = 1;

                //loop through neighbors horizontally
                for(int i = 0; i < info.getWidth() - x; i++) {
                    if(!tiles[x + i][y].getInfo().isColliding()) {
                        //if tile is not clipped, we set width to i which is current x offset


                        width = i;
                        break;
                    }
                }


                //only if width is bigger than zero can the rect have any tiels..
                if(width > 0) {
                    boolean breakingBad = false;
                    //loop through neighbors horizontally
                    for(int j = 0; j < info.getHeight() - y; j++) {
                        //loop though neigbors vertizally
                        for(int i = 0; i < width; i++) {
                            //check if tile is not colliding 
                            if(!tiles[x + i][y + j].getInfo().isColliding()) {
                                //and if so, we set height to j which is current y offset
                                height = j;

                                //breaking bad aka leaving both loops
                                breakingBad = true;
                                break;
                            }
                        }
                        if(breakingBad) {
                            break;
                        }
                    }
                }
                if(width * height > 0)
                    allRects.add(new Rectangle(x, y, width, height));
            }
        }
    }

    Collections.sort(allRects, new Comparator<Rectangle>() {

        @Override
        public int compare(Rectangle o1, Rectangle o2) {
            Integer o1Square = o1.width * o1.height;
            Integer o2Square = o2.width * o2.height;
            return o2Square.compareTo(o1Square);
        }
    });

    List<Rectangle> finalRects = new ArrayList<Rectangle>();
    mainloop:
    for(Rectangle rect: allRects) {
        for(Rectangle finalRect: finalRects) {
            if(finalRect.contains(rect)) {
                continue mainloop;
            }
        }
        finalRects.add(rect);
    }

    for(Rectangle rect: finalRects) {
        PolygonShape polyShape = new PolygonShape();
        polyShape.setAsBox((float)rect.getWidth() / 2, (float)rect.getHeight() / 2, Vector2.tmp.set((float)rect.getCenterX(), (float)rect.getCenterY()), 0f);

        mapBody.createFixture(polyShape, 1);
        polyShape.dispose();
    }

}

然而,这个门槛似乎相当低效,因为由于某些原因,它仍然会创建比可能的更小的固定装置,例如在右上角

它还在中心矩形的角落创建了单个灯具,我不知道为什么!

整个想法都是低效的,我应该使用其他方法还是手动创建碰撞贴图,或者最好的想法是什么?

最初每个瓷砖都是自己的固定装置,这会在它们的边缘造成奇怪的错误,正如预期的那样

【问题讨论】:

  • 当我们谈论效率低下时,在“compareTo”方法中,您执行了大量的自动装箱。 'Rectangle.width' 是 int 还是 Integer ?
  • 我尝试了您的比较方法,结果发现它比仅使用整数的类似比较贵 2 倍。

标签: java box2d libgdx tiles game-physics


【解决方案1】:

首先,自定义图块映射工具在表面上是个好主意,但您正在重新发明轮子。

libGDX 具有对 TMX 映射的内置支持。 http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/maps/tiled/TmxMapLoader.html

您可以使用全功能编辑器,例如 Tiled - http://www.mapeditor.org/

,而不是使用您的自制编辑器

因此,一旦您为地图建立了更好的系统,我会从面向对象的角度来看待这个问题。由于您想使用 box2d 物理,每个 collidableTile 都有一个 body。因此,您需要做的就是为每个 collidableTile 分配一个物理体,并根据您的标准 tile 大小设置大小。

不要忘记 box2d 世界和您的游戏屏幕之间存在差异,其中 box2d 以公制单位衡量,而您的屏幕以像素衡量。所以你需要做一些数学来正确设置位置和大小。如果你想让一组瓦片共享一个body,你可能想在构造每个collidableTile时将body作为参数传入,然后根据你能找到多少相邻瓦片来调整body的大小。物理体的更复杂的形状可能更复杂。

您还可以通过将这些图块设置为“睡眠”来节省资源,其中 box2d 会减少对这些物体的模拟,直到检测到碰撞。如果您仅使用 box2d 在地形上进行碰撞检测,您可能需要考虑其他选项,例如使用形状库来检测交叉点,然后在您的玩家角色身体上设置 box2d 物理特性以在有接触时停止向下加速,或者某物。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-28
    • 1970-01-01
    • 2015-02-07
    • 2010-10-30
    • 2018-09-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多