具有多个Tilset的Libgdx AtlasTmxMapLoader

具有多个Tilset的Libgdx AtlasTmxMapLoader,libgdx,tiled,texturepacker,Libgdx,Tiled,Texturepacker,我正在开发一个加载平铺地图的Libgdx游戏。我正在绘制的当前地图使用了两个瓷砖集,一个用于阴影/灯光,另一个用于地形和建筑物。我所做的一般过程一直很好,就是从艺术家那里收到精灵表,设计地图,然后获取精灵表文件并使用ImageMagick分割它。从那里,我采取分割图像和创建一个优化的png和图集文件与TexturePacker 然而,这是我制作的第一张使用多个瓷砖集的地图。我遇到的问题是,当使用AtlasTmxMapLoader加载地图时,它依赖于地图中的单个atlas文件属性。我的阴影和照明被

我正在开发一个加载平铺地图的Libgdx游戏。我正在绘制的当前地图使用了两个瓷砖集,一个用于阴影/灯光,另一个用于地形和建筑物。我所做的一般过程一直很好,就是从艺术家那里收到精灵表,设计地图,然后获取精灵表文件并使用ImageMagick分割它。从那里,我采取分割图像和创建一个优化的png和图集文件与TexturePacker

然而,这是我制作的第一张使用多个瓷砖集的地图。我遇到的问题是,当使用AtlasTmxMapLoader加载地图时,它依赖于地图中的单个atlas文件属性。我的阴影和照明被分割成一个单独的图像和地图集,我宁愿不把它们全部合并成一个平铺的(并且必须重新绘制地图的一部分)


也许我错过了一些简单的东西。如何处理多个tileset?

我不是LibGDX专家,但我见过的几乎所有tilemap渲染器都依赖于使用1个tileset。原因是它们是使用OpenGL渲染的。渲染器设置纹理并使用1个绘制调用绘制所有平铺。你不能在两者之间切换纹理


最好的方法是创建两个(或更多)单独的层。每层使用1个瓷砖集。例如,1个用于背景,1个用于阴影,1个用于前景(例如墙)

因此,在深入了解.tmx文件的读取方式后,我能够解决我的问题

以下是在使用多个瓷砖集并在TexturePacker中重新打包SpriteSheet时如何正确执行此操作。首先,使用像ImageMagick这样的实用工具切割tileset图像,并确保它们已被索引(由文件名中的下划线和数字指定)。可以使用ImageMagick中的crop命令执行此操作,如下所示:

convert.exe“sires\u tileset.png”-裁剪16x16“sires\u tileset\u02d.png”

其次,将所有瓷砖集中的所有瓷砖重新打包到TexturePacker中的单个图集中。如果工作正常,您将在atlas文件中看到每个瓷砖集的名称,以及基于瓷砖id的关联索引。例如:

 shrine_tileset
  rotate: false
  xy: 382, 122
  size: 16, 16
  orig: 16, 16
  offset: 0, 0
  index: 703
最后(这是我无法理解的部分),确保每个tileset的tile索引都从.tmx文件中的“firstgid”值开始。例如,我的第二个tilesheet从2049开始,因为它们在第一张图纸中是2048个瓷砖。对于每个tileset,这应该在.tmx文件的顶部表示

<tileset firstgid="2049" source="shadow_light.tsx"/> 

因此,当为我的瓷砖集“shadow_light”切割瓷砖时,我会从索引2048开始,比gid少一个,例如:“shadow_light_2048.png”


希望这对某人有帮助

此问题已在1.9.11中修复。如果您使用的是早期版本,则可以使用修复程序覆盖AtlasTmxMapLoader

myatlastmxmmaploader.Java

import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.maps.ImageResolver;
import com.badlogic.gdx.maps.MapProperties;
import com.badlogic.gdx.maps.tiled.AtlasTmxMapLoader;
import com.badlogic.gdx.maps.tiled.TiledMapTile;
import com.badlogic.gdx.maps.tiled.TiledMapTileSet;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.GdxRuntimeException;
import com.badlogic.gdx.utils.SerializationException;
import com.badlogic.gdx.utils.XmlReader.Element;
public class MyAtlasTmxMapLoader extends AtlasTmxMapLoader {
       /**
        * Same as AtlasTmxMapLoader, but fixed to get the firstid attribute from  the tileset element in the TMX file, not tsx file.
        */
       @Override
       protected void loadTileSet(Element mapElement, FileHandle tmxFile,  ImageResolver imageResolver) {
              if (mapElement.getName().equals("tileset")) {
                     String imageSource = "";
                     int imageWidth = 0;
                     int imageHeight = 0;
                     FileHandle image = null;
                     Element element = null;
                     String source = mapElement.getAttribute("source", null);
                     if (source != null) {
                           FileHandle tsx = getRelativeFileHandle(tmxFile,  source);
                           try {
                                  element = xml.parse(tsx);
                                  Element imageElement =  element.getChildByName("image");
                                  if (imageElement != null) {
                                         imageSource =  imageElement.getAttribute("source");
                                         imageWidth =  imageElement.getIntAttribute("width", 0);
                                         imageHeight =  imageElement.getIntAttribute("height", 0);
                                         image = getRelativeFileHandle(tsx,  imageSource);
                                  }
                           } catch (SerializationException e) {
                                  throw new GdxRuntimeException("Error parsing  external tileset.");
                           }
                     } else {
                           Element imageElement =  mapElement.getChildByName("image");
                           if (imageElement != null) {
                                  imageSource =  imageElement.getAttribute("source");
                                  imageWidth =  imageElement.getIntAttribute("width", 0);
                                  imageHeight =  imageElement.getIntAttribute("height", 0);
                                  image = getRelativeFileHandle(tmxFile,  imageSource);
                           }
                     }
                     String name = element.get("name", null);
                     // Get the firstid attribute from the tileset element in the  TMX file, not tsx file.
                     int firstgid = mapElement.getIntAttribute("firstgid", 1);
                     int tilewidth = element.getIntAttribute("tilewidth", 0);
                     int tileheight = element.getIntAttribute("tileheight", 0);
                     int spacing = element.getIntAttribute("spacing", 0);
                     int margin = element.getIntAttribute("margin", 0);
                     Element offset = element.getChildByName("tileoffset");
                     int offsetX = 0;
                     int offsetY = 0;
                     if (offset != null) {
                           offsetX = offset.getIntAttribute("x", 0);
                           offsetY = offset.getIntAttribute("y", 0);
                     }
                     TiledMapTileSet tileSet = new TiledMapTileSet();
                     // TileSet
                     tileSet.setName(name);
                     final MapProperties tileSetProperties =  tileSet.getProperties();
                     Element properties = element.getChildByName("properties");
                     if (properties != null) {
                           loadProperties(tileSetProperties, properties);
                     }
                     tileSetProperties.put("firstgid", firstgid);
                     // Tiles
                     Array<Element> tileElements =  element.getChildrenByName("tile");
                     addStaticTiles(tmxFile, imageResolver, tileSet, element,  tileElements, name, firstgid, tilewidth,
                                  tileheight, spacing, margin, source, offsetX,  offsetY, imageSource, imageWidth, imageHeight, image);
                     for (Element tileElement : tileElements) {
                           int localtid = tileElement.getIntAttribute("id", 0);
                           TiledMapTile tile = tileSet.getTile(firstgid +  localtid);
                           if (tile != null) {
                                  addTileProperties(tile, tileElement);
                                  addTileObjectGroup(tile, tileElement);
                                  addAnimatedTile(tileSet, tile, tileElement,  firstgid);
                           }
                     }
                     map.getTileSets().addTileSet(tileSet);
              }
       }
}

来源:

请分享您的代码。谢谢您的回复。我不确定我是否完全理解。我的第二个瓷砖集实际上仅位于单独的贴图层(阴影/灯光层)上。我怎样才能将AtlasTmxMapLoader设置为两者都能使用?我想你不能(…但正如我已经说过的:我不是LibGDX专家)。您可以使用不同的地图集加载级别的2个实例(您可能需要修补tmx文件,或者以编程方式分配地图集)并覆盖它们。我的意思是:创建两个图层,将它们附加到同一父节点,并将它们显示为一个级别。这听起来会很混乱。但它确实让我思考。如果我能以某种方式将Texture Packer中的图像组合成一个可以与libgdxs平铺贴图渲染器一起使用的图集,那么一个图集就不是问题。如果平铺的名称与平铺集(和索引)相匹配,那么它应该可以工作。然而,我确实测试了它,它似乎没有画出我的阴影/灯光层。这肯定是件很平常的事,对吧?在任何大型地图上都有多个瓷砖集。我只是想避免在平铺中有一个平铺集。我不介意它被合并成一个外面的瓷砖。这对我来说在1.9.9,谢谢!在AtlasTmxMapLoader中,tileID的计算方法是:int tileID=firstgid+region.index,其中region.index是每个分割的tile后面的数字后缀。问题是libgdx正在从tsx文件而不是tmx文件读取firstgid,所以它将默认为1。所以OP的解决方案通过将后缀设为tileID-1来解决这个问题。
new MyAtlasTmxMapLoader().load(pathname)