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