Fixes a bug with moving elements.

This commit is contained in:
Alex Vasilev 2024-08-29 16:44:44 +03:00
parent a93577a606
commit 8eb5c86496
3 changed files with 248 additions and 96 deletions

View File

@ -18,6 +18,7 @@ class Board extends FlameGame {
int? selectedCol; int? selectedCol;
bool animating = false; bool animating = false;
Tile? lastMovedTile; Tile? lastMovedTile;
Tile? lastMovedByGravity;
Board({required this.sprites, required this.swapNotifier}); Board({required this.sprites, required this.swapNotifier});
@ -54,7 +55,7 @@ class Board extends FlameGame {
position: Vector2(col * tileSize, row * tileSize), position: Vector2(col * tileSize, row * tileSize),
row: row, row: row,
col: col, col: col,
onTileTap: handleTileTap, // onTileTap: handleTileTap,
onSwipe: handleTileSwipe, onSwipe: handleTileSwipe,
); );
rowTiles.add(tile); rowTiles.add(tile);
@ -85,37 +86,37 @@ class Board extends FlameGame {
} while (hasMatches); } while (hasMatches);
} }
void handleTileTap(Tile tappedTile) { // void handleTileTap(Tile tappedTile) {
if (animating) return; // if (animating) return;
int row = tappedTile.row; // int row = tappedTile.row;
int col = tappedTile.col; // int col = tappedTile.col;
if (selectedRow == null || selectedCol == null) { // if (selectedRow == null || selectedCol == null) {
tappedTile.select(); // tappedTile.select();
selectedRow = row; // selectedRow = row;
selectedCol = col; // selectedCol = col;
} else { // } else {
tiles[selectedRow!][selectedCol!]?.deselect(); // tiles[selectedRow!][selectedCol!]?.deselect();
if (_isAdjacent(selectedRow!, selectedCol!, row, col)) { // if (_isAdjacent(selectedRow!, selectedCol!, row, col)) {
lastMovedTile = tiles[selectedRow!][selectedCol!]; // lastMovedTile = tiles[selectedRow!][selectedCol!];
swapTiles(tiles[selectedRow!][selectedCol!]!, tiles[row][col]!, true); // swapTiles(tiles[selectedRow!][selectedCol!]!, tiles[row][col]!, true);
Future.delayed(const Duration(milliseconds: 300), () { // Future.delayed(const Duration(milliseconds: 300), () {
if (!checkMatches()) { // if (!checkMatches()) {
swapTiles( // swapTiles(
tiles[row][col]!, tiles[selectedRow!][selectedCol!]!, true); // tiles[row][col]!, tiles[selectedRow!][selectedCol!]!, true);
} // }
selectedRow = null; // selectedRow = null;
selectedCol = null; // selectedCol = null;
}); // });
} else { // } else {
tiles[selectedRow!][selectedCol!]?.deselect(); // tiles[selectedRow!][selectedCol!]?.deselect();
tappedTile.select(); // tappedTile.select();
selectedRow = row; // selectedRow = row;
selectedCol = col; // 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,7 +149,8 @@ class Board extends FlameGame {
if (!checkMatches()) { if (!checkMatches()) {
swapTiles(tile, targetTile, true); swapTiles(tile, targetTile, true);
} }
selectedRow = null;
selectedCol = null;
animating = false; animating = false;
} }
} }
@ -159,8 +161,8 @@ class Board extends FlameGame {
} }
void swapTiles(Tile tile1, Tile tile2, bool animate) { void swapTiles(Tile tile1, Tile tile2, bool animate) {
final tempPosition1 = tile1.position.clone(); // final tempPosition1 = tile1.position.clone();
final tempPosition2 = tile2.position.clone(); // final tempPosition2 = tile2.position.clone();
final tempRow1 = tile1.row; final tempRow1 = tile1.row;
final tempCol1 = tile1.col; final tempCol1 = tile1.col;
final tempRow2 = tile2.row; final tempRow2 = tile2.row;
@ -175,9 +177,13 @@ class Board extends FlameGame {
tiles[tile2.row][tile2.col] = tile2; tiles[tile2.row][tile2.col] = tile2;
if (animate) { if (animate) {
final tempPosition1 = tile1.position.clone();
final tempPosition2 = tile2.position.clone();
tile1.animateMoveTo(tempPosition2, () {}); tile1.animateMoveTo(tempPosition2, () {});
tile2.animateMoveTo(tempPosition1, () {}); tile2.animateMoveTo(tempPosition1, () {});
} }
tile1.deselect();
tile1.deselect();
} }
bool checkMatches() { bool checkMatches() {
@ -233,11 +239,90 @@ 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;
bool bombTriggered = false; bool bombTriggered = false;
Tile? tileToTransformIntoBomb = lastMovedTile; Tile? tileToTransformIntoBomb = null;
int left = col; int left = col;
while (left > 0 && tiles[row][left - 1]?.spriteIndex == value) left--; while (left > 0 && tiles[row][left - 1]?.spriteIndex == value) left--;
@ -249,7 +334,7 @@ class Board extends FlameGame {
score += _calculateScore(right - left + 1); score += _calculateScore(right - left + 1);
if (right - left + 1 >= 4) { if (right - left + 1 >= 4) {
tileToTransformIntoBomb = tiles[row][col]; tileToTransformIntoBomb = lastMovedTile ?? lastMovedByGravity;
} }
for (int i = left; i <= right; i++) { for (int i = left; i <= right; i++) {
@ -276,7 +361,7 @@ class Board extends FlameGame {
score += _calculateScore(bottom - top + 1); score += _calculateScore(bottom - top + 1);
if (bottom - top + 1 >= 4) { if (bottom - top + 1 >= 4) {
tileToTransformIntoBomb = tiles[row][col]; tileToTransformIntoBomb = lastMovedTile ?? lastMovedByGravity;
} }
for (int i = top; i <= bottom; i++) { for (int i = top; i <= bottom; i++) {
@ -426,45 +511,87 @@ 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; final bombPosition = bombTile.position.clone();
final bombRow = bombTile.row; final bombRow = bombTile.row;
final bombCol = bombTile.col; final bombCol = bombTile.col;
for (int rowOffset = -1; rowOffset <= 1; rowOffset++) { for (int i = max(0, bombRow - 1); i <= min(rows - 1, bombRow + 1); i++) {
for (int colOffset = -1; colOffset <= 1; colOffset++) { for (int j = max(0, bombCol - 1); j <= min(cols - 1, bombCol + 1); j++) {
final row = bombRow + rowOffset; if (tiles[i][j] != null) {
final col = bombCol + colOffset; if (tiles[i][j]!.isBomb && (i != bombRow || j != bombCol)) {
_triggerBomb(i, j);
if (row >= 0 && row < rows && col >= 0 && col < cols) { } else {
final tile = tiles[row][col]; _animateRemoveTile(tiles[i][j]!);
if (tile != null && tile != bombTile) { tiles[i][j] = null;
_animateRemoveTile(tile);
tiles[row][col] = null;
} }
} }
} }
} }
bombTile.add(RemoveEffect( // Анимация взрыва бомбы
delay: 0.5, _animateBombExplosion(bombPosition);
onComplete: () => remove(bombTile), tiles[bombRow][bombCol] = null;
));
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;
// }
// }
// }
// }
// }
// }
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--) {
@ -476,6 +603,7 @@ class Board extends FlameGame {
tiles[row][col]!.row = row; tiles[row][col]!.row = row;
tiles[row][col]!.animateMoveTo( tiles[row][col]!.animateMoveTo(
Vector2(col * tileSize, row * tileSize), () {}); Vector2(col * tileSize, row * tileSize), () {});
lastMovedByGravity = tiles[row][col];
break; break;
} }
} }
@ -496,7 +624,7 @@ class Board extends FlameGame {
position: Vector2(col * tileSize, -tileSize), position: Vector2(col * tileSize, -tileSize),
row: row, row: row,
col: col, col: col,
onTileTap: handleTileTap, // onTileTap: handleTileTap,
onSwipe: handleTileSwipe, onSwipe: handleTileSwipe,
); );
tiles[row][col] = tile; tiles[row][col] = tile;

View File

@ -47,9 +47,7 @@ class _MatchMagicGameScreenState extends State<MatchMagicGameScreen> {
sprites: sprites, swapNotifier: context.read<SwapNotifier>()); sprites: sprites, swapNotifier: context.read<SwapNotifier>());
return Column( return Column(
children: [ children: [
SizedBox( const SizedBox(height: 50),
height: 50,
),
const ScoreDisplay(), const ScoreDisplay(),
Expanded( Expanded(
child: Center( child: Center(
@ -59,16 +57,27 @@ class _MatchMagicGameScreenState extends State<MatchMagicGameScreen> {
), ),
), ),
), ),
ElevatedButton( Row(
onPressed: _restartGame, mainAxisAlignment: MainAxisAlignment.center,
child: const Text( children: [
'Restart', ElevatedButton(
style: TextStyle(color: Colors.black), 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),
),
),
],
), ),
SizedBox( const SizedBox(height: 50),
height: 50,
)
], ],
); );
} }

View File

@ -8,13 +8,15 @@ class Tile extends SpriteComponent with TapCallbacks, DragCallbacks {
int row; int row;
int col; int col;
int spriteIndex; int spriteIndex;
final void Function(Tile) onTileTap; // final void Function(Tile) onTileTap;
final void Function(Tile, Vector2) onSwipe; final void Function(Tile, Vector2) onSwipe;
bool isSelected = false; bool isSelected = false;
bool isBomb = false; bool isBomb = false;
bool isMagicCube = false; bool isMagicCube = false;
Vector2? startDragPosition; Vector2? startDragPosition;
bool isAnimating = false;
Tile({ Tile({
required Sprite sprite, required Sprite sprite,
required this.spriteIndex, required this.spriteIndex,
@ -22,31 +24,34 @@ class Tile extends SpriteComponent with TapCallbacks, DragCallbacks {
required Vector2 position, required Vector2 position,
required this.row, required this.row,
required this.col, required this.col,
required this.onTileTap, // required this.onTileTap,
required this.onSwipe, required this.onSwipe,
}) : super(sprite: sprite, size: size, position: position); }) : super(sprite: sprite, size: size, position: position);
@override // @override
bool onTapDown(TapDownEvent event) { // bool onTapDown(TapDownEvent event) {
if (parent is Board && (parent as Board).animating) { // if (isAnimating || (parent is Board && (parent as Board).animating)) {
return false; // return false;
} // }
onTileTap(this); // onTileTap(this);
return true; // return true;
} // }
@override @override
bool onDragStart(DragStartEvent event) { bool onDragStart(DragStartEvent event) {
super.onDragStart(event); if (isAnimating || (parent as Board).animating) {
if (parent is Board && (parent as Board).animating) {
return false; return false;
} }
super.onDragStart(event);
startDragPosition = event.localPosition; startDragPosition = event.localPosition;
return true; return true;
} }
@override @override
bool onDragEnd(DragEndEvent event) { bool onDragEnd(DragEndEvent event) {
if (isAnimating || (parent as Board).animating) {
return false;
}
super.onDragEnd(event); super.onDragEnd(event);
if (startDragPosition != null) { if (startDragPosition != null) {
final delta = event.velocity; final delta = event.velocity;
@ -81,17 +86,27 @@ class Tile extends SpriteComponent with TapCallbacks, DragCallbacks {
} }
void animateMoveTo(Vector2 newPosition, VoidCallback onComplete) { void animateMoveTo(Vector2 newPosition, VoidCallback onComplete) {
isAnimating = true;
print('animation start');
add(MoveEffect.to( add(MoveEffect.to(
newPosition, newPosition,
EffectController(duration: 0.3), EffectController(duration: 0.3),
onComplete: onComplete, onComplete: () {
print('animation complete');
isAnimating = false;
onComplete();
},
)); ));
} }
void animateRemove(VoidCallback onComplete) { // void animateRemove(VoidCallback onComplete) {
add(RemoveEffect( // isAnimating = true;
delay: 0.5, // add(RemoveEffect(
onComplete: onComplete, // delay: 0.5,
)); // onComplete: () {
} // isAnimating = false;
// onComplete();
// },
// ));
// }
} }