有效地从tilemap生成Box2D主体(碰撞图)

时间:2013-01-22 17:29:11

标签: java box2d libgdx tiles game-physics

我正在制作一款使用瓷砖地图的平台游戏,我不知道这是不是一个好主意!

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

我正在创建一个从tile map创建碰撞贴图的方法,如果贴图是可碰撞的,则该贴图具有数据!

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

循环遍历地图,如果我们发现碰撞的瓷砖循环通过其相邻的瓷砖并查看它们是否也发生碰撞,并且这样做,直到我们为碰撞矩形设置宽度和高度时找到非滑动瓷砖

在我们得到一堆矩形后,我按照从最大的正方形到最小的顺序对它们进行排序,所以我们得到最大的碎片,然后我将矩形添加到最终列表中并检查最终的矩形,如果它们中的任何一个与当前的身体重叠,那么我就不要有重叠的身体

但是你知道,代码告诉超过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();
    }

}

inefficient?

然而,这个窗台似乎效率很低,因为由于某些原因,它仍然会产生比可能的更小的固定装置,例如在右上角

它也在中心矩形的角落里创造了单个灯具,我无法弄明白为什么!

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

最初每个瓷砖都是自己的夹具,它会在边缘上产生奇怪的错误

1 个答案:

答案 0 :(得分:3)

首先,自定义平铺贴图工具在表面上是一个好主意,但你正在重新发明轮子。

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分配一个物理主体,并根据您的标准平铺大小设置大小。

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

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