【问题标题】:Libgdx AtlasTmxMapLoader with multiple tilsets具有多个 tilset 的 Libgdx AtlasTmxMapLoader
【发布时间】:2023-04-08 08:44:02
【问题描述】:

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

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

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

【问题讨论】:

  • 请分享你的代码。

标签: libgdx tiled texturepacker


【解决方案1】:

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

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

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

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

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

最后(这是我想不通的部分),确保每个图块集的图块索引从 .tmx 文件中的“firstgid”值开始。例如,我的第二个 tilesheet 从 2049 开始,因为它们是第一个工作表中的 2048 个图块。这应该在每个图块集的 .tmx 文件的顶部表示。

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

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

希望这对某人有所帮助!

【讨论】:

  • 这在 1.9.9 中对我有用,谢谢! tileID 在 AtlasTmxMapLoader 中通过以下方式计算:int tileId = firstgid + region.index,其中 region.index 是每个切割瓷砖后面的数字后缀。问题是 libgdx 是从 tsx 文件中读取 firstgid,而不是 tmx 文件,所以它只会默认为 1。所以 OP 的解决方案通过将后缀设为 tileID-1 来解决这个问题。
【解决方案2】:

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

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

【讨论】:

  • 感谢您的回复。我不确定我是否完全理解。我的第二个图块集实际上仅在单独的地图层(阴影/光层)上。如何设置 AtlasTmxMapLoader 以同时使用两者?
  • 我认为你不能(...但正如我已经说过的:我不是 LibGDX 专家)。您可能能够使用不同的图集加载关卡的 2 个实例(您可能需要修补 tmx 文件 - 或以编程方式分配图集)并覆盖它们。对于叠加层,我的意思是:创建 2 个图层,将它们附加到同一个父节点并像显示它们一样显示它们。
  • 这听起来会很混乱。但这确实让我思考。如果我能以某种方式将 Texture Packer 中的图像组合成一个可以与 libgdxs 平铺地图渲染器一起使用的地图集,那么一个地图集就不是问题。如果瓦片的名称相应地匹配瓦片集(和索引),它应该可以工作。但是,我确实对此进行了测试,但它似乎没有绘制我的阴影/光层。这一定是一件普遍的事情,对吧?在任何大地图上都会给出多个图块集。我只是想避免在 Tiled 中有一个单独的图块集。我不介意将它合并到 Tiled 之外。
【解决方案3】:

此问题已在 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

【讨论】:

    猜你喜欢
    • 2013-03-07
    • 2017-09-30
    • 2019-01-08
    • 2019-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-14
    • 2014-05-15
    相关资源
    最近更新 更多