How to create unique tile ID's

Hi,

After a bit of digging, I found that you can make each tile have a unique ID (for exporting to a .csv) by adding a ‘name’ attribute to each tile. This is tedious and takes forever to add a distinct number to each name attribute. Is there an easier way?

The name replaces the ID and is used when you want non-numerical ID. If you don’t input a name, its numerical ID (defined by Tiled) will be output instead.

Something else to consider: if you output names, you’ll not get tile flipping information in the output. If you want that, you have to let Tiled use its IDs.

The problem with using the default ID’s is that they are not unique, there will be multiple tiles of the same ID from different tilesheets. This is obviously not an option.

Ah, it seems you are correct. The reason for this is that the CSV plugin was designed with a single tileset in mind and is not meant for maps with multiple tilesets. Normally, the tile IDs Tiled outputs are unique, as they include an offset that is unique to each tileset, allowing you to identify the tileset each tile belongs to. You would need extra metadata to tell you which tileset is which, though, as the tileset order is not guaranteed within Tiled. TMX files contain this data, the CSV output does not.

Here’s a script I wrote that lets you export CSV with global IDs. It adds a “CSV with GIDs” option in your export formats. Note that since these are TMX-style GIDs, 0 now means “no tile”, and the actual tile IDs start at 1. To help identify the tilesets used, it also outputs a MapName_tilesets.csv file, which lists firstgid, "tileset location" pairs, one per row, in increasing order of firstgid. To match the tiles to their tileset, check their ID against this list, their tileset will be the one with the largest firstgid that’s less than or equal to the tile’s global ID. It also numbers the outputted layer CSVs so that you know the layer order in addition to the layer names.
Caveat: It does not currently support grouped layers, because Tiled’s scripting API does not yet have a convenient way to access them. If you need group support, let me know and I can add it (it can be done, it’s just tedious work I’d rather avoid if it’s not needed).

var customMapFormat = {
    name = "CSV with GIDs",
    extension = "csv",
    
    write: function(map, fileName) {
		//Assign firstgids to each tileset:
		var firstgids = [];
		var tilesets = map.tilesets;
		firstgids[0] = 1;
		for(var i = 1; i < tilesets.length; i++) {
			firstgids[i] = firstgids[i-1] + tilesets[i-1].tileCount;
		}
		
		var prefix = fileName.search(".csv");
		if(prefix >= 0) prefix = fileName.substr(0, prefix);
		else prefix = fileName;
		var numLayers = 0;
		for (var i = 0; i < map.layerCount; ++i) {
            var curLayer = map.layerAt(i);
            if (curLayer.isTileLayer) {
				var file = new TextFile(prefix+"_"+numLayers+"_"+curLayer.name+".csv", TextFile.WriteOnly);
				var output;
                for (y = 0; y < curLayer.height; ++y) {
                    output = "";
                    for (x = 0; x < curLayer.width; ++x) {
						if(x > 0) output += ",";

						var cell = curLayer.cellAt(x, y);
						var tile = cell.tileId;

						var tileset = curLayer.tileAt(x, y);
						if(tileset) {
							tileset = tileset.tileset;
							//add the firstgid for this tile's tileset:
							tileset = tilesets.indexOf(tileset);
							if(tileset >= 0)
								tile += firstgids[tileset];

							if(cell.flippedHorizontally) tile = tile | 0x80000000;
							if(cell.flippedVertically) tile = tile | 0x40000000;
							if(cell.flippedAntiDiagonally) tile = tile | 0x20000000;
							if(cell.rotatedHexagonal120) tile = tile | 0x10000000;
						} else tile = 0;
                        output += tile;
					}
					file.writeLine(output);
                }
				file.commit();
				numLayers++;
            }
        }
		//Output a metadata file with what each tileset is:
		var file = new TextFile(prefix+"_tilesets.csv", TextFile.WriteOnly);
		var output = '';
		for(i = 0; i < tilesets.length; i++) {
			output += firstgids[i] + ', "' + tilesets[i].fileName + '"\n';
		}
		file.writeLine(output);
		file.commit();
	}
}

tiled.registerMapFormat("CSV with GIDs", customMapFormat);
1 Like

At the moment the CSV export basically does not support the use of multiple tilesets on the same layer, since indeed there’s no way to tell them apart. The other formats solve this by including the list of tilesets and a “first global tile ID” value for each tileset.

If you’re using multiple tilesets but still would like to use the CSV export, please consider also how you’d expect this to be supported. Also, you may want to consider alternatives to using the CSV format:

  • You could use the JSON export, which is generally easy to parse in any language, includes the tile layer data pretty much in a CSV format but supporting multiple tilesets by using global tile IDs.

  • If you really need a CSV-like format but have some custom approach in mind for supporting multiple tilesets, consider writing a bit of JavaScript to export the map in this format. It’s not hard to extend Tiled with a custom format.

Edit: Oops, @eishiya was a little bit faster with a rather more helpful reply. ^^

Although I posted a janky script for it, I’d still also encourage OP to use another format. CSV is just not a good format for multi-layer, multi-tileset map data because of all the extra metadata involved.