Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add isometric support for flame_tiled #1885

Merged
merged 3 commits into from
Sep 5, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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