import 'dart:async'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; import 'package:hydrated_bloc/hydrated_bloc.dart'; import 'package:memory/models/game/game.dart'; import 'package:memory/models/settings/settings_game.dart'; import 'package:memory/models/settings/settings_global.dart'; part 'game_state.dart'; class GameCubit extends HydratedCubit<GameState> { GameCubit() : super(GameState( currentGame: Game.createNull(), )); void updateState(Game game) { emit(GameState( currentGame: game, )); } void refresh() { final Game game = Game( // Settings gameSettings: state.currentGame.gameSettings, globalSettings: state.currentGame.globalSettings, // State isRunning: state.currentGame.isRunning, isStarted: state.currentGame.isStarted, isFinished: state.currentGame.isFinished, animationInProgress: state.currentGame.animationInProgress, shufflingInProgress: state.currentGame.shufflingInProgress, // Base data board: state.currentGame.board, // Game data guessesCount: state.currentGame.guessesCount, pairsFound: state.currentGame.pairsFound, ); game.dump(); updateState(game); } void startNewGame({ required GameSettings gameSettings, required GlobalSettings globalSettings, }) { final Game newGame = Game.createNew( // Settings gameSettings: gameSettings, globalSettings: globalSettings, ); newGame.dump(); updateState(newGame); refresh(); } void quitGame() { state.currentGame.isRunning = false; refresh(); } void resumeSavedGame() { state.currentGame.isRunning = true; refresh(); } void deleteSavedGame() { state.currentGame.isRunning = false; state.currentGame.isFinished = true; refresh(); } void allowInteractions(bool active) { state.currentGame.animationInProgress = !active; refresh(); } void unselectAllTiles() { for (int i = 0; i < state.currentGame.board.tiles.length; i++) { state.currentGame.board.tiles[i].selected = false; } refresh(); } void markTilesAsPaired(List<int> tilesIndexes) { for (int i = 0; i < tilesIndexes.length; i++) { state.currentGame.board.tiles[tilesIndexes[i]].paired = true; } refresh(); } void tapOnTile(int tileIndex) { // Already selected? -> skip if (state.currentGame.board.tiles[tileIndex].selected) { return; } // Already paired? -> skip if (state.currentGame.board.tiles[tileIndex].paired) { return; } // Flip selected tile state.currentGame.board.tiles[tileIndex].selected = true; refresh(); // Is first tile selected? List<int> selectedTilesIndexes = []; for (int i = 0; i < state.currentGame.board.tiles.length; i++) { if (state.currentGame.board.tiles[i].selected) { selectedTilesIndexes.add(i); } } if (selectedTilesIndexes.length >= 2) { allowInteractions(false); // does all selected tiles have same value? bool hasSameValue = true; for (int i = 1; i < selectedTilesIndexes.length; i++) { if (state.currentGame.board.tiles[selectedTilesIndexes[i]].value != state.currentGame.board.tiles[selectedTilesIndexes[i - 1]].value) { hasSameValue = false; } } state.currentGame.guessesCount++; refresh(); // timer + check pair + unselect Timer(const Duration(seconds: 2), () { if (hasSameValue) { markTilesAsPaired(selectedTilesIndexes); final int itemValue = state.currentGame.board.tiles[selectedTilesIndexes[0]].value; state.currentGame.pairsFound.add(itemValue); refresh(); } state.currentGame.isFinished = state.currentGame.gameWon; refresh(); unselectAllTiles(); allowInteractions(true); }); } } @override GameState? fromJson(Map<String, dynamic> json) { final Game currentGame = json['currentGame'] as Game; return GameState( currentGame: currentGame, ); } @override Map<String, dynamic>? toJson(GameState state) { return <String, dynamic>{ 'currentGame': state.currentGame.toJson(), }; } }