Skip to content

Commit

Permalink
fix!: Update IsometricTileMapComponent to have better defined positio…
Browse files Browse the repository at this point in the history
…n 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.
  • Loading branch information
luanpotter authored Apr 29, 2024
1 parent 6e80bf5 commit 9a7bdc7
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 11 deletions.
12 changes: 6 additions & 6 deletions examples/lib/stories/rendering/isometric_tile_map_example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,17 @@ class IsometricTileMapExample extends FlameGame with MouseMovementDetector {
static const srcTileSize = 32.0;
static const destTileSize = scale * srcTileSize;

static const halfSize = true;
static const tileHeight = scale * (halfSize ? 8.0 : 16.0);
static const suffix = halfSize ? '-short' : '';

final originColor = Paint()..color = const Color(0xFFFF00FF);
final originColor2 = Paint()..color = const Color(0xFFAA55FF);

final bool halfSize;
late final tileHeight = scale * (halfSize ? 8.0 : 16.0);
late final suffix = halfSize ? '-short' : '';

late IsometricTileMapComponent base;
late Selector selector;

IsometricTileMapExample();
IsometricTileMapExample({required this.halfSize});

@override
Future<void> onLoad() async {
Expand Down Expand Up @@ -65,7 +65,7 @@ class IsometricTileMapExample extends FlameGame with MouseMovementDetector {
super.render(canvas);
canvas.renderPoint(topLeft, size: 5, paint: originColor);
canvas.renderPoint(
topLeft.clone()..y -= tileHeight,
base.position + base.getBlockCenterPosition(const Block(0, 0)),
size: 5,
paint: originColor2,
);
Expand Down
6 changes: 5 additions & 1 deletion examples/lib/stories/rendering/rendering.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ void addRenderingStories(Dashbook dashbook) {
)
..add(
'Isometric Tile Map',
(_) => GameWidget(game: IsometricTileMapExample()),
(context) => GameWidget(
game: IsometricTileMapExample(
halfSize: context.boolProperty('Half size', true),
),
),
codeLink: baseLink('rendering/isometric_tile_map_example.dart'),
info: IsometricTileMapExample.description,
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'dart:math';
import 'dart:ui';

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

/// Displacement applied so that the origin of the component
/// matches the origin of the AABB.
final Vector2 _offset = Vector2.zero();

IsometricTileMapComponent(
this.tileset,
this.matrix, {
Expand All @@ -70,7 +75,9 @@ class IsometricTileMapComponent extends PositionComponent {
super.children,
super.priority,
super.key,
}) : _renderSprite = Sprite(tileset.image);
}) : _renderSprite = Sprite(tileset.image) {
_recomputeSizeAndOffset();
}

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

@override
void update(double dt) {
_recomputeSizeAndOffset();
}

/// Get the position in which a block is rendered in, in the isometric space.
///
/// This does not include the (x,y) PositionComponent offset!
Expand All @@ -124,7 +136,9 @@ class IsometricTileMapComponent extends PositionComponent {
final cartesianPosition = _cartesianPositionCache
..setValues(i.toDouble(), j.toDouble())
..multiply(halfTile);
return cartToIso(cartesianPosition)..sub(halfTile);
return cartToIso(cartesianPosition)
..add(_offset)
..sub(halfTile);
}

/// Get the position of the center of the surface of the isometric tile in
Expand Down Expand Up @@ -168,6 +182,7 @@ class IsometricTileMapComponent extends PositionComponent {
final multiplier = 1 - halfTile.y / (2 * effectiveTileHeight * scale.x);
final iso = _getBlockIsoCache
..setFrom(p)
..sub(_offset)
..sub(position)
..translate(halfTile.x, halfTile.y * multiplier);
final cart = isoToCart(iso);
Expand Down Expand Up @@ -210,4 +225,18 @@ class IsometricTileMapComponent extends PositionComponent {
block.x >= 0 &&
block.x < matrix[block.y].length;
}

void _recomputeSizeAndOffset() {
final width = matrix.fold<int>(
0,
(previousValue, element) => max(previousValue, element.length),
);
final height = matrix.length;

size.x = effectiveTileSize.x * width;
size.y = effectiveTileSize.y * height / 2 + effectiveTileHeight;

_offset.x = size.x / 2;
_offset.y = effectiveTileHeight;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ void main() {

expect(
c.getBlockCenterPosition(const Block(0, 0)),
closeToVector(Vector2.zero()),
closeToVector(Vector2(32, 8)),
);
});

Expand All @@ -77,9 +77,10 @@ void main() {
destTileSize: tileSize,
);
//expect the block to be directly below
final blockAbove = c.getBlockRenderPositionInts(0, 0);
expect(
c.getBlockRenderPositionInts(1, 1),
closeToVector(Vector2(-156 / 2, 12.5), 1e-13),
closeToVector(blockAbove + Vector2(0, 181 / 2), 1e-13),
);
});
});
Expand Down

0 comments on commit 9a7bdc7

Please sign in to comment.