Java 从tilemap高效生成Box2D实体(碰撞贴图)

Java 从tilemap高效生成Box2D实体(碰撞贴图),java,box2d,libgdx,tiles,game-physics,Java,Box2d,Libgdx,Tiles,Game Physics,我正在开发一款使用平铺贴图的平板游戏,我不知道这是否是个好主意 我制作了一个整洁的平铺地图编辑器,带有设置繁殖点等工具。但现在我想在编辑地图后测试玩游戏,为了将来的使用,我当然需要集成物理,我已经用LibGDX附带的Box2D完成了 我正在创建一个方法,从具有数据的平铺贴图创建一个碰撞贴图,如果平铺是可碰撞的或不可碰撞的 所以我想出了一个好主意: 在地图中循环,如果我们发现一个碰撞的瓷砖,则在其相邻的瓷砖中循环,看看它们是否也在碰撞,然后执行此操作,直到在设置碰撞矩形的宽度和高度时找到非碰撞瓷砖

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

我制作了一个整洁的平铺地图编辑器,带有设置繁殖点等工具。但现在我想在编辑地图后测试玩游戏,为了将来的使用,我当然需要集成物理,我已经用LibGDX附带的Box2D完成了

我正在创建一个方法,从具有数据的平铺贴图创建一个碰撞贴图,如果平铺是可碰撞的或不可碰撞的

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

在地图中循环,如果我们发现一个碰撞的瓷砖,则在其相邻的瓷砖中循环,看看它们是否也在碰撞,然后执行此操作,直到在设置碰撞矩形的宽度和高度时找到非碰撞瓷砖

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

但你知道,密码能说出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();
    }

}
public void createBody(){
List allRects=new ArrayList();
对于(int x=0;x0){
布尔breakingBad=false;
//水平循环通过邻居
对于(int j=0;j0)
添加(新的矩形(x,y,宽度,高度));
}
}
}
Collections.sort(allRects,newcomparator(){
@凌驾
公共整数比较(矩形o1,矩形o2){
整数o1Square=o1.width*o1.height;
整数o2Square=o2.width*o2.height;
返回o2Square.compareTo(o1Square);
}
});
List finalRects=new ArrayList();
主回路:
for(矩形矩形:所有矩形){
用于(矩形最终效果:最终效果){
if(finalRect.contains(rect)){
继续主循环;
}
}
最终结果添加(rect);
}
用于(矩形矩形:最终效果){
PolygonShape polyShape=新PolygonShape();
polyShape.setAsBox((float)rect.getWidth()/2,(float)rect.getHeight()/2,Vector2.tmp.set((float)rect.getCenterX(),(float)rect.getCenterY()),0f);
mapBody.createFixture(多边形,1);
polyShape.dispose();
}
}

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

而且它在中心矩形的角上创建单个装置,我不明白为什么

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


最初,每个瓷砖都有自己的固定装置,这会在其边缘造成奇怪的bug,正如预期的那样。首先,在曲面上使用自定义瓷砖贴图工具是一个很好的主意,但您正在重新发明轮子

libGDX内置了对TMX映射的支持。

您可以使用功能齐全的编辑器(如此平铺编辑器),而不是使用自制编辑器

所以,一旦你有了一个更好的地图系统,我会从面向对象的角度来看这个问题。由于要使用box2d物理,因此每个可碰撞体都有一个主体。所以你需要做的就是给每个可碰撞对象分配一个物理体,然后根据你的标准瓷砖大小设置大小

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

您还可以通过将这些平铺设置为“睡眠”来节省资源,box2d在这些实体上进行简化模拟,直到检测到碰撞为止。如果你只在地形上使用Box 2D进行碰撞检测,你可能想考虑其他选项,比如使用形状库来检测交叉点,然后在你的玩家角色体上设置Box 2D物理,以在有接触或其他东西的时候停止向下加速。p> 当