Flutter/블럭 퍼즐 맞추기(Android)

[Flutter] 위젯 원하는 위치에 배치하기(Positioned) & 테트리스 모양 만들기

FDG 2023. 6. 5. 00:24
Positioned을 이용하면 원하는 위치에 픽셀 단위로 배치를 할 수 있다.

 

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class TetrisBlocks {
  final List<List<int>> shape;

  TetrisBlocks(this.shape);
}

class MyApp extends StatelessWidget {
  final TetrisBlocks iTetrisBlocks = TetrisBlocks([
    [1, 1, 1, 1],
  ]);

  final TetrisBlocks jTetrisBlocks = TetrisBlocks([
    [1, 0, 0],
    [1, 1, 1],
  ]);

  final TetrisBlocks lTetrisBlocks = TetrisBlocks([
    [0, 0, 1],
    [1, 1, 1],
  ]);

  final TetrisBlocks oTetrisBlocks = TetrisBlocks([
    [1, 1],
    [1, 1],
  ]);

  final TetrisBlocks sTetrisBlocks = TetrisBlocks([
    [0, 1, 1],
    [1, 1, 0],
  ]);

  final TetrisBlocks tTetrisBlocks = TetrisBlocks([
    [0, 1, 0],
    [1, 1, 1],
  ]);

  final TetrisBlocks zTetrisBlocks = TetrisBlocks([
    [1, 1, 0],
    [0, 1, 1],
  ]);

  final TetrisBlocks zFlipTetrisBlocks = TetrisBlocks([
    [0, 1, 1],
    [1, 1, 0],
  ]);

  final TetrisBlocks thumbTetrisBlocks = TetrisBlocks([
    [0, 1],
    [1, 1],
    [1, 1],
  ]);

  final TetrisBlocks halfITetrisBlocks = TetrisBlocks([
    [1],
    [1],
  ]);
  final TetrisBlocks bigOTetrisBlocks = TetrisBlocks([
    [1, 1],
    [1, 1],
    [1, 1],
  ]);

  List<List<int>> _rotateShape(List<List<int>> shape) {
    int rows = shape.length;
    int columns = shape[0].length;

    List<List<int>> rotatedShape =
        List.generate(columns, (index) => List.generate(rows, (index) => 0));

    for (int i = 0; i < rows; i++) {
      for (int j = 0; j < columns; j++) {
        rotatedShape[j][rows - i - 1] = shape[i][j];
      }
    }

    return rotatedShape;
  }

  Widget _buildTetrisBlocks(TetrisBlocks tetrisBlocks, int rotation, Color c,
      double size, double gap) {
    List<List<int>> rotatedShape = tetrisBlocks.shape;
    for (int i = 0; i < rotation; i++) {
      rotatedShape = _rotateShape(rotatedShape);
    }
    return Column(
      children: rotatedShape.map((row) {
        return Row(
          children: row.map((block) {
            return Container(
              width: size,
              height: size,
              color: block == 1 ? c : Colors.transparent,
              margin: EdgeInsets.all(gap),
            );
          }).toList(),
        );
      }).toList(),
    );
  }

  @override
  Widget build(BuildContext context) {
    double gapSize = 0;
    double blockSize = 20;
    double gridSize = blockSize + gapSize;
    double hCenter = MediaQuery.of(context).size.width / 2;
    double vCenter = MediaQuery.of(context).size.height / 2;

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Tetris Shapes')),
        body: Center(
          child: Stack(
            children: [
              Positioned(
                top: vCenter + gridSize * 0,
                left: hCenter + gridSize * 0,
                child: _buildTetrisBlocks(
                    iTetrisBlocks, 0, Colors.red, blockSize, gapSize),
              ),
              Positioned(
                top: vCenter + gridSize * 1,
                left: hCenter + gridSize * 0,
                child: _buildTetrisBlocks(
                    iTetrisBlocks, 1, Colors.grey, blockSize, gapSize),
              ),
              Positioned(
                top: vCenter + gridSize * 1,
                left: hCenter + gridSize * 1,
                child: _buildTetrisBlocks(
                    oTetrisBlocks, 0, Colors.green, blockSize, gapSize),
              ),
              Positioned(
                top: vCenter + gridSize * 2,
                left: hCenter + gridSize * 1,
                child: _buildTetrisBlocks(
                    lTetrisBlocks, 0, Colors.cyan, blockSize, gapSize),
              ),
              Positioned(
                top: vCenter + gridSize * 3,
                left: hCenter + gridSize * 3,
                child: _buildTetrisBlocks(
                    tTetrisBlocks, 3, Colors.yellow, blockSize, gapSize),
              ),
              Positioned(
                top: vCenter + gridSize * 0,
                left: hCenter + gridSize * 3,
                child: _buildTetrisBlocks(
                    tTetrisBlocks, 3, Colors.orange, blockSize, gapSize),
              ),
              Positioned(
                top: vCenter + gridSize * 4,
                left: hCenter + gridSize * 0,
                child: _buildTetrisBlocks(
                    zFlipTetrisBlocks, 0, Colors.black, blockSize, gapSize),
              ),
              Positioned(
                top: vCenter + gridSize * 5,
                left: hCenter + gridSize * 2,
                child: _buildTetrisBlocks(thumbTetrisBlocks, 1,
                    Colors.deepOrange, blockSize, gapSize),
              ),
              Positioned(
                top: vCenter + gridSize * 5,
                left: hCenter + gridSize * -1,
                child: _buildTetrisBlocks(
                    jTetrisBlocks, 0, Colors.blue, blockSize, gapSize),
              ),
              Positioned(
                top: vCenter + gridSize * 4,
                left: hCenter + gridSize * -2,
                child: _buildTetrisBlocks(
                    jTetrisBlocks, 1, Colors.amber, blockSize, gapSize),
              ),
              Positioned(
                top: vCenter + gridSize * 3,
                left: hCenter + gridSize * -2,
                child: _buildTetrisBlocks(
                    halfITetrisBlocks, 1, Colors.lime, blockSize, gapSize),
              ),
              Positioned(
                top: vCenter + gridSize * 0,
                left: hCenter + gridSize * -2,
                child: _buildTetrisBlocks(
                    bigOTetrisBlocks, 0, Colors.teal, blockSize, gapSize),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

결과