Skip to content

Commit

Permalink
feat: Add isometric support for flame_tiled (#1885)
Browse files Browse the repository at this point in the history
    Updates some forEach to regular for() loops
    Adds golden test with license free tilemaps
  • Loading branch information
jtmcdole authored Sep 5, 2022
1 parent 6db519e commit cf82882
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 31 deletions.
76 changes: 47 additions & 29 deletions packages/flame_tiled/lib/src/renderable_tile_map.dart
Original file line number Diff line number Diff line change
Expand Up @@ -258,41 +258,59 @@ class _RenderableTileLayer extends _RenderableLayer<TileLayer> {
void _cacheLayerTiles() {
final tileData = layer.tileData!;
final batchMap = _cachedSpriteBatches;
tileData.asMap().forEach((ty, tileRow) {
tileRow.asMap().forEach((tx, tileGid) {
final halfTile = _destTileSize / 2;
for (var ty = 0; ty < tileData.length; ty++) {
final tileRow = tileData[ty];
for (var tx = 0; tx < tileRow.length; tx++) {
final tileGid = tileRow[tx];
if (tileGid.tile == 0) {
return;
continue;
}

final tile = _map.tileByGid(tileGid.tile);
final tileset = _map.tilesetByTileGId(tileGid.tile);
final img = tile.image ?? tileset.image;
if (img != null) {
final batch = batchMap[img.source];
final src = tileset.computeDrawRect(tile).toRect();
final flips = SimpleFlips.fromFlips(tileGid.flips);
final size = _destTileSize;
final scale = size.x / src.width;
final anchorX = src.width / 2;
final anchorY = src.height / 2;
final offsetX = ((tx + .5) * size.x) + (layer.offsetX * scale);
final offsetY = ((ty + .5) * size.y) + (layer.offsetY * scale);
final scos = flips.cos * scale;
final ssin = flips.sin * scale;
if (batch != null) {
batch.addTransform(
source: src,
transform: ui.RSTransform(
scos,
ssin,
offsetX + -scos * anchorX + ssin * anchorY,
offsetY + -ssin * anchorX - scos * anchorY,
),
flip: flips.flip,
);
}
if (img == null) {
continue;
}
});
});

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

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

late double offsetX;
late double offsetY;
if (_map.orientation == MapOrientation.isometric) {
offsetX = halfTile.x * (tx - ty);
offsetY = halfTile.y * (tx + ty);
} else {
offsetX = (tx + .5) * size.x;
offsetY = (ty + .5) * size.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,
);
}
}
}

@override
Expand Down
2 changes: 2 additions & 0 deletions packages/flame_tiled/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ dependencies:
dev_dependencies:
dartdoc: ^6.0.1
flame_lint: ^0.1.2
flutter_test:
sdk: flutter
test: any
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/test_isometric.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="isometric" renderorder="right-down" width="5" height="5" tilewidth="128" tileheight="64" infinite="0" nextlayerid="4" nextobjectid="1">
<tileset firstgid="1" name="isometric_spritesheet" tilewidth="128" tileheight="256" tilecount="4" columns="1">
<image source="isometric_spritesheet.png" width="128" height="1024"/>
</tileset>
<layer id="1" name="ground" width="5" height="5">
<data encoding="base64">
AgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAQAAAACAAAAAwAAAAMAAAACAAAAAwAAAAIAAAADAAAAAgAAAAIAAAAEAACAAgAAAAMAAAACAAAAAwAAAAIAAAACAAAAAgAAAA==
</data>
</layer>
<layer id="2" name="item" width="5" height="5">
<data encoding="base64">
AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAACAAAAAAAAAAAAAAAAAAAAAAA==
</data>
</layer>
</map>
Binary file added packages/flame_tiled/test/goldens/isometric.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
39 changes: 37 additions & 2 deletions packages/flame_tiled/test/tiled_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'dart:ui';
Expand All @@ -7,7 +6,7 @@ import 'package:flame/extensions.dart';
import 'package:flame/flame.dart';
import 'package:flame_tiled/flame_tiled.dart';
import 'package:flutter/services.dart' show CachingAssetBundle;
import 'package:test/test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:tiled/tiled.dart';

void main() {
Expand Down Expand Up @@ -264,6 +263,42 @@ void main() {
);
});
});

group('isometric', () {
late Uint8List pngData;
late RenderableTiledMap overlapMap;

test('renders', () async {
Flame.bundle = TestAssetBundle(
imageNames: [
'isometric_spritesheet.png',
],
mapPath: 'test/assets/test_isometric.tmx',
);
overlapMap = await RenderableTiledMap.fromFile(
'test_isometric.tmx',
Vector2(256 / 4, 128 / 4),
);

final canvasRecorder = PictureRecorder();
final canvas = Canvas(canvasRecorder);
// Isometric maps are centered with tile(0,0) being at the top.
// So translate the canvas halfway.
canvas.translate((256 * 5) / 4 / 2, 0);
overlapMap.render(canvas);
final picture = canvasRecorder.endRecording();

// Map size is now 320 wide, but it has 1 extra tile of height becusae
// its actually double-height tiles.
final image =
await picture.toImageSafe(256 * 5 ~/ 4, (128 * 5 + 128) ~/ 4);
pngData = (await image.toByteData(format: ImageByteFormat.png))!
.buffer
.asUint8List();

expect(pngData, matchesGoldenFile('goldens/isometric.png'));
});
});
}

class TestAssetBundle extends CachingAssetBundle {
Expand Down

0 comments on commit cf82882

Please sign in to comment.