Hints have been added to the game. The main menu page has been added. Added new game animation.
This commit is contained in:
parent
8eb5c86496
commit
34d7687dc0
@ -20,6 +20,8 @@ class Board extends FlameGame {
|
|||||||
Tile? lastMovedTile;
|
Tile? lastMovedTile;
|
||||||
Tile? lastMovedByGravity;
|
Tile? lastMovedByGravity;
|
||||||
|
|
||||||
|
bool isFirstLaunch = true;
|
||||||
|
|
||||||
Board({required this.sprites, required this.swapNotifier});
|
Board({required this.sprites, required this.swapNotifier});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -34,32 +36,53 @@ class Board extends FlameGame {
|
|||||||
selectedCol = null;
|
selectedCol = null;
|
||||||
animating = false;
|
animating = false;
|
||||||
tileSize = size.x / cols;
|
tileSize = size.x / cols;
|
||||||
_initializeGrid();
|
_initializeGrid(isFirstLaunch);
|
||||||
_removeInitialMatches();
|
_removeInitialMatches();
|
||||||
|
isFirstLaunch = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void restartGame() {
|
void restartGame() {
|
||||||
|
isFirstLaunch = true;
|
||||||
_resetGame();
|
_resetGame();
|
||||||
swapNotifier.resetScore();
|
swapNotifier.resetScore();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _initializeGrid() {
|
void _initializeGrid(bool animate) {
|
||||||
for (int row = 0; row < rows; row++) {
|
for (int row = 0; row < rows; row++) {
|
||||||
List<Tile?> rowTiles = [];
|
List<Tile?> rowTiles = [];
|
||||||
for (int col = 0; col < cols; col++) {
|
for (int col = 0; col < cols; col++) {
|
||||||
int spriteIndex = _randomElement();
|
int spriteIndex = _randomElement();
|
||||||
|
|
||||||
|
var initialPosition = animate
|
||||||
|
? Vector2(col * tileSize, -tileSize * rows)
|
||||||
|
: Vector2(col * tileSize, row * tileSize);
|
||||||
|
|
||||||
var tile = Tile(
|
var tile = Tile(
|
||||||
sprite: sprites[spriteIndex],
|
sprite: sprites[spriteIndex],
|
||||||
spriteIndex: spriteIndex,
|
spriteIndex: spriteIndex,
|
||||||
size: Vector2.all(tileSize),
|
size: Vector2.all(tileSize),
|
||||||
position: Vector2(col * tileSize, row * tileSize),
|
position: initialPosition,
|
||||||
row: row,
|
row: row,
|
||||||
col: col,
|
col: col,
|
||||||
// onTileTap: handleTileTap,
|
|
||||||
onSwipe: handleTileSwipe,
|
onSwipe: handleTileSwipe,
|
||||||
);
|
);
|
||||||
rowTiles.add(tile);
|
rowTiles.add(tile);
|
||||||
add(tile);
|
add(tile);
|
||||||
|
|
||||||
|
if (animate) {
|
||||||
|
double delay = 0.04 * ((rows - 1 - row) * cols + col);
|
||||||
|
|
||||||
|
tile.add(
|
||||||
|
MoveEffect.to(
|
||||||
|
Vector2(col * tileSize, row * tileSize),
|
||||||
|
EffectController(
|
||||||
|
duration: 0.5,
|
||||||
|
startDelay: delay,
|
||||||
|
curve: Curves.bounceOut,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tiles.add(rowTiles);
|
tiles.add(rowTiles);
|
||||||
}
|
}
|
||||||
@ -86,38 +109,6 @@ class Board extends FlameGame {
|
|||||||
} while (hasMatches);
|
} 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)) {
|
|
||||||
// lastMovedTile = tiles[selectedRow!][selectedCol!];
|
|
||||||
// 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 {
|
Future<void> handleTileSwipe(Tile tile, Vector2 delta) async {
|
||||||
if (animating) return;
|
if (animating) return;
|
||||||
|
|
||||||
@ -148,6 +139,8 @@ class Board extends FlameGame {
|
|||||||
|
|
||||||
if (!checkMatches()) {
|
if (!checkMatches()) {
|
||||||
swapTiles(tile, targetTile, true);
|
swapTiles(tile, targetTile, true);
|
||||||
|
} else {
|
||||||
|
swapNotifier.incrementMoveCount();
|
||||||
}
|
}
|
||||||
selectedRow = null;
|
selectedRow = null;
|
||||||
selectedCol = null;
|
selectedCol = null;
|
||||||
@ -186,7 +179,17 @@ class Board extends FlameGame {
|
|||||||
tile1.deselect();
|
tile1.deselect();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkMatches() {
|
bool checkMatches({bool simulate = false}) {
|
||||||
|
if (simulate) {
|
||||||
|
for (int row = 0; row < rows; row++) {
|
||||||
|
for (int col = 0; col < cols; col++) {
|
||||||
|
if (_hasMatch(row, col)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
animating = true;
|
animating = true;
|
||||||
|
|
||||||
final matches = <List<int>>[];
|
final matches = <List<int>>[];
|
||||||
@ -239,85 +242,6 @@ class Board extends FlameGame {
|
|||||||
return count >= 3;
|
return count >= 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// int _removeMatchedElements(int row, int col) {
|
|
||||||
// int score = 0;
|
|
||||||
// final int? value = tiles[row][col]?.spriteIndex;
|
|
||||||
// bool bombTriggered = false;
|
|
||||||
// Tile? tileToTransformIntoBomb = null;
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
// score += _calculateScore(right - left + 1);
|
|
||||||
|
|
||||||
// if (right - left + 1 >= 4 &&
|
|
||||||
// lastMovedTile != null &&
|
|
||||||
// lastMovedTile!.row == row &&
|
|
||||||
// lastMovedTile!.col >= left &&
|
|
||||||
// lastMovedTile!.col <= right) {
|
|
||||||
// tileToTransformIntoBomb = lastMovedTile;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for (int i = left; i <= right; i++) {
|
|
||||||
// if (tiles[row][i] != null) {
|
|
||||||
// if (tiles[row][i]!.isBomb) {
|
|
||||||
// bombTriggered = true;
|
|
||||||
// _triggerBomb(row, i);
|
|
||||||
// }
|
|
||||||
// if (tiles[row][i] != tileToTransformIntoBomb) {
|
|
||||||
// _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) {
|
|
||||||
// score += _calculateScore(bottom - top + 1);
|
|
||||||
|
|
||||||
// if (bottom - top + 1 >= 4 &&
|
|
||||||
// lastMovedTile != null &&
|
|
||||||
// lastMovedTile!.col == col &&
|
|
||||||
// lastMovedTile!.row >= top &&
|
|
||||||
// lastMovedTile!.row <= bottom) {
|
|
||||||
// tileToTransformIntoBomb = lastMovedTile;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for (int i = top; i <= bottom; i++) {
|
|
||||||
// if (tiles[i][col] != null) {
|
|
||||||
// if (tiles[i][col]!.isBomb) {
|
|
||||||
// bombTriggered = true;
|
|
||||||
// _triggerBomb(i, col);
|
|
||||||
// }
|
|
||||||
// if (tiles[i][col] != tileToTransformIntoBomb) {
|
|
||||||
// _animateRemoveTile(tiles[i][col]!);
|
|
||||||
// tiles[i][col] = null;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (bombTriggered) {
|
|
||||||
// _triggerBomb(row, col);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (tileToTransformIntoBomb != null) {
|
|
||||||
// _createBomb(tileToTransformIntoBomb.row, tileToTransformIntoBomb.col);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return score;
|
|
||||||
// }
|
|
||||||
|
|
||||||
int _removeMatchedElements(int row, int col) {
|
int _removeMatchedElements(int row, int col) {
|
||||||
int score = 0;
|
int score = 0;
|
||||||
final int? value = tiles[row][col]?.spriteIndex;
|
final int? value = tiles[row][col]?.spriteIndex;
|
||||||
@ -511,45 +435,6 @@ class Board extends FlameGame {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// void explodeBomb(Tile bombTile) {
|
|
||||||
// final bombPosition = bombTile.position;
|
|
||||||
// final bombRow = bombTile.row;
|
|
||||||
// final bombCol = bombTile.col;
|
|
||||||
|
|
||||||
// for (int rowOffset = -1; rowOffset <= 1; rowOffset++) {
|
|
||||||
// for (int colOffset = -1; colOffset <= 1; colOffset++) {
|
|
||||||
// final row = bombRow + rowOffset;
|
|
||||||
// final col = bombCol + colOffset;
|
|
||||||
|
|
||||||
// if (row >= 0 && row < rows && col >= 0 && col < cols) {
|
|
||||||
// final tile = tiles[row][col];
|
|
||||||
// if (tile != null && tile != bombTile) {
|
|
||||||
// _animateRemoveTile(tile);
|
|
||||||
// tiles[row][col] = null;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// bombTile.add(RemoveEffect(
|
|
||||||
// delay: 0.5,
|
|
||||||
// onComplete: () => remove(bombTile),
|
|
||||||
// ));
|
|
||||||
|
|
||||||
// final explosion = CircleComponent(
|
|
||||||
// radius: tileSize / 2,
|
|
||||||
// paint: Paint()..color = Colors.orange.withOpacity(0.7),
|
|
||||||
// position: bombPosition,
|
|
||||||
// );
|
|
||||||
// add(explosion);
|
|
||||||
|
|
||||||
// explosion.add(ScaleEffect.to(
|
|
||||||
// Vector2.all(2),
|
|
||||||
// EffectController(duration: 0.5),
|
|
||||||
// onComplete: () => explosion.removeFromParent(),
|
|
||||||
// ));
|
|
||||||
// }
|
|
||||||
|
|
||||||
void explodeBomb(Tile bombTile) {
|
void explodeBomb(Tile bombTile) {
|
||||||
final bombPosition = bombTile.position.clone();
|
final bombPosition = bombTile.position.clone();
|
||||||
final bombRow = bombTile.row;
|
final bombRow = bombTile.row;
|
||||||
@ -568,30 +453,10 @@ class Board extends FlameGame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Анимация взрыва бомбы
|
|
||||||
_animateBombExplosion(bombPosition);
|
_animateBombExplosion(bombPosition);
|
||||||
tiles[bombRow][bombCol] = null;
|
tiles[bombRow][bombCol] = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 _applyGravity() {
|
void _applyGravity() {
|
||||||
for (int col = 0; col < cols; col++) {
|
for (int col = 0; col < cols; col++) {
|
||||||
for (int row = rows - 1; row >= 0; row--) {
|
for (int row = rows - 1; row >= 0; row--) {
|
||||||
@ -634,4 +499,217 @@ class Board extends FlameGame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Tile? findHint() {
|
||||||
|
for (int row = 0; row < rows; row++) {
|
||||||
|
for (int col = 0; col < cols; col++) {
|
||||||
|
Tile? tile = tiles[row][col];
|
||||||
|
|
||||||
|
if (col < cols - 1 && _canSwap(row, col, row, col + 1)) {
|
||||||
|
return tile;
|
||||||
|
}
|
||||||
|
if (row < rows - 1 && _canSwap(row, col, row + 1, col)) {
|
||||||
|
return tile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _canSwap(int row1, int col1, int row2, int col2) {
|
||||||
|
Tile tempTile1 = tiles[row1][col1]!;
|
||||||
|
Tile tempTile2 = tiles[row2][col2]!;
|
||||||
|
|
||||||
|
tiles[row1][col1] = tempTile2;
|
||||||
|
tiles[row2][col2] = tempTile1;
|
||||||
|
|
||||||
|
bool matchFound = checkMatches(simulate: true);
|
||||||
|
|
||||||
|
tiles[row1][col1] = tempTile1;
|
||||||
|
tiles[row2][col2] = tempTile2;
|
||||||
|
|
||||||
|
return matchFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
void showHint() {
|
||||||
|
Tile? hintTile = findHint();
|
||||||
|
if (hintTile != null) {
|
||||||
|
hintTile.select();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 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)) {
|
||||||
|
// lastMovedTile = tiles[selectedRow!][selectedCol!];
|
||||||
|
// 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;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// int _removeMatchedElements(int row, int col) {
|
||||||
|
// int score = 0;
|
||||||
|
// final int? value = tiles[row][col]?.spriteIndex;
|
||||||
|
// bool bombTriggered = false;
|
||||||
|
// Tile? tileToTransformIntoBomb = null;
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
// score += _calculateScore(right - left + 1);
|
||||||
|
|
||||||
|
// if (right - left + 1 >= 4 &&
|
||||||
|
// lastMovedTile != null &&
|
||||||
|
// lastMovedTile!.row == row &&
|
||||||
|
// lastMovedTile!.col >= left &&
|
||||||
|
// lastMovedTile!.col <= right) {
|
||||||
|
// tileToTransformIntoBomb = lastMovedTile;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// for (int i = left; i <= right; i++) {
|
||||||
|
// if (tiles[row][i] != null) {
|
||||||
|
// if (tiles[row][i]!.isBomb) {
|
||||||
|
// bombTriggered = true;
|
||||||
|
// _triggerBomb(row, i);
|
||||||
|
// }
|
||||||
|
// if (tiles[row][i] != tileToTransformIntoBomb) {
|
||||||
|
// _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) {
|
||||||
|
// score += _calculateScore(bottom - top + 1);
|
||||||
|
|
||||||
|
// if (bottom - top + 1 >= 4 &&
|
||||||
|
// lastMovedTile != null &&
|
||||||
|
// lastMovedTile!.col == col &&
|
||||||
|
// lastMovedTile!.row >= top &&
|
||||||
|
// lastMovedTile!.row <= bottom) {
|
||||||
|
// tileToTransformIntoBomb = lastMovedTile;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// for (int i = top; i <= bottom; i++) {
|
||||||
|
// if (tiles[i][col] != null) {
|
||||||
|
// if (tiles[i][col]!.isBomb) {
|
||||||
|
// bombTriggered = true;
|
||||||
|
// _triggerBomb(i, col);
|
||||||
|
// }
|
||||||
|
// if (tiles[i][col] != tileToTransformIntoBomb) {
|
||||||
|
// _animateRemoveTile(tiles[i][col]!);
|
||||||
|
// tiles[i][col] = null;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (bombTriggered) {
|
||||||
|
// _triggerBomb(row, col);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (tileToTransformIntoBomb != null) {
|
||||||
|
// _createBomb(tileToTransformIntoBomb.row, tileToTransformIntoBomb.col);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return score;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// void explodeBomb(Tile bombTile) {
|
||||||
|
// final bombPosition = bombTile.position;
|
||||||
|
// final bombRow = bombTile.row;
|
||||||
|
// final bombCol = bombTile.col;
|
||||||
|
|
||||||
|
// for (int rowOffset = -1; rowOffset <= 1; rowOffset++) {
|
||||||
|
// for (int colOffset = -1; colOffset <= 1; colOffset++) {
|
||||||
|
// final row = bombRow + rowOffset;
|
||||||
|
// final col = bombCol + colOffset;
|
||||||
|
|
||||||
|
// if (row >= 0 && row < rows && col >= 0 && col < cols) {
|
||||||
|
// final tile = tiles[row][col];
|
||||||
|
// if (tile != null && tile != bombTile) {
|
||||||
|
// _animateRemoveTile(tile);
|
||||||
|
// tiles[row][col] = null;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// bombTile.add(RemoveEffect(
|
||||||
|
// delay: 0.5,
|
||||||
|
// onComplete: () => remove(bombTile),
|
||||||
|
// ));
|
||||||
|
|
||||||
|
// final explosion = CircleComponent(
|
||||||
|
// radius: tileSize / 2,
|
||||||
|
// paint: Paint()..color = Colors.orange.withOpacity(0.7),
|
||||||
|
// position: bombPosition,
|
||||||
|
// );
|
||||||
|
// add(explosion);
|
||||||
|
|
||||||
|
// explosion.add(ScaleEffect.to(
|
||||||
|
// Vector2.all(2),
|
||||||
|
// EffectController(duration: 0.5),
|
||||||
|
// onComplete: () => explosion.removeFromParent(),
|
||||||
|
// ));
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
@ -31,60 +31,133 @@ class _MatchMagicGameScreenState extends State<MatchMagicGameScreen> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _showSettingsDialog() {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: const Text('Settings'),
|
||||||
|
content: const Text('The settings have not yet been implemented.'),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
_showExitConfirmationDialog();
|
||||||
|
},
|
||||||
|
child: const Text('Exit to Main Menu'),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: const Text('Close'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showExitConfirmationDialog() {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: const Text('Warning'),
|
||||||
|
content: const Text(
|
||||||
|
'You will lose all game progress. Are you sure you want to exit?'),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||||
|
},
|
||||||
|
child: const Text('Yes'),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: const Text('No'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return FutureBuilder<List<Sprite>>(
|
return Scaffold(
|
||||||
future: _spritesFuture,
|
backgroundColor: Colors.black,
|
||||||
builder: (context, snapshot) {
|
body: FutureBuilder<List<Sprite>>(
|
||||||
if (snapshot.connectionState == ConnectionState.done) {
|
future: _spritesFuture,
|
||||||
if (snapshot.hasError) {
|
builder: (context, snapshot) {
|
||||||
return Center(child: Text('Error: ${snapshot.error}'));
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
} else if (!snapshot.hasData || snapshot.data == null) {
|
if (snapshot.hasError) {
|
||||||
return const Center(child: Text('No sprites found'));
|
return Center(child: Text('Error: ${snapshot.error}'));
|
||||||
} else {
|
} else if (!snapshot.hasData || snapshot.data == null) {
|
||||||
final sprites = snapshot.data!;
|
return const Center(child: Text('No sprites found'));
|
||||||
board ??= Board(
|
} else {
|
||||||
sprites: sprites, swapNotifier: context.read<SwapNotifier>());
|
final sprites = snapshot.data!;
|
||||||
return Column(
|
board ??= Board(
|
||||||
children: [
|
sprites: sprites, swapNotifier: context.read<SwapNotifier>());
|
||||||
const SizedBox(height: 50),
|
|
||||||
const ScoreDisplay(),
|
return Stack(
|
||||||
Expanded(
|
children: [
|
||||||
child: Center(
|
Column(
|
||||||
child: AspectRatio(
|
children: [
|
||||||
aspectRatio: 1,
|
const SizedBox(height: 50),
|
||||||
child: GameWidget(game: board!),
|
const ScoreDisplay(),
|
||||||
|
Expanded(
|
||||||
|
child: Center(
|
||||||
|
child: AspectRatio(
|
||||||
|
aspectRatio: 1,
|
||||||
|
child: GameWidget(game: board!),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: _restartGame,
|
||||||
|
child: const Text(
|
||||||
|
'Restart',
|
||||||
|
style: TextStyle(color: Colors.black),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 20),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
board?.showHint();
|
||||||
|
},
|
||||||
|
child: const Text(
|
||||||
|
'Hint',
|
||||||
|
style: TextStyle(color: Colors.black),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 50),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
top: 16,
|
||||||
|
left: 16,
|
||||||
|
child: IconButton(
|
||||||
|
icon: const Icon(Icons.settings, color: Colors.white),
|
||||||
|
onPressed: _showSettingsDialog,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
Row(
|
);
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
}
|
||||||
children: [
|
} else {
|
||||||
ElevatedButton(
|
return const Center(child: CircularProgressIndicator());
|
||||||
onPressed: _restartGame,
|
|
||||||
child: const Text(
|
|
||||||
'Restart',
|
|
||||||
style: TextStyle(color: Colors.black),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 20),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () {},
|
|
||||||
child: const Text(
|
|
||||||
'Hint',
|
|
||||||
style: TextStyle(color: Colors.black),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 50),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
},
|
||||||
return const Center(child: CircularProgressIndicator());
|
),
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -96,14 +169,44 @@ class ScoreDisplay extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Consumer<SwapNotifier>(
|
child: Row(
|
||||||
builder: (context, notifier, child) {
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
return Text(
|
children: [
|
||||||
'Score: ${notifier.score}',
|
Consumer<SwapNotifier>(
|
||||||
style: const TextStyle(
|
builder: (context, notifier, child) {
|
||||||
fontSize: 24, fontWeight: FontWeight.bold, color: Colors.white),
|
return Card(
|
||||||
);
|
color: Colors.blueGrey[900],
|
||||||
},
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(
|
||||||
|
'Score: ${notifier.score}',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.white),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Consumer<SwapNotifier>(
|
||||||
|
builder: (context, notifier, child) {
|
||||||
|
return Card(
|
||||||
|
color: Colors.blueGrey[900],
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(
|
||||||
|
'Moves: ${notifier.moveCount}',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.white),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,14 @@ import 'tile.dart';
|
|||||||
class SwapNotifier extends ChangeNotifier {
|
class SwapNotifier extends ChangeNotifier {
|
||||||
Tile? selectedTile;
|
Tile? selectedTile;
|
||||||
int _score = 0;
|
int _score = 0;
|
||||||
|
int _moveCount = 0;
|
||||||
|
|
||||||
int get score => _score;
|
int get score => _score;
|
||||||
|
int get moveCount => _moveCount;
|
||||||
|
|
||||||
void resetScore() {
|
void resetScore() {
|
||||||
_score = 0;
|
_score = 0;
|
||||||
|
_moveCount = 0;
|
||||||
selectedTile = null;
|
selectedTile = null;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
@ -18,6 +21,11 @@ class SwapNotifier extends ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void incrementMoveCount() {
|
||||||
|
_moveCount += 1;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
void selectTile(Tile tile) {
|
void selectTile(Tile tile) {
|
||||||
if (selectedTile == null) {
|
if (selectedTile == null) {
|
||||||
selectedTile = tile;
|
selectedTile = tile;
|
||||||
|
@ -61,9 +61,24 @@ class Tile extends SpriteComponent with TapCallbacks, DragCallbacks {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// void select() {
|
||||||
|
// isSelected = true;
|
||||||
|
// updateBorder();
|
||||||
|
// }
|
||||||
|
|
||||||
void select() {
|
void select() {
|
||||||
isSelected = true;
|
final effectController = EffectController(
|
||||||
updateBorder();
|
duration: 0.3,
|
||||||
|
repeatCount: 2,
|
||||||
|
reverseDuration: 0.3,
|
||||||
|
);
|
||||||
|
|
||||||
|
final blinkEffect = OpacityEffect.to(
|
||||||
|
0.0,
|
||||||
|
effectController,
|
||||||
|
);
|
||||||
|
|
||||||
|
add(blinkEffect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void deselect() {
|
void deselect() {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:match_magic/screens/main_menu.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'game/match_magic_game.dart';
|
import 'game/match_magic_game.dart';
|
||||||
import 'game/swap_notifier.dart';
|
import 'game/swap_notifier.dart';
|
||||||
@ -21,15 +22,8 @@ class MyApp extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return const MaterialApp(
|
||||||
title: 'Match Magic',
|
home: MainMenu(),
|
||||||
theme: ThemeData(
|
|
||||||
primarySwatch: Colors.blue,
|
|
||||||
),
|
|
||||||
home: const Scaffold(
|
|
||||||
backgroundColor: Colors.black,
|
|
||||||
body: MatchMagicGameScreen(),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
70
lib/screens/main_menu.dart
Normal file
70
lib/screens/main_menu.dart
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:match_magic/game/match_magic_game.dart';
|
||||||
|
|
||||||
|
class MainMenu extends StatelessWidget {
|
||||||
|
const MainMenu({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
leading: IconButton(
|
||||||
|
icon: const Icon(Icons.settings, color: Colors.white),
|
||||||
|
onPressed: () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AlertDialog(
|
||||||
|
title: const Text('Settings'),
|
||||||
|
content:
|
||||||
|
const Text('The settings have not yet been implemented.'),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: const Text('Ok'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
backgroundColor: Colors.black,
|
||||||
|
),
|
||||||
|
backgroundColor: Colors.black,
|
||||||
|
body: Center(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
const SizedBox(
|
||||||
|
height: 100,
|
||||||
|
),
|
||||||
|
const Text(
|
||||||
|
'Match Magic',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 28,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.white),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 300,
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => const MatchMagicGameScreen()),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 60.0, vertical: 16.0),
|
||||||
|
),
|
||||||
|
child: const Text('Play', style: TextStyle(fontSize: 16)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user