Libgdx 具有多个倾斜集的 AtlasTmxMapLoader

Libgdx AtlasTmxMapLoader with multiple tilsets

我正在开发一款加载 Tiled 地图的 Libgdx 游戏。我正在处理的当前地图使用了 2 个图块集,一个用于 shadow/light,另一个用于地形和建筑物。我所做的一般过程一直运行良好,是我从艺术家那里收到精灵 sheet,设计地图,然后获取精灵 sheet 文件并使用 ImageMagick 将其拆分。从那里我获取分割图像并使用 TexturePacker 创建优化的 png 和 atlas 文件。

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

也许我遗漏了一些简单的东西。我如何处理多个图块集?

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

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

因此,在详细了解如何读取 .tmx 文件后,我能够解决我的问题。

以下是在使用多个图块集并在 TexturePacker 中重新打包您的 spritesheet 时如何正确执行此操作。首先,使用像 ImageMagick 这样的实用程序切割 tileset 图像并确保它们被索引(由文件名中的下划线和数字指定)。您可以像这样使用 ImageMagick 中的裁剪命令执行此操作:

convert.exe "shrine_tileset.png" -crop 16x16 "shrine_tileset_%02d.png"

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

 shrine_tileset
  rotate: false
  xy: 382, 122
  size: 16, 16
  orig: 16, 16
  offset: 0, 0
  index: 703

最后(这是我无法弄清楚的部分),确保每个 tileset 的 tile 索引从 .tmx 文件中的 "firstgid" 值开始。例如,我的第二个瓷砖 sheet 从 2049 开始,因为它们在第一个 sheet 中是 2048 个瓷砖。这应该在每个 tileset 的 .tmx 文件的顶部指出。

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

因此,在为我的 tileset "shadow_light" 切割图块时,我会从索引 2048 开始,比 gid 小 1,例如:"shadow_light_2048.png".

希望这对某人有所帮助!

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

MyAtlasTmxMapLoader.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);
              }
       }
}

然后调用:

new MyAtlasTmxMapLoader().load(pathname)

来源:[Tutorial] Using multiple Tilesets with Libgdx and Tiled