match_magic/lib/game/board.dart

296 lines
8.4 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:math';
import 'package:flame/components.dart';
import 'package:flame/effects.dart';
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;
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,
onSwipe: handleTileSwipe,
);
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;
int row = tappedTile.row;
int col = tappedTile.col;
if (selectedRow == null || selectedCol == null) {
tappedTile.select();
selectedRow = row;
selectedCol = col;
} else {
tiles[selectedRow!][selectedCol!]?.deselect();
if (_isAdjacent(selectedRow!, selectedCol!, row, col)) {
swapTiles(tiles[selectedRow!]![selectedCol!]!, tiles[row]![col]!, true);
Future.delayed(const Duration(milliseconds: 300), () {
if (!checkMatches()) {
swapTiles(
tiles[row]![col]!, tiles[selectedRow!]![selectedCol!]!, true);
}
selectedRow = null;
selectedCol = null;
});
} else {
tiles[selectedRow!][selectedCol!]?.deselect();
tappedTile.select();
selectedRow = row;
selectedCol = col;
}
}
}
Future<void> handleTileSwipe(Tile tile, Vector2 delta) async {
if (animating) return; // Блокируем свайп во время анимации
int row = tile.row;
int col = tile.col;
Tile? targetTile;
if (delta.x.abs() > delta.y.abs()) {
if (delta.x > 0 && col < cols - 1) {
targetTile = tiles[row][col + 1];
} else if (delta.x < 0 && col > 0) {
targetTile = tiles[row][col - 1];
}
} else {
if (delta.y > 0 && row < rows - 1) {
targetTile = tiles[row + 1][col];
} else if (delta.y < 0 && row > 0) {
targetTile = tiles[row - 1][col];
}
}
if (targetTile != null) {
animating = true; // Устанавливаем флаг анимации
swapTiles(tile, targetTile, true);
await Future.delayed(const Duration(milliseconds: 300));
if (!checkMatches()) {
swapTiles(tile, targetTile!, true);
}
animating = false; // Сбрасываем флаг анимации
}
}
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) {
final tempPosition1 = tile1.position.clone();
final tempPosition2 = tile2.position.clone();
final tempRow1 = tile1.row;
final tempCol1 = tile1.col;
final tempRow2 = tile2.row;
final tempCol2 = tile2.col;
tile1.row = tempRow2;
tile1.col = tempCol2;
tile2.row = tempRow1;
tile2.col = tempCol1;
tiles[tile1.row][tile1.col] = tile1;
tiles[tile2.row][tile2.col] = tile2;
if (animate) {
tile1.animateMoveTo(tempPosition2, () {});
tile2.animateMoveTo(tempPosition1, () {});
}
}
bool checkMatches() {
if (animating) return false; // Не проверяем совпадения, пока идет анимация
animating = true; // Устанавливаем флаг анимации
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();
});
});
});
return true;
}
animating = false; // Сбрасываем флаг анимации, если нет совпадений
return false;
}
bool _hasMatch(int row, int col) {
final value = tiles[row]?[col]?.spriteIndex;
int count = 1;
for (int i = col + 1; i < cols && tiles[row]?[i]?.spriteIndex == value; i++)
count++;
for (int i = col - 1; i >= 0 && tiles[row]?[i]?.spriteIndex == value; i--)
count++;
if (count >= 3) return true;
count = 1;
for (int i = row + 1; i < rows && tiles[i]?[col]?.spriteIndex == value; i++)
count++;
for (int i = row - 1; i >= 0 && tiles[i]?[col]?.spriteIndex == value; i--)
count++;
return count >= 3;
}
void _removeMatchedElements(int row, int col) {
final value = tiles[row]?[col]?.spriteIndex;
int left = col;
while (left > 0 && tiles[row]?[left - 1]?.spriteIndex == value) left--;
int right = col;
while (right < cols - 1 && tiles[row]?[right + 1]?.spriteIndex == value)
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;
}
}
}
int top = row;
while (top > 0 && tiles[top - 1]?[col]?.spriteIndex == value) top--;
int bottom = row;
while (bottom < rows - 1 && tiles[bottom + 1]?[col]?.spriteIndex == value)
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;
}
}
}
}
void _animateRemoveTile(Tile tile) {
tile.animateRemove(() {
remove(tile);
});
}
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;
}
}
}
}
}
}
void _fillEmptySpaces() {
for (int col = 0; col < cols; col++) {
for (int row = rows - 1; row >= 0; row--) {
if (tiles[row]?[col] == null) {
int spriteIndex = _randomElement();
var tile = Tile(
sprite: sprites[spriteIndex],
spriteIndex: spriteIndex,
size: Vector2.all(tileSize),
position: Vector2(col * tileSize, -tileSize),
row: row,
col: col,
onTileTap: handleTileTap,
onSwipe: handleTileSwipe, // Добавлен обработчик свайпов
);
tiles[row][col] = tile;
add(tile);
tile.animateMoveTo(Vector2(col * tileSize, row * tileSize), () {});
}
}
}
}
}