diff --git a/packages/flame_tiled/lib/src/renderable_layers/image_layer.dart b/packages/flame_tiled/lib/src/renderable_layers/image_layer.dart index 16f8e9cf3f0..e15e1385353 100644 --- a/packages/flame_tiled/lib/src/renderable_layers/image_layer.dart +++ b/packages/flame_tiled/lib/src/renderable_layers/image_layer.dart @@ -14,8 +14,8 @@ class FlameImageLayer extends RenderableLayer { final Image _image; late final ImageRepeat _repeat; final MutableRect _paintArea = MutableRect.fromLTRB(0, 0, 0, 0); - final Vector2 _canvasSize = Vector2.zero(); final Vector2 _maxTranslation = Vector2.zero(); + late final Vector2 _mapSize; FlameImageLayer({ required super.layer, @@ -25,13 +25,15 @@ class FlameImageLayer extends RenderableLayer { required Image image, super.filterQuality, }) : _image = image { + _mapSize = Vector2( + map.width * destTileSize.x, + map.height * destTileSize.y, + ); _initImageRepeat(); } @override - void handleResize(Vector2 canvasSize) { - _canvasSize.setFrom(canvasSize); - } + void handleResize(Vector2 canvasSize) {} @override void render(Canvas canvas, CameraComponent? camera) { @@ -79,20 +81,22 @@ class FlameImageLayer extends RenderableLayer { // it still matches up with its initial layer offsets. if (_repeat == ImageRepeat.repeatX || _repeat == ImageRepeat.repeat) { - final xImages = (_maxTranslation.x / _image.size.x).ceil(); + // Calculate images needed for max translation and map size + final xImages = ((_maxTranslation.x + _mapSize.x) / _image.size.x).ceil(); _paintArea.left = -_image.size.x * xImages; - _paintArea.right = _canvasSize.x + _image.size.x * xImages; + _paintArea.right = _image.size.x * xImages; } else { _paintArea.left = 0; - _paintArea.right = _canvasSize.x; + _paintArea.right = _mapSize.x; } if (_repeat == ImageRepeat.repeatY || _repeat == ImageRepeat.repeat) { - final yImages = (_maxTranslation.y / _image.size.y).ceil(); + // Calculate images needed for max translation and map size + final yImages = ((_maxTranslation.y + _mapSize.y) / _image.size.y).ceil(); _paintArea.top = -_image.size.y * yImages; - _paintArea.bottom = _canvasSize.y + _image.size.y * yImages; + _paintArea.bottom = _image.size.y * yImages; } else { _paintArea.top = 0; - _paintArea.bottom = _canvasSize.y; + _paintArea.bottom = _mapSize.y; } } diff --git a/packages/flame_tiled/test/assets/image_layer_full_screen.tmx b/packages/flame_tiled/test/assets/image_layer_full_screen.tmx new file mode 100644 index 00000000000..ebedfb6e649 --- /dev/null +++ b/packages/flame_tiled/test/assets/image_layer_full_screen.tmx @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/flame_tiled/test/goldens/image_layer_covers_map.png b/packages/flame_tiled/test/goldens/image_layer_covers_map.png new file mode 100644 index 00000000000..a6223ecd778 Binary files /dev/null and b/packages/flame_tiled/test/goldens/image_layer_covers_map.png differ diff --git a/packages/flame_tiled/test/image_layer_test.dart b/packages/flame_tiled/test/image_layer_test.dart new file mode 100644 index 00000000000..47ff28d78ab --- /dev/null +++ b/packages/flame_tiled/test/image_layer_test.dart @@ -0,0 +1,54 @@ +import 'package:flame/cache.dart'; +import 'package:flame/game.dart'; +import 'package:flame_tiled/flame_tiled.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'test_asset_bundle.dart'; +import 'test_image_utils.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + setUp(TiledAtlas.atlasMap.clear); + + group('ImageLayer rendering', () { + test( + 'image layer covers entire map', + () async { + final bundle = TestAssetBundle( + imageNames: [ + 'Tileset_Hexagonal_PointyTop_60x52_60x80.png', + 'images/gear.png', + 'green_sprite.png', + 'red_sprite.png', + ], + stringNames: ['image_layer_full_screen.tmx'], + ); + + final component = await TiledComponent.load( + 'image_layer_full_screen.tmx', + Vector2.all(16), + bundle: bundle, + images: Images(bundle: bundle), + ); + + // The map is 15x15 tiles at 16x16, so the total size is 240x240 + expect(component.size, Vector2(240, 240)); + + // Initialize game context + final game = FlameGame(); + game.onGameResize(component.size); + game.world.add(component); + await component.onLoad(); + await game.ready(); + + final pngData = await renderMapToPng(component); + + expect( + pngData, + matchesGoldenFile('goldens/image_layer_covers_map.png'), + ); + }, + ); + }); +}