match_magic/lib/game/board.dart

259 lines
6.9 KiB
Dart
Raw Normal View History

2024-08-05 08:04:54 +00:00
import 'dart:math';
import 'package:flame/components.dart';
import 'package:flame/effects.dart';
2024-08-05 08:04:54 +00:00
import 'package:flame/game.dart';
import 'tile.dart';
import 'package:flame/sprite.dart';
class Board extends FlameGame {
final List<Sprite> sprites;
static const int rows = 8;
static const int cols = 8;
late double tileSize;
List<List<Tile?>> tiles = [];
int? selectedRow;
int? selectedCol;
bool animating = false;
2024-08-05 08:04:54 +00:00
Board({required this.sprites});
@override
Future<void> onLoad() async {
super.onLoad();
tileSize = size.x / cols;
_initializeGrid();
_removeInitialMatches();
}
void _initializeGrid() {
for (int row = 0; row < rows; row++) {
List<Tile?> rowTiles = [];
for (int col = 0; col < cols; col++) {
int spriteIndex = _randomElement();
var tile = Tile(
sprite: sprites[spriteIndex],
spriteIndex: spriteIndex,
size: Vector2.all(tileSize),
position: Vector2(col * tileSize, row * tileSize),
row: row,
col: col,
onTileTap: handleTileTap,
);
rowTiles.add(tile);
add(tile);
}
tiles.add(rowTiles);
}
}
int _randomElement() {
return Random().nextInt(7);
}
void _removeInitialMatches() {
bool hasMatches;
do {
hasMatches = false;
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
if (_hasMatch(row, col)) {
int spriteIndex = _randomElement();
tiles[row][col]!.sprite = sprites[spriteIndex];
tiles[row][col]!.spriteIndex = spriteIndex;
hasMatches = true;
}
}
}
} while (hasMatches);
}
void handleTileTap(Tile tappedTile) {
if (animating) return;
2024-08-05 08:04:54 +00:00
int row = tappedTile.row;
int col = tappedTile.col;
if (selectedRow == null || selectedCol == null) {
tappedTile.select();
2024-08-05 08:04:54 +00:00
selectedRow = row;
selectedCol = col;
} else {
tiles[selectedRow!][selectedCol!]?.deselect();
2024-08-05 08:04:54 +00:00
if (_isAdjacent(selectedRow!, selectedCol!, row, col)) {
swapTiles(tiles[selectedRow!]![selectedCol!]!, tiles[row]![col]!, true);
2024-08-05 08:04:54 +00:00
Future.delayed(const Duration(milliseconds: 300), () {
if (!_checkMatches()) {
swapTiles(
tiles[row]![col]!, tiles[selectedRow!]![selectedCol!]!, true);
2024-08-05 08:04:54 +00:00
}
selectedRow = null;
selectedCol = null;
});
} else {
tiles[selectedRow!][selectedCol!]?.deselect();
tappedTile.select();
2024-08-05 08:04:54 +00:00
selectedRow = row;
selectedCol = col;
}
}
}
bool _isAdjacent(int row1, int col1, int row2, int col2) {
return (row1 == row2 && (col1 - col2).abs() == 1) ||
(col1 == col2 && (row1 - row2).abs() == 1);
}
void swapTiles(Tile tile1, Tile tile2, bool animate) {
2024-08-05 08:04:54 +00:00
final tempPosition = tile1.position;
final tempRow = tile1.row;
final tempCol = tile1.col;
tile1.position = tile2.position;
tile1.row = tile2.row;
tile1.col = tile2.col;
tile2.position = tempPosition;
tile2.row = tempRow;
tile2.col = tempCol;
tiles[tile1.row][tile1.col] = tile1;
tiles[tile2.row][tile2.col] = tile2;
if (animate) {
tile1.animateMoveTo(tile1.position, () {});
tile2.animateMoveTo(tile2.position, () {});
}
2024-08-05 08:04:54 +00:00
}
bool _checkMatches() {
if (animating) return false;
animating = true;
2024-08-05 08:04:54 +00:00
final matches = <List<int>>[];
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
if (_hasMatch(row, col)) {
matches.add([row, col]);
}
}
}
if (matches.isNotEmpty) {
for (final match in matches) {
_removeMatchedElements(match[0], match[1]);
}
Future.delayed(const Duration(milliseconds: 300), () {
_applyGravity();
Future.delayed(const Duration(milliseconds: 300), () {
_fillEmptySpaces();
Future.delayed(const Duration(milliseconds: 300), () {
animating = false;
_checkMatches();
});
});
2024-08-05 08:04:54 +00:00
});
return true;
}
animating = false;
2024-08-05 08:04:54 +00:00
return false;
}
bool _hasMatch(int row, int col) {
final value = tiles[row]?[col]?.spriteIndex;
2024-08-05 08:04:54 +00:00
int count = 1;
for (int i = col + 1; i < cols && tiles[row]?[i]?.spriteIndex == value; i++)
2024-08-05 08:04:54 +00:00
count++;
for (int i = col - 1; i >= 0 && tiles[row]?[i]?.spriteIndex == value; i--)
2024-08-05 08:04:54 +00:00
count++;
if (count >= 3) return true;
count = 1;
for (int i = row + 1; i < rows && tiles[i]?[col]?.spriteIndex == value; i++)
2024-08-05 08:04:54 +00:00
count++;
for (int i = row - 1; i >= 0 && tiles[i]?[col]?.spriteIndex == value; i--)
2024-08-05 08:04:54 +00:00
count++;
return count >= 3;
}
void _removeMatchedElements(int row, int col) {
final value = tiles[row]?[col]?.spriteIndex;
2024-08-05 08:04:54 +00:00
int left = col;
while (left > 0 && tiles[row]?[left - 1]?.spriteIndex == value) left--;
2024-08-05 08:04:54 +00:00
int right = col;
while (right < cols - 1 && tiles[row]?[right + 1]?.spriteIndex == value)
2024-08-05 08:04:54 +00:00
right++;
if (right - left + 1 >= 3) {
for (int i = left; i <= right; i++) {
if (tiles[row]?[i] != null) {
_animateRemoveTile(tiles[row]![i]!);
tiles[row]![i] = null;
}
2024-08-05 08:04:54 +00:00
}
}
int top = row;
while (top > 0 && tiles[top - 1]?[col]?.spriteIndex == value) top--;
2024-08-05 08:04:54 +00:00
int bottom = row;
while (bottom < rows - 1 && tiles[bottom + 1]?[col]?.spriteIndex == value)
2024-08-05 08:04:54 +00:00
bottom++;
if (bottom - top + 1 >= 3) {
for (int i = top; i <= bottom; i++) {
if (tiles[i]?[col] != null) {
_animateRemoveTile(tiles[i]![col]!);
tiles[i]![col] = null;
}
2024-08-05 08:04:54 +00:00
}
}
}
void _animateRemoveTile(Tile tile) {
tile.animateRemove(() {
remove(tile);
});
}
2024-08-05 08:04:54 +00:00
void _applyGravity() {
for (int col = 0; col < cols; col++) {
for (int row = rows - 1; row >= 0; row--) {
if (tiles[row]?[col] == null) {
for (int k = row - 1; k >= 0; k--) {
if (tiles[k]?[col] != null) {
tiles[row]![col] = tiles[k]![col]!;
tiles[k]![col] = null;
tiles[row]![col]!.row = row;
tiles[row]![col]!.animateMoveTo(
Vector2(col * tileSize, row * tileSize), () {});
break;
}
2024-08-05 08:04:54 +00:00
}
}
}
}
}
void _fillEmptySpaces() {
for (int col = 0; col < cols; col++) {
for (int row = rows - 1; row >= 0; row--) {
if (tiles[row]?[col] == null) {
2024-08-05 08:04:54 +00:00
int spriteIndex = _randomElement();
var tile = Tile(
sprite: sprites[spriteIndex],
spriteIndex: spriteIndex,
size: Vector2.all(tileSize),
position: Vector2(col * tileSize, -tileSize),
2024-08-05 08:04:54 +00:00
row: row,
col: col,
onTileTap: handleTileTap,
);
tiles[row][col] = tile;
add(tile);
tile.animateMoveTo(Vector2(col * tileSize, row * tileSize), () {});
2024-08-05 08:04:54 +00:00
}
}
}
}
}