Skip to content
Snippets Groups Projects
Select Git revision
  • 5b8fca201e5e4154b9391760d6bba22f65a699a8
  • master default protected
  • 100-upgrade-framework-and-dependencies
  • 65-improve-app-metadata
  • Release_1.8.0_80 protected
  • Release_1.7.2_79 protected
  • Release_1.7.1_78 protected
  • Release_1.7.0_77 protected
  • Release_1.6.0_76 protected
  • Release_1.5.0_75 protected
  • Release_1.4.0_74 protected
  • Release_1.3.2_73 protected
  • Release_1.3.1_72 protected
  • Release_1.3.0_71 protected
  • Release_1.2.1_70 protected
  • Release_1.2.0_69 protected
  • Release_1.1.3_68 protected
  • Release_1.1.2_67 protected
  • Release_1.1.1_66 protected
  • Release_1.1.0_65 protected
  • Release_1.0.63_64 protected
  • Release_1.0.62_63 protected
  • Release_1.0.61_62 protected
  • Release_1.0.60_61 protected
24 results

contents.xcworkspacedata

Blame
  • game_board.dart 4.29 KiB
    import 'package:flutter/material.dart';
    import 'package:flutter_bloc/flutter_bloc.dart';
    
    import 'package:jeweled/cubit/game_cubit.dart';
    import 'package:jeweled/models/game.dart';
    import 'package:jeweled/models/cell_location.dart';
    import 'package:jeweled/ui/painters/game_board_painter.dart';
    
    class GameBoard extends StatefulWidget {
      const GameBoard({super.key});
    
      @override
      State<GameBoard> createState() => _GameBoard();
    }
    
    class _GameBoard extends State<GameBoard> with TickerProviderStateMixin {
      final int animationDuration = 500;
    
      List<List<Animation<double>?>> animations = [];
    
      void resetAnimations(int boardSize) {
        this.animations = List.generate(
          boardSize,
          (i) => List.generate(
            boardSize,
            (i) => null,
          ),
        );
      }
    
      void animateCells(List<CellLocation> cellsToRemove) {
        final GameCubit gameCubit = BlocProvider.of<GameCubit>(context);
        final Game currentGame = gameCubit.state.currentGame;
    
        // "move down" cells
        final controller = AnimationController(
          vsync: this,
          duration: Duration(milliseconds: animationDuration),
        )..addListener(() {
            if (mounted) {
              setState(() {});
            }
          });
    
        if (mounted) {
          setState(() {});
        }
    
        Animation<double> animation(int count) => Tween(
              begin: 0.0,
              end: count.toDouble(),
            ).animate(CurvedAnimation(
              curve: Curves.bounceOut,
              parent: controller,
            ))
              ..addStatusListener((status) {
                if (status == AnimationStatus.completed) {
                  gameCubit.postAnimate();
    
                  resetAnimations(currentGame.gameSettings.boardSize);
                  setState(() {});
    
                  controller.dispose();
                }
              });
    
        // Count translation length for each cell to move
        final List<List<int>> stepsDownCounts = List.generate(
          currentGame.gameSettings.boardSize,
          (i) => List.generate(
            currentGame.gameSettings.boardSize,
            (i) => 0,
          ),
        );
        cellsToRemove.forEach((cellToRemove) {
          for (int i = 0; i < cellToRemove.row; i++) {
            stepsDownCounts[(cellToRemove.row - i) - 1][cellToRemove.col] += 1;
          }
        });
    
        // Build animation for each cell to move
        bool needAnimation = false;
        cellsToRemove.forEach((cellToRemove) {
          for (int i = 0; i < cellToRemove.row; i++) {
            final int stepsCount = stepsDownCounts[(cellToRemove.row - i) - 1][cellToRemove.col];
            this.animations[(cellToRemove.row - i) - 1][cellToRemove.col] = animation(stepsCount);
            needAnimation = true;
          }
        });
    
        controller.forward().orCancel;
    
        if (!needAnimation) {
          gameCubit.postAnimate();
        }
      }
    
      @override
      Widget build(BuildContext context) {
        final double displayWidth = MediaQuery.of(context).size.width;
    
        return Center(
          child: BlocBuilder<GameCubit, GameState>(
            builder: (BuildContext context, GameState gameState) {
              final Game currentGame = gameState.currentGame;
    
              if (this.animations.length == 0) {
                resetAnimations(currentGame.gameSettings.boardSize);
              }
    
              return GestureDetector(
                onTapUp: (details) {
                  bool animationInProgress = false;
                  animations.forEach((row) {
                    row.forEach((cell) {
                      if (cell != null) {
                        animationInProgress = true;
                      }
                    });
                  });
    
                  if (!animationInProgress) {
                    final double xTap = details.localPosition.dx;
                    final double yTap = details.localPosition.dy;
                    final int col = xTap ~/ (displayWidth / currentGame.gameSettings.boardSize);
                    final int row = yTap ~/ (displayWidth / currentGame.gameSettings.boardSize);
    
                    final GameCubit gameCubit = BlocProvider.of<GameCubit>(context);
                    animateCells(gameCubit.tapOnCell(CellLocation.go(row, col)));
                  }
                },
                child: CustomPaint(
                  size: Size(displayWidth, displayWidth),
                  willChange: false,
                  painter: GameBoardPainter(
                    game: currentGame,
                    animations: this.animations,
                  ),
                  isComplex: true,
                ),
              );
            },
          ),
        );
      }
    }