mirror of
https://github.com/flame-engine/flame.git
synced 2025-11-03 20:36:31 +08:00
103 lines
3.0 KiB
Dart
103 lines
3.0 KiB
Dart
import 'dart:ui';
|
|
|
|
import 'position_component.dart';
|
|
|
|
import '../extensions/vector2.dart';
|
|
import '../spritesheet.dart';
|
|
|
|
/// This is just a pair of <int, int>.
|
|
///
|
|
/// Represents a position in a matrix, or in this case, on the tilemap.
|
|
class Block {
|
|
/// x and y coordinates on the matrix
|
|
int x, y;
|
|
|
|
Block(this.x, this.y);
|
|
|
|
@override
|
|
String toString() => '($x, $y)';
|
|
}
|
|
|
|
/// This component renders a tilemap, represented by an int matrix, given a
|
|
/// tileset, in witch the integers are the block ids.
|
|
///
|
|
/// It can change the scale of each block by using the optional destTileSize
|
|
/// property.
|
|
class IsometricTileMapComponent extends PositionComponent {
|
|
/// This is the tileset that will be used to render this map.
|
|
SpriteSheet tileset;
|
|
|
|
/// The positions of each block will be placed respecting this matrix.
|
|
List<List<int>> matrix;
|
|
|
|
/// Optionally provide a new tile size to render it scaled.
|
|
Vector2 destTileSize;
|
|
|
|
IsometricTileMapComponent(this.tileset, this.matrix, {this.destTileSize});
|
|
|
|
/// This is the size the tiles will be drawn (either original or overwritten).
|
|
Vector2 get effectiveTileSize => destTileSize ?? tileset.srcSize;
|
|
|
|
@override
|
|
void render(Canvas c) {
|
|
super.render(c);
|
|
|
|
final size = effectiveTileSize;
|
|
for (int i = 0; i < matrix.length; i++) {
|
|
for (int j = 0; j < matrix[i].length; j++) {
|
|
final element = matrix[i][j];
|
|
if (element != -1) {
|
|
final sprite = tileset.getSpriteById(element);
|
|
final p = getBlockPositionInts(j, i);
|
|
sprite.renderRect(c, p.toPositionedRect(size));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Get the position in witch a block must be in the isometric space.
|
|
///
|
|
/// This does not include the (x,y) PositionComponent offset!
|
|
Vector2 getBlockPosition(Block block) {
|
|
return getBlockPositionInts(block.x, block.y);
|
|
}
|
|
|
|
Vector2 getBlockPositionInts(int i, int j) {
|
|
final pos = Vector2(i.toDouble(), j.toDouble())
|
|
..multiply(effectiveTileSize / 2);
|
|
return cartToIso(pos) - Vector2(effectiveTileSize.x / 2, 0);
|
|
}
|
|
|
|
/// Converts a coordinate from the isometric space to the cartesian space.
|
|
Vector2 isoToCart(Vector2 p) {
|
|
final x = (2 * p.y + p.x) / 2;
|
|
final y = (2 * p.y - p.x) / 2;
|
|
return Vector2(x, y);
|
|
}
|
|
|
|
/// Converts a coordinate from the cartesian space to the isometric space.
|
|
Vector2 cartToIso(Vector2 p) {
|
|
final x = p.x - p.y;
|
|
final y = (p.x + p.y) / 2;
|
|
return Vector2(x, y);
|
|
}
|
|
|
|
/// Get what block is at isometric position p.
|
|
///
|
|
/// This can be used to handle clicks or hovers.
|
|
Block getBlock(Vector2 p) {
|
|
final cart = isoToCart(p - position);
|
|
final px = cart.x ~/ (effectiveTileSize.x / 2);
|
|
final py = cart.y ~/ (effectiveTileSize.y / 2);
|
|
return Block(px, py);
|
|
}
|
|
|
|
/// Return whether the matrix contains a block in its bounds.
|
|
bool containsBlock(Block block) {
|
|
return block.x >= 0 &&
|
|
block.x < matrix.length &&
|
|
block.y >= 0 &&
|
|
block.y < matrix[block.x].length;
|
|
}
|
|
}
|