From 5d08e8440780c21cdb34343af0ccbb338b54369a Mon Sep 17 00:00:00 2001 From: alexvasl Date: Tue, 6 Aug 2024 21:00:51 +0300 Subject: [PATCH] Changed the behaviour of elements on the field. --- lib/game/board.dart | 98 ++++++++++++++++++++++------------ lib/game/match_magic_game.dart | 1 - lib/game/swap_notifier.dart | 5 +- lib/game/tile.dart | 35 +++++++++++- lib/main.dart | 7 ++- 5 files changed, 108 insertions(+), 38 deletions(-) diff --git a/lib/game/board.dart b/lib/game/board.dart index 34fb86c..b32df44 100644 --- a/lib/game/board.dart +++ b/lib/game/board.dart @@ -1,9 +1,8 @@ import 'dart:math'; import 'package:flame/components.dart'; +import 'package:flame/effects.dart'; import 'package:flame/game.dart'; -import 'package:provider/provider.dart'; import 'tile.dart'; -import 'swap_notifier.dart'; import 'package:flame/sprite.dart'; class Board extends FlameGame { @@ -14,6 +13,7 @@ class Board extends FlameGame { List> tiles = []; int? selectedRow; int? selectedCol; + bool animating = false; Board({required this.sprites}); @@ -69,23 +69,30 @@ class Board extends FlameGame { } 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]!); + swapTiles(tiles[selectedRow!]![selectedCol!]!, tiles[row]![col]!, true); Future.delayed(const Duration(milliseconds: 300), () { if (!_checkMatches()) { - swapTiles(tiles[row][col]!, tiles[selectedRow!][selectedCol!]!); + swapTiles( + tiles[row]![col]!, tiles[selectedRow!]![selectedCol!]!, true); } selectedRow = null; selectedCol = null; }); } else { + tiles[selectedRow!][selectedCol!]?.deselect(); + tappedTile.select(); selectedRow = row; selectedCol = col; } @@ -97,7 +104,7 @@ class Board extends FlameGame { (col1 == col2 && (row1 - row2).abs() == 1); } - void swapTiles(Tile tile1, Tile tile2) { + void swapTiles(Tile tile1, Tile tile2, bool animate) { final tempPosition = tile1.position; final tempRow = tile1.row; final tempCol = tile1.col; @@ -113,13 +120,16 @@ class Board extends FlameGame { tiles[tile1.row][tile1.col] = tile1; tiles[tile2.row][tile2.col] = tile2; - tile1.animateMoveTo(tile1.position, () {}); - tile2.animateMoveTo(tile2.position, () {}); - - _checkMatches(); + if (animate) { + tile1.animateMoveTo(tile1.position, () {}); + tile2.animateMoveTo(tile2.position, () {}); + } } bool _checkMatches() { + if (animating) return false; + animating = true; + final matches = >[]; for (int row = 0; row < rows; row++) { for (int col = 0; col < cols; col++) { @@ -133,71 +143,92 @@ class Board extends FlameGame { for (final match in matches) { _removeMatchedElements(match[0], match[1]); } - _applyGravity(); Future.delayed(const Duration(milliseconds: 300), () { - _fillEmptySpaces(); - _checkMatches(); + _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; + final value = tiles[row]?[col]?.spriteIndex; int count = 1; - for (int i = col + 1; i < cols && tiles[row][i]!.spriteIndex == value; i++) + 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--) + 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++) + 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--) + 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; + final value = tiles[row]?[col]?.spriteIndex; int left = col; - while (left > 0 && tiles[row][left - 1]!.spriteIndex == value) left--; + while (left > 0 && tiles[row]?[left - 1]?.spriteIndex == value) left--; int right = col; - while (right < cols - 1 && tiles[row][right + 1]!.spriteIndex == value) + while (right < cols - 1 && tiles[row]?[right + 1]?.spriteIndex == value) right++; if (right - left + 1 >= 3) { for (int i = left; i <= right; i++) { - tiles[row][i] = null; + 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--; + while (top > 0 && tiles[top - 1]?[col]?.spriteIndex == value) top--; int bottom = row; - while (bottom < rows - 1 && tiles[bottom + 1][col]!.spriteIndex == value) + while (bottom < rows - 1 && tiles[bottom + 1]?[col]?.spriteIndex == value) bottom++; if (bottom - top + 1 >= 3) { for (int i = top; i <= bottom; i++) { - tiles[i][col] = null; + 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++) { - int emptyRow = rows - 1; for (int row = rows - 1; row >= 0; row--) { - if (tiles[row][col] != null) { - if (row != emptyRow) { - tiles[emptyRow][col] = tiles[row][col]; - tiles[emptyRow][col]!.row = emptyRow; - tiles[row][col] = null; + 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; + } } - emptyRow--; } } } @@ -206,19 +237,20 @@ class Board extends FlameGame { void _fillEmptySpaces() { for (int col = 0; col < cols; col++) { for (int row = rows - 1; row >= 0; row--) { - if (tiles[row][col] == null) { + if (tiles[row]?[col] == null) { int spriteIndex = _randomElement(); var tile = Tile( sprite: sprites[spriteIndex], spriteIndex: spriteIndex, size: Vector2.all(tileSize), - position: Vector2(col * tileSize, row * tileSize), + position: Vector2(col * tileSize, -tileSize), row: row, col: col, onTileTap: handleTileTap, ); tiles[row][col] = tile; add(tile); + tile.animateMoveTo(Vector2(col * tileSize, row * tileSize), () {}); } } } diff --git a/lib/game/match_magic_game.dart b/lib/game/match_magic_game.dart index a964713..ba3a4d8 100644 --- a/lib/game/match_magic_game.dart +++ b/lib/game/match_magic_game.dart @@ -2,7 +2,6 @@ import 'package:flame/components.dart'; import 'package:flame/game.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'sprite_loader.dart'; import 'board.dart'; import 'swap_notifier.dart'; diff --git a/lib/game/swap_notifier.dart b/lib/game/swap_notifier.dart index 20ca3c9..7fcff33 100644 --- a/lib/game/swap_notifier.dart +++ b/lib/game/swap_notifier.dart @@ -8,12 +8,15 @@ class SwapNotifier extends ChangeNotifier { void selectTile(Tile tile, Board board) { if (selectedTile == null) { selectedTile = tile; + tile.select(); } else { if (_isNeighbor(selectedTile!, tile)) { - board.swapTiles(selectedTile!, tile); + board.swapTiles(selectedTile!, tile, true); selectedTile = null; } else { + selectedTile?.deselect(); selectedTile = tile; + tile.select(); } } notifyListeners(); diff --git a/lib/game/tile.dart b/lib/game/tile.dart index d070d03..837a760 100644 --- a/lib/game/tile.dart +++ b/lib/game/tile.dart @@ -1,7 +1,6 @@ import 'package:flame/components.dart'; import 'package:flame/effects.dart'; import 'package:flame/events.dart'; -import 'package:flame/input.dart'; import 'package:flutter/material.dart'; class Tile extends SpriteComponent with TapCallbacks { @@ -9,6 +8,7 @@ class Tile extends SpriteComponent with TapCallbacks { int col; int spriteIndex; final void Function(Tile) onTileTap; + bool isSelected = false; Tile({ required Sprite sprite, @@ -26,10 +26,41 @@ class Tile extends SpriteComponent with TapCallbacks { return true; } + void select() { + isSelected = true; + updateBorder(); + } + + void deselect() { + isSelected = false; + updateBorder(); + } + + void updateBorder() { + if (isSelected) { + add(RectangleComponent( + size: size, + paint: Paint() + ..color = Colors.yellow + ..style = PaintingStyle.stroke + ..strokeWidth = 3, + )); + } else { + children.removeWhere((child) => child is RectangleComponent); + } + } + void animateMoveTo(Vector2 newPosition, VoidCallback onComplete) { add(MoveEffect.to( newPosition, - EffectController(duration: 0.5), + EffectController(duration: 0.3), + onComplete: onComplete, + )); + } + + void animateRemove(VoidCallback onComplete) { + add(RemoveEffect( + delay: 0.5, onComplete: onComplete, )); } diff --git a/lib/main.dart b/lib/main.dart index b42f2c9..ad5332d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -48,7 +48,12 @@ class MatchMagicGameScreen extends StatelessWidget { return const Center(child: Text('No sprites found')); } else { final sprites = snapshot.data!; - return MatchMagicGame(sprites: sprites); + return Center( + child: AspectRatio( + aspectRatio: 1, + child: MatchMagicGame(sprites: sprites), + ), + ); } } else { return const Center(child: CircularProgressIndicator());