Skip to content

Commit 9a7bdc7

Browse files
authored
fix!: Update IsometricTileMapComponent to have better defined position and size (#3142)
Update IsometricTileMapComponent to have better defined position and size. Before, the isometric component "zero" would be the center of the 0,0 block. However, that does not play nicely with our component system if you want to know the size (i.e. bounding box) of a component. This changes so that the 0,0 of the component is the 0,0 of the AABB around the isometric tiles. Then, it also computes the size of the component accordingly. This also changes the example to allow toggling between half and full size more easily. In our example, this is what it looks like: ![image](https://github.com/flame-engine/flame/assets/882703/6e3d6bb5-ff66-4923-9c66-2f0794fd3eab) The example still shows how to compute the previous origin (the purple dot) if you want to. With full size blocks: ![image](https://github.com/flame-engine/flame/assets/882703/485dbffc-51a8-46f5-a125-6f12cce5b35e) This is a minor breaking change as you might need to "reposition" your tile components, essentially remove the "compensation" for its location that you probably did yourself. If you were centering the tile component based on the available methods such as `map.getBlockCenterPosition`, then just make sure you are adding the `map.position` to that and it should work as before.
1 parent 6e80bf5 commit 9a7bdc7

File tree

4 files changed

+45
-11
lines changed

4 files changed

+45
-11
lines changed

examples/lib/stories/rendering/isometric_tile_map_example.dart

+6-6
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,17 @@ class IsometricTileMapExample extends FlameGame with MouseMovementDetector {
1919
static const srcTileSize = 32.0;
2020
static const destTileSize = scale * srcTileSize;
2121

22-
static const halfSize = true;
23-
static const tileHeight = scale * (halfSize ? 8.0 : 16.0);
24-
static const suffix = halfSize ? '-short' : '';
25-
2622
final originColor = Paint()..color = const Color(0xFFFF00FF);
2723
final originColor2 = Paint()..color = const Color(0xFFAA55FF);
2824

25+
final bool halfSize;
26+
late final tileHeight = scale * (halfSize ? 8.0 : 16.0);
27+
late final suffix = halfSize ? '-short' : '';
28+
2929
late IsometricTileMapComponent base;
3030
late Selector selector;
3131

32-
IsometricTileMapExample();
32+
IsometricTileMapExample({required this.halfSize});
3333

3434
@override
3535
Future<void> onLoad() async {
@@ -65,7 +65,7 @@ class IsometricTileMapExample extends FlameGame with MouseMovementDetector {
6565
super.render(canvas);
6666
canvas.renderPoint(topLeft, size: 5, paint: originColor);
6767
canvas.renderPoint(
68-
topLeft.clone()..y -= tileHeight,
68+
base.position + base.getBlockCenterPosition(const Block(0, 0)),
6969
size: 5,
7070
paint: originColor2,
7171
);

examples/lib/stories/rendering/rendering.dart

+5-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ void addRenderingStories(Dashbook dashbook) {
2121
)
2222
..add(
2323
'Isometric Tile Map',
24-
(_) => GameWidget(game: IsometricTileMapExample()),
24+
(context) => GameWidget(
25+
game: IsometricTileMapExample(
26+
halfSize: context.boolProperty('Half size', true),
27+
),
28+
),
2529
codeLink: baseLink('rendering/isometric_tile_map_example.dart'),
2630
info: IsometricTileMapExample.description,
2731
)

packages/flame/lib/src/components/isometric_tile_map_component.dart

+31-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'dart:math';
12
import 'dart:ui';
23

34
import 'package:flame/components.dart';
@@ -57,6 +58,10 @@ class IsometricTileMapComponent extends PositionComponent {
5758
/// Where the tileset's image is stored.
5859
Sprite _renderSprite;
5960

61+
/// Displacement applied so that the origin of the component
62+
/// matches the origin of the AABB.
63+
final Vector2 _offset = Vector2.zero();
64+
6065
IsometricTileMapComponent(
6166
this.tileset,
6267
this.matrix, {
@@ -70,7 +75,9 @@ class IsometricTileMapComponent extends PositionComponent {
7075
super.children,
7176
super.priority,
7277
super.key,
73-
}) : _renderSprite = Sprite(tileset.image);
78+
}) : _renderSprite = Sprite(tileset.image) {
79+
_recomputeSizeAndOffset();
80+
}
7481

7582
/// This is the size the tiles will be drawn (either original or overwritten).
7683
Vector2 get effectiveTileSize => destTileSize ?? tileset.srcSize;
@@ -101,6 +108,11 @@ class IsometricTileMapComponent extends PositionComponent {
101108
}
102109
}
103110

111+
@override
112+
void update(double dt) {
113+
_recomputeSizeAndOffset();
114+
}
115+
104116
/// Get the position in which a block is rendered in, in the isometric space.
105117
///
106118
/// This does not include the (x,y) PositionComponent offset!
@@ -124,7 +136,9 @@ class IsometricTileMapComponent extends PositionComponent {
124136
final cartesianPosition = _cartesianPositionCache
125137
..setValues(i.toDouble(), j.toDouble())
126138
..multiply(halfTile);
127-
return cartToIso(cartesianPosition)..sub(halfTile);
139+
return cartToIso(cartesianPosition)
140+
..add(_offset)
141+
..sub(halfTile);
128142
}
129143

130144
/// Get the position of the center of the surface of the isometric tile in
@@ -168,6 +182,7 @@ class IsometricTileMapComponent extends PositionComponent {
168182
final multiplier = 1 - halfTile.y / (2 * effectiveTileHeight * scale.x);
169183
final iso = _getBlockIsoCache
170184
..setFrom(p)
185+
..sub(_offset)
171186
..sub(position)
172187
..translate(halfTile.x, halfTile.y * multiplier);
173188
final cart = isoToCart(iso);
@@ -210,4 +225,18 @@ class IsometricTileMapComponent extends PositionComponent {
210225
block.x >= 0 &&
211226
block.x < matrix[block.y].length;
212227
}
228+
229+
void _recomputeSizeAndOffset() {
230+
final width = matrix.fold<int>(
231+
0,
232+
(previousValue, element) => max(previousValue, element.length),
233+
);
234+
final height = matrix.length;
235+
236+
size.x = effectiveTileSize.x * width;
237+
size.y = effectiveTileSize.y * height / 2 + effectiveTileHeight;
238+
239+
_offset.x = size.x / 2;
240+
_offset.y = effectiveTileHeight;
241+
}
213242
}

packages/flame/test/components/isometric_tile_map_component_test.dart

+3-2
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ void main() {
6565

6666
expect(
6767
c.getBlockCenterPosition(const Block(0, 0)),
68-
closeToVector(Vector2.zero()),
68+
closeToVector(Vector2(32, 8)),
6969
);
7070
});
7171

@@ -77,9 +77,10 @@ void main() {
7777
destTileSize: tileSize,
7878
);
7979
//expect the block to be directly below
80+
final blockAbove = c.getBlockRenderPositionInts(0, 0);
8081
expect(
8182
c.getBlockRenderPositionInts(1, 1),
82-
closeToVector(Vector2(-156 / 2, 12.5), 1e-13),
83+
closeToVector(blockAbove + Vector2(0, 181 / 2), 1e-13),
8384
);
8485
});
8586
});

0 commit comments

Comments
 (0)