Added score counter.
This commit is contained in:
parent
a440fd1545
commit
c6b5ed65d9
@ -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);
|
||||||
|
@ -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),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user