Skip to content

Commit

Permalink
fix: [#443] Fix Tiled tilesets with margin/spacing defined (#444)
Browse files Browse the repository at this point in the history
Closes #443 

TODO:
* [x] Tests


Tiled and Excalibur use the same words for different things 🤦
 * Tiled tileset `margin` is the same as Excalibur's `SpriteSheet.originOffset`
 * Tiled tileset `spacing` is the same as Excalibur's `SpriteSheet.margin`

Uploaded a Tiled example that demonstrates this in the plugin

<img width="320" alt="image" src="https://github.com/excaliburjs/excalibur-tiled/assets/612071/60844efe-929a-438a-9ea5-01540130d99c">

<img width="414" alt="image" src="https://github.com/excaliburjs/excalibur-tiled/assets/612071/f3daa2e1-fd2d-487e-b2bb-2146c5002933">
  • Loading branch information
eonarheim authored Jun 29, 2023
1 parent b28d5ab commit 0fe3031
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 0 deletions.
Binary file added example/assets/margin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions example/game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,26 @@ const start = (mapFile: string) => {

(window as any).map = map;
game.start(loader).then(() => {

game.input.pointers.primary.on('down', evt => {
// ex TileMap data structure by name
const tilemap = map.getTileMapLayers().filter(tm => tm.name === 'Ground')[0];
const tile = tilemap.getTileByPoint(evt.worldPos);
const tileIndex = tilemap.tiles.indexOf(tile);

// Tiled data
// gid can be found by looking up the original data, locate layer by name
const tiledLayer = map.data.getTileLayerByName('Ground');
const tileGid = tiledLayer.data[tileIndex];

// tileset properties
const tiledTileset = map.getTilesetForTile(tileGid);
// odd quirk of Tiled's data the gid's here are off by 1 from the data array :/
const tiledTile = tiledTileset.tiles.find(t => t.id === (tileGid - 1));
console.log('gid', tileGid);
console.log('tile props', tiledTile?.properties);
});

player.pos = ex.vec(100, 100);
if (isIsometric) {
player.graphics.use(playercube.toSprite());
Expand All @@ -103,6 +123,8 @@ const start = (mapFile: string) => {
if (start) {
player.pos.x = start.x;
player.pos.y = start.y;
console.log("player start", start.x, start.y);
console.log("props:" , start.getProperty<number>("Custom Prop"));
}

// Use polyline for patrols
Expand Down
1 change: 1 addition & 0 deletions example/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

<select id="select-map" name="select-map">
<option value="example-city.tmx">tmx</option>
<option value="margin.tmx">margin.tmx</option>
<option value="example-isometric.tmx">isometric</option>
<option value="example-city-external-tsx.tmx">tmx external tsx</option>
<option value="example-city-base64.tmx">tmx base64</option>
Expand Down
30 changes: 30 additions & 0 deletions example/margin.tmx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="30" height="20" tilewidth="10" tileheight="10" infinite="0" nextlayerid="2" nextobjectid="1">
<tileset firstgid="1" name="margin" tilewidth="10" tileheight="10" spacing="10" margin="10" tilecount="100" columns="10">
<image source="assets/margin.png" width="200" height="200"/>
</tileset>
<layer id="1" name="Tile Layer 1" width="30" height="20">
<data encoding="csv">
1,2,1,2,1,2,1,2,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11,12,11,12,11,12,11,12,11,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,2,1,2,1,2,1,2,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11,12,11,12,11,12,11,12,11,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,2,1,2,1,2,1,2,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11,12,11,12,11,12,11,12,11,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,2,1,2,1,2,1,2,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11,12,11,12,11,12,11,12,11,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,2,1,2,1,2,1,2,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11,12,11,12,11,12,11,12,11,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
</data>
</layer>
</map>
7 changes: 7 additions & 0 deletions src/tiled-map-resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,9 @@ export class TiledMapResource implements Loadable<TiledMap> {
const rows = Math.floor((tileset.imageheight + spacing) / (tileset.tileheight + spacing));
// Single image tilesets
if (this.imageMap[tileset.firstgid]) {
// Tiled and Excalibur use the same words for different things :facepalm:
// Tiled margin is the same as Excalibur originOffset
// Tiled spacing is the same as Excalibur margin
const ss = SpriteSheet.fromImageSource({
image: this.imageMap[tileset.firstgid],
grid: {
Expand All @@ -582,6 +585,10 @@ export class TiledMapResource implements Loadable<TiledMap> {
spriteHeight: tileset.tileheight
},
spacing: {
originOffset: {
x: tileset.margin ?? 0,
y: tileset.margin ?? 0
},

This comment has been minimized.

Copy link
@max-vogler

max-vogler Jun 29, 2023

Thank you so much for the quick fix. I think there might still be a bug if I understand the code correctly:

  • Tiled margin seems to be applied to all 4 sides - top, left, bottom, right.
  • Excalibur's originOffset is only applied to top and left.

In your example, both Tiled spacing and margin are 10px, so there is no difference in behavior. If they were different, Excalibur would not apply the Tiled margin on the right and bottom side, potentially allocating too many sprites per row?

This comment has been minimized.

Copy link
@eonarheim

eonarheim Jun 30, 2023

Author Member

@max-vogler Those are good points, I'll look into that

margin: {
x: tileset.spacing ?? 0,
y: tileset.spacing ?? 0,
Expand Down
1 change: 1 addition & 0 deletions test/integration/ex-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ test('Tiled Tests', async (page) => {
}

const legacyMapTypes = [
'margin.tmx',
'v1',
'v1 external tileset',
'v0 gzip',
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 0fe3031

Please sign in to comment.