首页 > 其他分享 >一统天下 flutter - 游戏: 俄罗斯方块

一统天下 flutter - 游戏: 俄罗斯方块

时间:2023-09-18 11:22:32浏览次数:44  
标签:square dart shape 一统天下 var import flutter 方块

源码 https://github.com/webabcd/flutter_demo
作者 webabcd

一统天下 flutter - 游戏: 俄罗斯方块

示例如下:

lib\game\tetris\tetris.dart

/*
 * 俄罗斯方块
 *
 * 使用了 flame 库,在 pubspec.yaml 中做如下配置,然后 flutter pub get
 * dependencies:
 *   flame: ^1.7.3
 */


import 'package:flame/game.dart';
import 'package:flutter/material.dart';
import 'package:flutter_demo/game/tetris/shape/shape.dart';
import 'package:flutter_demo/game/tetris/shape/square.dart';
import 'package:flutter_demo/game/tetris/shape/t.dart';

import 'config.dart';
import 'controller.dart';
import 'core.dart';

class Tetris extends StatefulWidget {
  const Tetris({Key? key}) : super(key: key);

  @override
  TetrisState createState() => TetrisState();
}

class TetrisState extends State<Tetris> {

  final controller = Controller();

  @override
  Widget build(BuildContext context) {
    return Material(
      color: Colors.orange,
      child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          Container(
            width: Config.mainMatrixWidth * Config.squareWidth,
            height: Config.mainMatrixHeight * Config.squareWidth,
            child: GameWidget(
              game: MyGame(controller: controller),
            ),
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              _button1(
                Icons.arrow_back, () { controller.left(); }, () { },
              ),
              _button1(
                Icons.arrow_forward, () { controller.right(); }, () { },
              ),
              _button1(
                Icons.rotate_right_rounded, () { controller.rotate(); }, () { },
              ),
              _button1(
                Icons.arrow_downward, () { controller.downPressed = true; }, () { controller.downPressed = false; },
              ),
            ],
          ),
        ],
      ),
    );
  }

  Ink _button1(IconData iconData, VoidCallback onDown, VoidCallback onUp) {
    return Ink(
      padding: EdgeInsets.zero,
      width: 36,
      height: 36,
      decoration: BoxDecoration(
        color: Colors.blue,
        borderRadius: BorderRadius.circular(18),
      ),
      child: InkWell(
        child: Icon(iconData, color: Colors.white,),
        onTapDown: (details) { onDown(); },
        onTapUp: (details) { onUp(); },
      ),
    );
  }
}

class MyGame extends FlameGame {
  MyGame({required this.controller});
  final Controller controller;
  bool shapeUpdated = false;

  List<Shape> shapeList = <Shape>[];
  List<List<Square?>> mainMatrix = <List<Square?>>[];

  @override
  Future<void>? onl oad() async {

    shapeList.add(Core.createShape());
    Core.initMainMatrix(mainMatrix);

    controller.addListener(() {
      if (controller.rotateTimes > 0) {
        shapeList[0].rotate();
        controller.rotateTimes--;
      } else if (controller.leftTimes > 0) {
        shapeList[0].left();
        controller.leftTimes--;
      } else if (controller.rightTimes > 0) {
        shapeList[0].right();
        controller.rightTimes--;
      }
      shapeUpdated = true;
    });

    return super.onLoad();
  }

  @override
  void render(Canvas canvas) {
    super.render(canvas);

    shapeList[0].render(canvas);

    for (var j = 0; j < mainMatrix.length; j++) {
      for (var i = 0; i < mainMatrix[j].length; i++) {
        var square = mainMatrix[j][i];
        if (square != null) {
          var offsetCenter = Offset(square.width / 2 + i * square.width, square.width / 2 + j * square.width);
          canvas.drawRect(Rect.fromCenter(center: offsetCenter, width: square.width, height: square.width), square.borderPaint);
          canvas.drawRect(Rect.fromCenter(center: offsetCenter, width: square.width - square.borderWidth, height: square.width - square.borderWidth), square.paint);
        }
      }
    }
  }

  @override
  void update(double dt) {
    super.update(dt);

    if (controller.downPressed) {
      Config.speed = 500;
    } else {
      Config.speed = 20;
    }

    var shape = shapeList[0];
    if (shapeUpdated) {
      shapeUpdated = false;
    } else {
      shape.update(dt);
    }

    var collisionType = Core.checkCollision(shape, mainMatrix);
    if (collisionType == CollisionType.bottom) {
      shape.loadPrev();
      Core.pinShape(shape, mainMatrix);
      controller.downPressed = false;
      Core.removeLineShape(mainMatrix);

      shapeList.removeAt(0);
      var newShape = Core.createShape();
      shapeList.add(newShape);
      if (Core.checkCollision(newShape, mainMatrix) == CollisionType.bottom) {
        Core.initMainMatrix(mainMatrix); // 死了重来
      }
    } else if (collisionType == CollisionType.edge) {
      shape.loadPrev();
    }
  }
}

lib\game\tetris\core.dart

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter_demo/game/tetris/shape/i.dart';
import 'package:flutter_demo/game/tetris/shape/l.dart';
import 'package:flutter_demo/game/tetris/shape/l2.dart';
import 'package:flutter_demo/game/tetris/shape/n.dart';
import 'package:flutter_demo/game/tetris/shape/n2.dart';
import 'package:flutter_demo/game/tetris/shape/o.dart';
import 'package:flutter_demo/game/tetris/shape/shape.dart';
import 'package:flutter_demo/game/tetris/shape/square.dart';
import 'package:flutter_demo/game/tetris/shape/t.dart';

import 'config.dart';

enum CollisionType { none, edge, bottom }

class Core {

  static var random = Random();

  static CollisionType checkCollision(Shape shape, List<List<Square?>> mainMatrix) {
    var shapeMatrix = shape.matrixList[shape.currentIndex];
    for (var j = 0; j < shapeMatrix.length; j++) { // 纵轴是 j 横轴是 i
      for (var i = 0; i < shapeMatrix[j].length; i++) {
        var cell = shapeMatrix[j][i];
        if (cell == 1) {
          var leftTopPoint = shape.leftTopPoint;
          var prevLeftTopPoint = shape.prevLeftTopPoint;
          var mi = i + leftTopPoint.dx.toInt();
          var mj = j + leftTopPoint.dy.toInt();
          if (mi < 0 || mi >= mainMatrix[0].length) {
            return CollisionType.edge;
          }
          if (mj >= mainMatrix.length) {
            return CollisionType.bottom;
          }
          var square = mainMatrix[mj][mi];
          if (square != null) {
            if (leftTopPoint.dx == prevLeftTopPoint.dx) {
              return CollisionType.bottom;
            } else {
              return CollisionType.edge;
            }
          }
        }
      }
    }
    return CollisionType.none;
  }

  static void pinShape(Shape shape, List<List<Square?>> mainMatrix) {
    var shapeMatrix = shape.matrixList[shape.currentIndex];
    for (var j = 0; j < shapeMatrix.length; j++) { // 纵轴是 j 横轴是 i
      for (var i = 0; i < shapeMatrix[j].length; i++) {
        var cell = shapeMatrix[j][i];
        if (cell == 1) {
          var mi = i + shape.leftTopPoint.dx.toInt();
          var mj = j + shape.leftTopPoint.dy.toInt();
          if (mi < 0 || mi >= mainMatrix[0].length) {
            return;
          }
          if (mj < 0 || mj >= mainMatrix.length) {
            return;
          }

          mainMatrix[mj][mi] = Square(shape.square.paint.color, shape.square.borderPaint.color);
        }
      }
    }
  }

  static void removeLineShape(List<List<Square?>> mainMatrix) {
    for (var j = 0; j < mainMatrix.length; j++) { // 纵轴是 j 横轴是 i
      var line = true;
      for (var i = 0; i < mainMatrix[j].length; i++) {
        var square = mainMatrix[j][i];
        if (square == null) {
          line = false;
          continue;
        }
      }

      if (line) {
        mainMatrix.removeAt(j);

        var row = <Square?>[];
        mainMatrix.insert(0, row);
        for (var i = 0; i < 10; i++) {
          row.add(null);
        }
      }
    }
  }

  static void initMainMatrix(List<List<Square?>> mainMatrix) {
    mainMatrix.clear();
    for (var i = 0; i < Config.mainMatrixHeight; i++) {
      var row = <Square?>[];
      mainMatrix.add(row);
      for (var j = 0; j < Config.mainMatrixWidth; j++) {
        row.add(null);
      }
    }
  }

  static Shape createShape() {
    var shapeList = <Shape>[I(), L(), L2(), N(), N2(), O(), T()];
    var shape = shapeList[random.nextInt(shapeList.length)];
    return shape;
  }
}

lib\game\tetris\config.dart

class Config {
  static double mainMatrixWidth = 10;
  static double mainMatrixHeight = 20;

  static double squareWidth = 20;
  static double squareBorderWidth = 2;

  static double speed = 50;
}

lib\game\tetris\controller.dart

import 'package:flutter/material.dart';

class Controller extends ChangeNotifier {

  int rotateTimes = 0;
  int leftTimes = 0;
  int rightTimes = 0;

  bool downPressed = false;

  void left() {
    leftTimes++;
    notifyListeners();
  }

  void right() {
    rightTimes++;
    notifyListeners();
  }

  void rotate() {
    rotateTimes++;
    notifyListeners();
  }
}

lib\game\tetris\shape\square.dart

import 'package:flutter/material.dart';

import '../config.dart';

class Square {

  late Paint paint;
  late Paint borderPaint;

  double width = Config.squareWidth;
  double borderWidth = Config.squareBorderWidth;

  Square(Color color, Color borderColor) {
    paint = Paint()..color = color;
    borderPaint = Paint()..color = borderColor;
  }
}

lib\game\tetris\shape\shape.dart

import 'package:flutter/material.dart';
import 'package:flutter_demo/game/tetris/shape/square.dart';

import '../config.dart';

class Shape {

  Shape(this.square) {
    leftTopOffset = Offset(3 * Config.squareWidth, 0);
    prevLeftTopOffset = Offset(3 * Config.squareWidth, 0);
  }

  Square square;
  Offset leftTopOffset = const Offset(0, 0);
  int currentIndex = 0;
  int maxIndex = 3;

  Offset prevLeftTopOffset = const Offset(0, 0);
  int prevCurrentIndex = 0;

  Offset get leftTopPoint {
    return _getLeftTopPoint(leftTopOffset);
  }
  Offset get prevLeftTopPoint {
    return _getLeftTopPoint(prevLeftTopOffset);
  }
  Offset _getLeftTopPoint(Offset offset) {
    var x = offset.dx % square.width == 0 ? offset.dx ~/ square.width : offset.dx ~/ square.width + 1;
    var y = offset.dy % square.width == 0 ? offset.dy ~/ square.width : offset.dy ~/ square.width + 1;
    return Offset(x.toDouble(), y.toDouble());
  }

  List<List<List<int>>> get matrixList => [
    [
      [],
    ],
  ];

  void render(Canvas canvas) {
    var matrix = matrixList[currentIndex];

    for (var j = 0; j < matrix.length; j++) {
      for (var i = 0; i < matrix[j].length; i++) {
        var cell = matrix[j][i];
        if (cell == 1) {
          var offsetCenter = leftTopOffset.translate(square.width / 2 + i * square.width, square.width / 2 + j * square.width);
          canvas.drawRect(Rect.fromCenter(center: offsetCenter, width: square.width, height: square.width), square.borderPaint);
          canvas.drawRect(Rect.fromCenter(center: offsetCenter, width: square.width - square.borderWidth, height: square.width - square.borderWidth), square.paint);
        }
      }
    }
  }

  void update(double dt) {
    savePrev();
    leftTopOffset = leftTopOffset.translate(0, dt * Config.speed);
  }

  void rotate() {
    savePrev();
    if (currentIndex < maxIndex) {
      currentIndex ++;
    } else {
      currentIndex = 0;
    }
  }

  void left() {
    savePrev();
    leftTopOffset = leftTopOffset.translate(-square.width, 0);
  }

  void right() {
    savePrev();
    leftTopOffset = leftTopOffset.translate(square.width, 0);
  }

  void savePrev() {
    prevLeftTopOffset = leftTopOffset;
    prevCurrentIndex = currentIndex;
  }

  void loadPrev() {
    leftTopOffset = prevLeftTopOffset;
    currentIndex = prevCurrentIndex;
  }
}

lib\game\tetris\shape\i.dart

import 'package:flutter/material.dart';
import 'package:flutter_demo/game/tetris/shape/square.dart';
import 'shape.dart';

class I extends Shape {
  I() : super(Square(Colors.red, Colors.white70));

  @override
  List<List<List<int>>> get matrixList => [
    [
      [0,1,0,0],
      [0,1,0,0],
      [0,1,0,0],
      [0,1,0,0],
    ],
    [
      [0,0,0,0],
      [1,1,1,1],
      [0,0,0,0],
      [0,0,0,0],
    ],
  ];

  @override
  int get maxIndex => 1;
}

lib\game\tetris\shape\l.dart

import 'package:flutter/material.dart';
import 'package:flutter_demo/game/tetris/shape/square.dart';
import 'shape.dart';

class L extends Shape {
  L() : super(Square(Colors.green[200]!, Colors.white70));

  @override
  List<List<List<int>>> get matrixList => [
    [
      [0,1,0,0],
      [0,1,0,0],
      [0,1,1,0],
      [0,0,0,0],
    ],
    [
      [0,0,0,0],
      [1,1,1,0],
      [1,0,0,0],
      [0,0,0,0],
    ],
    [
      [1,1,0,0],
      [0,1,0,0],
      [0,1,0,0],
      [0,0,0,0],
    ],
    [
      [0,0,1,0],
      [1,1,1,0],
      [0,0,0,0],
      [0,0,0,0],
    ],
  ];

  @override
  int get maxIndex => 3;
}

lib\game\tetris\shape\l2.dart

import 'package:flutter/material.dart';
import 'package:flutter_demo/game/tetris/shape/square.dart';
import 'shape.dart';

class L2 extends Shape {
  L2() : super(Square(Colors.green[800]!, Colors.white70));

  @override
  List<List<List<int>>> get matrixList => [
    [
      [0,0,1,0],
      [0,0,1,0],
      [0,1,1,0],
      [0,0,0,0],
    ],
    [
      [0,1,0,0],
      [0,1,1,1],
      [0,0,0,0],
      [0,0,0,0],
    ],
    [
      [0,0,1,1],
      [0,0,1,0],
      [0,0,1,0],
      [0,0,0,0],
    ],
    [
      [0,0,0,0],
      [0,1,1,1],
      [0,0,0,1],
      [0,0,0,0],
    ],
  ];

  @override
  int get maxIndex => 3;
}

lib\game\tetris\shape\n.dart

import 'package:flutter/material.dart';
import 'package:flutter_demo/game/tetris/shape/square.dart';
import 'shape.dart';

class N extends Shape {
  N() : super(Square(Colors.blue[200]!, Colors.white70));

  @override
  List<List<List<int>>> get matrixList => [
    [
      [0,0,1,0],
      [0,1,1,0],
      [0,1,0,0],
      [0,0,0,0],
    ],
    [
      [0,1,1,0],
      [0,0,1,1],
      [0,0,0,0],
      [0,0,0,0],
    ],
  ];

  @override
  int get maxIndex => 1;
}

lib\game\tetris\shape\n2.dart

import 'package:flutter/material.dart';
import 'package:flutter_demo/game/tetris/shape/square.dart';
import 'shape.dart';

class N2 extends Shape {
  N2() : super(Square(Colors.blue[800]!, Colors.white70));

  @override
  List<List<List<int>>> get matrixList => [
    [
      [0,1,0,0],
      [0,1,1,0],
      [0,0,1,0],
      [0,0,0,0],
    ],
    [
      [0,0,1,1],
      [0,1,1,0],
      [0,0,0,0],
      [0,0,0,0],
    ],
  ];

  @override
  int get maxIndex => 1;
}

lib\game\tetris\shape\o.dart

import 'package:flutter/material.dart';
import 'package:flutter_demo/game/tetris/shape/square.dart';
import 'shape.dart';

class O extends Shape {
  O() : super(Square(Colors.yellow, Colors.white70));

  @override
  List<List<List<int>>> get matrixList => [
    [
      [0,1,1,0],
      [0,1,1,0],
      [0,0,0,0],
      [0,0,0,0],
    ],
  ];

  @override
  int get maxIndex => 0;
}

lib\game\tetris\shape\t.dart

import 'package:flutter/material.dart';
import 'package:flutter_demo/game/tetris/shape/square.dart';
import 'shape.dart';

class T extends Shape {
  T() : super(Square(Colors.purple, Colors.white70));

  @override
  List<List<List<int>>> get matrixList => [
    [
      [0,1,0,0],
      [1,1,1,0],
      [0,0,0,0],
      [0,0,0,0],
    ],
    [
      [0,1,0,0],
      [0,1,1,0],
      [0,1,0,0],
      [0,0,0,0],
    ],
    [
      [0,0,0,0],
      [1,1,1,0],
      [0,1,0,0],
      [0,0,0,0],
    ],
    [
      [0,1,0,0],
      [1,1,0,0],
      [0,1,0,0],
      [0,0,0,0],
    ],
  ];

  @override
  int get maxIndex => 3;
}

源码 https://github.com/webabcd/flutter_demo
作者 webabcd

标签:square,dart,shape,一统天下,var,import,flutter,方块
From: https://www.cnblogs.com/webabcd/p/flutter_lib_game_tetris_tetris.html

相关文章

  • Flutter的SystemUiOverlayStyle类详解
    SystemUiOverlayStyle介绍Flutter中的SystemUiOverlayStyle是一个类,用于控制应用程序的系统UI(用户界面)覆盖样式。它提供了一种定制应用程序状态栏和导航栏外观的方法。SystemUiOverlayStyle的属性详解SystemUiOverlayStyle类有以下属性可以设置:statusBarColor:状态栏的背景颜色......
  • Flutter插件flutter_boost 在android模块中的报红问题解决.
    1,在开发Flutter插件时,打开插件的android项目,准备编写native端的代码时,发现各种报红,代码无法跳转,体验十分不好。就像我下面的截图一样:导入了FlutterBoostflutterBoost源码爆红。但是运行正常。。这说明本身是没有问题的。。分明是没有错误的类都存在。但是就是爆红。。。。可......
  • Android Studio中无法显示main.dart(Flutter项目在Android Studio中显示不全)
    问题描述创建完项目后只出现android文件选择ProjectFiles就会显示整个目录内容设置后......
  • Flutter example01
    import'package:flutter/material.dart';import'package:english_words/english_words.dart';voidmain()=>runApp(MyApp());classMyAppextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){//finalworldP......
  • flutter解析html的图片和链接
    html链接内容如下:"<p><ahref="https://www.hihonor.com/cn/m/notice-14658"rel="nofollow"><imgalt="750.png"src="https://hshop.honorfile.com/pimages/detailImg/2023/08/31/C757CDF3D975230D36F9176D41A90......
  • Flutter中多种状态管理方案
    Flutter中有多种状态管理方案,用于管理应用程序中的状态和数据,以确保应用的可维护性和可扩展性。以下是一些常见的Flutter状态管理方法:setState:这是Flutter中最基本的状态管理方法。在StatefulWidget中,可以使用setState方法来通知Flutter框架,界面需要被重新绘制,以反映状态的变化。......
  • 日常使用vscode开发flutter相关的插件
    简介这里整理了日常使用vscode开发flutter相关的插件,也有部分通用类型的插件Flutter&Dart这2个是flutter官方插件,开发flutter装机必备,不用多说。AwesomeFlutterSnippetsAwesomeFlutterSnippetsisacollectionsnippetsandshortcutsforcommonlyusedFlutterfunctions......
  • Flutter vs Kotlin :哪个更适合 App 开发?
    前言跨平台应用程序框架是开发人员用来为不同框架构建应用程序的工具。与原生平台不同,跨平台框架允许开发人员创建可以在多个平台(包括iOS、Android和Windows)上运行的单个应用程序,只需对开发过程进行少量修改。使用跨平台应用程序有什么好处?跨平台应用程序的显着优势之一是能够覆......
  • 阿里巴巴Flutter开源Kraken初体验
    阿里巴巴Flutter开源Kraken初体验向治洪在知乎工程师​关注他 22人赞同了该文章一、Kraken简介历时3年,阿里巴巴正式开源了基于Flutter的Web渲染引擎项目【北海】。一直以来,大家都在为跨平台开发进行不断的探索与实践,从最早的H5方案到Hybrid方案,以......
  • 关于Flutter的webview无法访问私有SSL证书链接的问题
    优先考虑用 Freessl 技术方案: 问题原因项目部署服务器的Https为私有SSL证书,目前确认不会提供共有SSL证书,导致WebView访问网页空白问题官方设计WebView插件时,为了考虑安全性在访问https链接时,必须要求SSL证书有效,不支持自定义SSL错误的处理解决方式有三种处理方式:使......