Skip to content

Commit

Permalink
Add support for sometric staggered maps
Browse files Browse the repository at this point in the history
fixes #1893

Also fixes improper scaling on hexagonal maps.
Cleanup: use switch statement for size.
  • Loading branch information
jtmcdole committed Sep 10, 2022
1 parent 29bda33 commit 59293a7
Show file tree
Hide file tree
Showing 12 changed files with 323 additions and 37 deletions.
136 changes: 121 additions & 15 deletions packages/flame_tiled/lib/src/renderable_tile_map.dart
Original file line number Diff line number Diff line change
Expand Up @@ -261,12 +261,20 @@ class _RenderableTileLayer extends _RenderableLayer<TileLayer> {
}

void _cacheLayerTiles() {
if (_map.orientation == MapOrientation.isometric) {
_cacheIsometricTiles();
} else if (_map.orientation == MapOrientation.hexagonal) {
_cacheHexagonalTiles();
} else {
_cacheOrthogonalLayerTiles();
switch (_map.orientation) {
case MapOrientation.isometric:
_cacheIsometricTiles();
break;
case MapOrientation.staggered:
_cacheIsometricStaggeredTiles();
break;
case MapOrientation.hexagonal:
_cacheHexagonalTiles();
break;
case MapOrientation.orthogonal:
default:
_cacheOrthogonalLayerTiles();
break;
}
}

Expand Down Expand Up @@ -381,7 +389,7 @@ class _RenderableTileLayer extends _RenderableLayer<TileLayer> {
}
}

void _cacheHexagonalTiles() {
void _cacheIsometricStaggeredTiles() {
final tileData = layer.tileData!;
final batchMap = _cachedSpriteBatches;
final halfDestinationTile = _destTileSize / 2;
Expand All @@ -390,16 +398,114 @@ class _RenderableTileLayer extends _RenderableLayer<TileLayer> {

var staggerY = 0.0;
var staggerX = 0.0;
if (_map.orientation == MapOrientation.hexagonal) {
// Hexagonal Ponity Tiles move down by a fractional amount.
// Hexagonal Ponity Tiles move down by a fractional amount.
if (_map.staggerAxis == StaggerAxis.y) {
staggerY = size.y * 0.5;
} else
// Hexagonal Flat Tiles move right by a fractional amount.
if (_map.staggerAxis == StaggerAxis.x) {
staggerX = size.x * 0.5;
}

for (var ty = 0; ty < tileData.length; ty++) {
final tileRow = tileData[ty];

// Hexagonal Pointy Tiles shift left and right depending on the row
if (_map.staggerAxis == StaggerAxis.y) {
staggerY = _map.tileHeight * 0.75;
if ((ty.isOdd && _map.staggerIndex == StaggerIndex.odd) ||
(ty.isEven && _map.staggerIndex == StaggerIndex.even)) {
staggerX = halfDestinationTile.x;
} else {
staggerX = 0.0;
}
}
// Hexagonal Flat Tiles move right by a fractional amount.
if (_map.staggerAxis == StaggerAxis.x) {
staggerX = _map.tileWidth * 0.75;

for (var tx = 0; tx < tileRow.length; tx++) {
final tileGid = tileRow[tx];
if (tileGid.tile == 0) {
continue;
}

final tile = _map.tileByGid(tileGid.tile);
final tileset = _map.tilesetByTileGId(tileGid.tile);
final img = tile.image ?? tileset.image;
if (img == null) {
continue;
}

final batch = batchMap[img.source];
if (batch == null) {
continue;
}

// Hexagonal Flat tiles shift up and down as we move across the row.
if (_map.staggerAxis == StaggerAxis.x) {
if ((tx.isOdd && _map.staggerIndex == StaggerIndex.odd) ||
(tx.isEven && _map.staggerIndex == StaggerIndex.even)) {
staggerY = halfDestinationTile.y;
} else {
staggerY = 0.0;
}
}

final src = tileset.computeDrawRect(tile).toRect();
final flips = SimpleFlips.fromFlips(tileGid.flips);
final scale = size.x / src.width;
final anchorX = src.width - halfMapTile.x;
final anchorY = src.height - halfMapTile.y;

late double offsetX;
late double offsetY;

// halfTile.x: shfits the map half a tile forward rather than
// lining up on at the center.
// halfTile.y: shfits the map half a tile down rather than
// lining up on at the center.
// StaggerX/Y: Moves the tile forward/down depending on orientation.
// * stagger: Isometric tiles move down or right by only a fraction,
// specifically 1/2 the width or height, for packing.
if (_map.staggerAxis == StaggerAxis.y) {
offsetX = tx * size.x + staggerX + halfDestinationTile.x;
offsetY = ty * staggerY + halfDestinationTile.y;
} else {
offsetX = tx * staggerX + halfDestinationTile.x;
offsetY = ty * size.y + staggerY + halfDestinationTile.y;
}

final scos = flips.cos * scale;
final ssin = flips.sin * scale;

batch.addTransform(
source: src,
transform: ui.RSTransform(
scos,
ssin,
offsetX + -scos * anchorX + ssin * anchorY,
offsetY + -ssin * anchorX - scos * anchorY,
),
flip: flips.flip,
);
}
}
}

void _cacheHexagonalTiles() {
final tileData = layer.tileData!;
final batchMap = _cachedSpriteBatches;
final halfDestinationTile = _destTileSize / 2;
final size = _destTileSize;
final halfMapTile = Vector2(_map.tileWidth / 2, _map.tileHeight / 2);

var staggerY = 0.0;
var staggerX = 0.0;
// Hexagonal Ponity Tiles move down by a fractional amount.
if (_map.staggerAxis == StaggerAxis.y) {
staggerY = size.y * 0.75;
} else
// Hexagonal Flat Tiles move right by a fractional amount.
if (_map.staggerAxis == StaggerAxis.x) {
staggerX = size.x * 0.75;
}

for (var ty = 0; ty < tileData.length; ty++) {
final tileRow = tileData[ty];
Expand Down Expand Up @@ -459,11 +565,11 @@ class _RenderableTileLayer extends _RenderableLayer<TileLayer> {
// * stagger: Hexagonal tiles move down or right by only a fraction,
// specifically 3/4 the width or height, for packing.
if (_map.staggerAxis == StaggerAxis.y) {
offsetX = tx * _map.tileWidth + staggerX + halfDestinationTile.x;
offsetX = tx * size.x + staggerX + halfDestinationTile.x;
offsetY = ty * staggerY + halfDestinationTile.y;
} else {
offsetX = tx * staggerX + halfDestinationTile.x;
offsetY = ty * _map.tileHeight + staggerY + halfDestinationTile.y;
offsetY = ty * size.y + staggerY + halfDestinationTile.y;
}

final scos = flips.cos * scale;
Expand Down
50 changes: 28 additions & 22 deletions packages/flame_tiled/lib/src/tiled_component.dart
Original file line number Diff line number Diff line change
Expand Up @@ -63,35 +63,41 @@ class TiledComponent<T extends FlameGame> extends Component with HasGameRef<T> {
final xScale = tileMap.destTileSize.x / tMap.tileWidth;
final yScale = tileMap.destTileSize.y / tMap.tileHeight;

late Vector2 size;

final tileScaled = Vector2(
tileMap.map.tileWidth * xScale,
tileMap.map.tileHeight * yScale,
);

if (tMap.orientation == MapOrientation.hexagonal) {
if (tMap.staggerAxis == StaggerAxis.y) {
size = Vector2(
switch (tMap.orientation) {
case MapOrientation.staggered:
return tMap.staggerAxis == StaggerAxis.y
? Vector2(
tileScaled.x * tileMap.map.width + tileScaled.x / 2,
tileScaled.y + ((tileMap.map.height - 1) * tileScaled.y / 2),
)
: Vector2(
tileScaled.x + ((tileMap.map.width - 1) * tileScaled.x / 2),
tileScaled.y * tileMap.map.height + tileScaled.y / 2,
);

case MapOrientation.hexagonal:
return tMap.staggerAxis == StaggerAxis.y
? Vector2(
tileMap.map.width * tileScaled.x + tileScaled.x / 2,
tileScaled.y + ((tileMap.map.height - 1) * tileScaled.y * 0.75),
)
: Vector2(
tileScaled.x + ((tileMap.map.width - 1) * tileScaled.x * 0.75),
(tileMap.map.height * tileScaled.y) + tileScaled.y / 2,
);

case MapOrientation.isometric:
case MapOrientation.orthogonal:
default:
return Vector2(
tileMap.map.width * tileScaled.x,
tileScaled.y + ((tileMap.map.height - 1) * tileScaled.y * 0.75),
tileMap.map.height * tileScaled.y,
);
} else {
size = Vector2(
tileScaled.x + ((tileMap.map.width - 1) * tileScaled.x * 0.75),
(tileMap.map.height * tileScaled.y) + tileScaled.y / 2,
);
}
} else {
size = Vector2(
tileMap.map.width * tileScaled.x,
tileMap.map.height * tileScaled.y,
);
}

if (tMap.staggerAxis == StaggerAxis.y) {
size.x += tMap.tileWidth / 2;
}
return size;
}
}
Binary file added packages/flame_tiled/test/assets/iso_stag.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions packages/flame_tiled/test/assets/iso_stag_x_even.tmx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.9" tiledversion="1.9.1" orientation="staggered" renderorder="right-down" width="4" height="5" tilewidth="128" tileheight="74" infinite="0" staggeraxis="x" staggerindex="even" nextlayerid="3" nextobjectid="1">
<tileset firstgid="1" name="iso_stag" tilewidth="128" tileheight="74" tilecount="12" columns="4">
<image source="iso_stag.png" width="512" height="222"/>
</tileset>
<layer id="1" name="ground" width="4" height="5">
<data encoding="base64" compression="zlib">
eJxjZWBgYEXC7EDMCaVhYpxIbA4ozQjFrGgYABL4AGw=
</data>
</layer>
<layer id="2" name="stuff" width="4" height="5">
<data encoding="base64" compression="zlib">
eJxjYkAAbiBmYWBoYIHQDjBxIPsAjM2FRsPYbFAMAFTMAcg=
</data>
</layer>
</map>
16 changes: 16 additions & 0 deletions packages/flame_tiled/test/assets/iso_stag_x_odd.tmx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.9" tiledversion="1.9.1" orientation="staggered" renderorder="right-down" width="4" height="5" tilewidth="128" tileheight="74" infinite="0" staggeraxis="x" staggerindex="odd" nextlayerid="3" nextobjectid="1">
<tileset firstgid="1" name="iso_stag" tilewidth="128" tileheight="74" tilecount="12" columns="4">
<image source="iso_stag.png" width="512" height="222"/>
</tileset>
<layer id="2" name="ground" width="4" height="5">
<data encoding="base64" compression="zlib">
eJxjZWBgYEXDnEhsdigfRDNgUYuOARJUAGw=
</data>
</layer>
<layer id="1" name="stuff" width="4" height="5">
<data encoding="base64" compression="zlib">
eJxjYGBg4GKAACYozcKAAEB2AxAfAGIHBhwApI8bygYARcABqg==
</data>
</layer>
</map>
16 changes: 16 additions & 0 deletions packages/flame_tiled/test/assets/iso_stag_y_even.tmx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.9" tiledversion="1.9.1" orientation="staggered" renderorder="right-down" width="4" height="5" tilewidth="128" tileheight="74" infinite="0" staggeraxis="y" staggerindex="even" nextlayerid="3" nextobjectid="1">
<tileset firstgid="1" name="iso_stag" tilewidth="128" tileheight="74" tilecount="12" columns="4">
<image source="iso_stag.png" width="512" height="222"/>
</tileset>
<layer id="1" name="ground" width="4" height="5">
<data encoding="base64" compression="zlib">
eJxjZGBgYIRiDijNjsTnBGJWJBokzoykBx0DAAyAAEM=
</data>
</layer>
<layer id="2" name="floor" width="4" height="5">
<data encoding="base64" compression="zlib">
eJxjYkAAbgZUAOMzMTA0sDFgByxIbC4gBgAcSACv
</data>
</layer>
</map>
16 changes: 16 additions & 0 deletions packages/flame_tiled/test/assets/iso_stag_y_odd.tmx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.9" tiledversion="1.9.1" orientation="staggered" renderorder="right-down" width="4" height="5" tilewidth="128" tileheight="74" infinite="0" staggeraxis="y" staggerindex="odd" nextlayerid="3" nextobjectid="1">
<tileset firstgid="1" name="iso_stag" tilewidth="128" tileheight="74" tilecount="12" columns="4">
<image source="iso_stag.png" width="512" height="222"/>
</tileset>
<layer id="1" name="ground" width="4" height="5">
<data encoding="base64" compression="zlib">
eJxjZGBgYIRiDijNjsTnBGJWJBokzoykBx0DAAyAAEM=
</data>
</layer>
<layer id="2" name="floor" width="4" height="5">
<data encoding="base64" compression="zlib">
eJxjYkAAbgZUAOMzMTA0sDFgByxIbC4gBgAcSACv
</data>
</layer>
</map>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 59293a7

Please sign in to comment.