Added score counter.

This commit is contained in:
Alex Vasilev 2024-08-13 17:50:11 +03:00
parent a440fd1545
commit c6b5ed65d9
4 changed files with 153 additions and 55 deletions

View File

@ -4,9 +4,12 @@ import 'package:flame/effects.dart';
import 'package:flame/game.dart'; import 'package:flame/game.dart';
import 'tile.dart'; import 'tile.dart';
import 'package:flame/sprite.dart'; import 'package:flame/sprite.dart';
import 'package:provider/provider.dart';
import 'swap_notifier.dart';
class Board extends FlameGame { class Board extends FlameGame {
final List<Sprite> sprites; final List<Sprite> sprites;
final SwapNotifier swapNotifier;
static const int rows = 8; static const int rows = 8;
static const int cols = 8; static const int cols = 8;
late double tileSize; late double tileSize;
@ -15,17 +18,29 @@ class Board extends FlameGame {
int? selectedCol; int? selectedCol;
bool animating = false; bool animating = false;
Board({required this.sprites}); Board({required this.sprites, required this.swapNotifier});
@override @override
Future<void> onLoad() async { Future<void> onLoad() async {
super.onLoad(); super.onLoad();
_resetGame();
}
void _resetGame() {
tiles.clear();
selectedRow = null;
selectedCol = null;
animating = false;
tileSize = size.x / cols; tileSize = size.x / cols;
_initializeGrid(); _initializeGrid();
_removeInitialMatches(); _removeInitialMatches();
} }
void restartGame() {
_resetGame();
swapNotifier.resetScore();
}
void _initializeGrid() { void _initializeGrid() {
for (int row = 0; row < rows; row++) { for (int row = 0; row < rows; row++) {
List<Tile?> rowTiles = []; List<Tile?> rowTiles = [];
@ -101,7 +116,7 @@ class Board extends FlameGame {
} }
Future<void> handleTileSwipe(Tile tile, Vector2 delta) async { Future<void> handleTileSwipe(Tile tile, Vector2 delta) async {
if (animating) return; // Блокируем свайп во время анимации if (animating) return;
int row = tile.row; int row = tile.row;
int col = tile.col; int col = tile.col;
@ -122,7 +137,7 @@ class Board extends FlameGame {
} }
if (targetTile != null) { if (targetTile != null) {
animating = true; // Устанавливаем флаг анимации animating = true;
swapTiles(tile, targetTile, true); swapTiles(tile, targetTile, true);
await Future.delayed(const Duration(milliseconds: 300)); await Future.delayed(const Duration(milliseconds: 300));
@ -131,7 +146,7 @@ class Board extends FlameGame {
swapTiles(tile, targetTile!, true); swapTiles(tile, targetTile!, true);
} }
animating = false; // Сбрасываем флаг анимации animating = false;
} }
} }
@ -163,8 +178,7 @@ class Board extends FlameGame {
} }
bool checkMatches() { bool checkMatches() {
if (animating) return false; // Не проверяем совпадения, пока идет анимация animating = true;
animating = true; // Устанавливаем флаг анимации
final matches = <List<int>>[]; final matches = <List<int>>[];
for (int row = 0; row < rows; row++) { for (int row = 0; row < rows; row++) {
@ -176,22 +190,25 @@ class Board extends FlameGame {
} }
if (matches.isNotEmpty) { if (matches.isNotEmpty) {
int points = 0;
for (final match in matches) { for (final match in matches) {
_removeMatchedElements(match[0], match[1]); points += _removeMatchedElements(match[0], match[1]);
} }
Future.delayed(const Duration(milliseconds: 300), () { Future.delayed(const Duration(milliseconds: 300), () {
_applyGravity(); _applyGravity();
Future.delayed(const Duration(milliseconds: 300), () { Future.delayed(const Duration(milliseconds: 300), () {
_fillEmptySpaces(); _fillEmptySpaces();
Future.delayed(const Duration(milliseconds: 300), () { Future.delayed(const Duration(milliseconds: 300), () {
animating = false; // Сбрасываем флаг анимации после всех анимаций animating = false;
checkMatches(); checkMatches();
}); });
}); });
}); });
swapNotifier.incrementScore(points);
return true; return true;
} }
animating = false; // Сбрасываем флаг анимации, если нет совпадений animating = false;
return false; return false;
} }
@ -213,7 +230,8 @@ class Board extends FlameGame {
return count >= 3; return count >= 3;
} }
void _removeMatchedElements(int row, int col) { int _removeMatchedElements(int row, int col) {
int score = 0;
final value = tiles[row]?[col]?.spriteIndex; final value = tiles[row]?[col]?.spriteIndex;
int left = col; int left = col;
@ -222,6 +240,8 @@ class Board extends FlameGame {
while (right < cols - 1 && tiles[row]?[right + 1]?.spriteIndex == value) while (right < cols - 1 && tiles[row]?[right + 1]?.spriteIndex == value)
right++; right++;
if (right - left + 1 >= 3) { if (right - left + 1 >= 3) {
int matchLength = right - left + 1;
score += _calculateScore(matchLength);
for (int i = left; i <= right; i++) { for (int i = left; i <= right; i++) {
if (tiles[row]?[i] != null) { if (tiles[row]?[i] != null) {
_animateRemoveTile(tiles[row]![i]!); _animateRemoveTile(tiles[row]![i]!);
@ -236,6 +256,8 @@ class Board extends FlameGame {
while (bottom < rows - 1 && tiles[bottom + 1]?[col]?.spriteIndex == value) while (bottom < rows - 1 && tiles[bottom + 1]?[col]?.spriteIndex == value)
bottom++; bottom++;
if (bottom - top + 1 >= 3) { if (bottom - top + 1 >= 3) {
int matchLength = bottom - top + 1;
score += _calculateScore(matchLength);
for (int i = top; i <= bottom; i++) { for (int i = top; i <= bottom; i++) {
if (tiles[i]?[col] != null) { if (tiles[i]?[col] != null) {
_animateRemoveTile(tiles[i]![col]!); _animateRemoveTile(tiles[i]![col]!);
@ -243,6 +265,17 @@ class Board extends FlameGame {
} }
} }
} }
return score;
}
int _calculateScore(int matchLength) {
if (matchLength == 3) {
return 50;
} else if (matchLength == 4) {
return 100;
}
return 0;
} }
void _animateRemoveTile(Tile tile) { void _animateRemoveTile(Tile tile) {
@ -283,7 +316,7 @@ class Board extends FlameGame {
row: row, row: row,
col: col, col: col,
onTileTap: handleTileTap, onTileTap: handleTileTap,
onSwipe: handleTileSwipe, // Добавлен обработчик свайпов onSwipe: handleTileSwipe,
); );
tiles[row][col] = tile; tiles[row][col] = tile;
add(tile); add(tile);

View File

@ -1,10 +1,77 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:flame/game.dart'; import 'package:flame/game.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:match_magic/game/sprite_loader.dart';
import 'package:match_magic/main.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'board.dart'; import 'board.dart';
import 'swap_notifier.dart'; import 'swap_notifier.dart';
class MatchMagicGameScreen extends StatefulWidget {
const MatchMagicGameScreen({Key? key}) : super(key: key);
@override
_MatchMagicGameScreenState createState() => _MatchMagicGameScreenState();
}
class _MatchMagicGameScreenState extends State<MatchMagicGameScreen> {
late Future<List<Sprite>> _spritesFuture;
Board? board;
@override
void initState() {
super.initState();
_spritesFuture = SpriteLoader.loadSprites();
}
void _restartGame() {
context.read<SwapNotifier>().resetScore();
setState(() {
board = null;
_spritesFuture = SpriteLoader.loadSprites();
});
}
@override
Widget build(BuildContext context) {
return FutureBuilder<List<Sprite>>(
future: _spritesFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
} else if (!snapshot.hasData || snapshot.data == null) {
return const Center(child: Text('No sprites found'));
} else {
final sprites = snapshot.data!;
board ??= Board(
sprites: sprites, swapNotifier: context.read<SwapNotifier>());
return Column(
children: [
const ScoreDisplay(),
Expanded(
child: Center(
child: AspectRatio(
aspectRatio: 1,
child: GameWidget(game: board!),
),
),
),
ElevatedButton(
onPressed: _restartGame,
child: const Text('Restart'),
),
],
);
}
} else {
return const Center(child: CircularProgressIndicator());
}
},
);
}
}
class MatchMagicGame extends StatelessWidget { class MatchMagicGame extends StatelessWidget {
final List<Sprite> sprites; final List<Sprite> sprites;
@ -12,10 +79,26 @@ class MatchMagicGame extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ChangeNotifierProvider( return GameWidget(
create: (_) => SwapNotifier(), game: Board(sprites: sprites, swapNotifier: context.read<SwapNotifier>()),
child: GameWidget( );
game: Board(sprites: sprites), }
}
class ScoreDisplay extends StatelessWidget {
const ScoreDisplay({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Consumer<SwapNotifier>(
builder: (context, notifier, child) {
return Text(
'Score: ${notifier.score}',
style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
);
},
), ),
); );
} }

View File

@ -1,34 +1,46 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'board.dart';
import 'tile.dart'; import 'tile.dart';
class SwapNotifier extends ChangeNotifier { class SwapNotifier extends ChangeNotifier {
Tile? selectedTile; Tile? selectedTile;
int _score = 0;
void selectTile(Tile tile, Board board) { int get score => _score;
void resetScore() {
_score = 0;
selectedTile = null;
notifyListeners();
}
void incrementScore(int value) {
_score += value;
notifyListeners();
}
void selectTile(Tile tile) {
if (selectedTile == null) { if (selectedTile == null) {
selectedTile = tile; selectedTile = tile;
tile.select(); tile.select();
} else { } else {
if (_isNeighbor(selectedTile!, tile)) { if (_isNeighbor(selectedTile!, tile)) {
board.swapTiles(selectedTile!, tile, true); notifyListeners();
Future.delayed(const Duration(milliseconds: 300), () {
if (!board.checkMatches()) {
board.swapTiles(tile, selectedTile!, true);
}
selectedTile = null;
});
} else { } else {
selectedTile?.deselect(); selectedTile?.deselect();
selectedTile = tile; selectedTile = tile;
tile.select(); tile.select();
}
}
notifyListeners(); notifyListeners();
} }
}
}
bool _isNeighbor(Tile tile1, Tile tile2) { bool _isNeighbor(Tile tile1, Tile tile2) {
return (tile1.row == tile2.row && (tile1.col - tile2.col).abs() == 1) || return (tile1.row == tile2.row && (tile1.col - tile2.col).abs() == 1) ||
(tile1.col == tile2.col && (tile1.row - tile2.row).abs() == 1); (tile1.col == tile2.col && (tile1.row - tile2.row).abs() == 1);
} }
void clearSelectedTile() {
selectedTile = null;
notifyListeners();
}
} }

View File

@ -32,33 +32,3 @@ class MyApp extends StatelessWidget {
); );
} }
} }
class MatchMagicGameScreen extends StatelessWidget {
const MatchMagicGameScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return FutureBuilder<List<Sprite>>(
future: SpriteLoader.loadSprites(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
} else if (!snapshot.hasData || snapshot.data == null) {
return const Center(child: Text('No sprites found'));
} else {
final sprites = snapshot.data!;
return Center(
child: AspectRatio(
aspectRatio: 1,
child: MatchMagicGame(sprites: sprites),
),
);
}
} else {
return const Center(child: CircularProgressIndicator());
}
},
);
}
}