diff --git a/Tetris2000.py b/Tetris2000.py index 10e00a9..45b1ce9 100644 --- a/Tetris2000.py +++ b/Tetris2000.py @@ -21,9 +21,8 @@ import consts from consts import L, R, CLOCKWISE, COUNTERCLOCKWISE from qt5 import QtWidgets, QtCore, QtGui, QtMultimedia from __version__ import __title__, __author__, __version__ -from block import Block from point import Point -from tetromino import Tetromino, GhostPiece +from tetromino import Block, Tetromino, GhostPiece class Grid(QtWidgets.QWidget): @@ -113,6 +112,7 @@ class Matrix(Grid): self.setFocusPolicy(QtCore.Qt.StrongFocus) + self.auto_repeat_delay = 0 self.auto_repeat_timer = QtCore.QTimer() self.auto_repeat_timer.setTimerType(QtCore.Qt.PreciseTimer) self.auto_repeat_timer.timeout.connect(self.auto_repeat) @@ -175,8 +175,8 @@ class Matrix(Grid): self.do(action) if action in (s.MOVE_LEFT, s.MOVE_RIGHT, s.SOFT_DROP): if action not in self.actions_to_repeat: - self.actions_to_repeat.append(action) self.auto_repeat_wait() + self.actions_to_repeat.append(action) def keyReleaseEvent(self, event): if event.isAutoRepeat(): @@ -339,6 +339,7 @@ class Matrix(Grid): if mino.coord.y() >= 0: self.cells[mino.coord.y()][mino.coord.x()] = mino mino.shine(glowing=2, delay=consts.ANIMATION_DELAY) + QtCore.QTimer.singleShot(consts.ANIMATION_DELAY, self.update) self.update() if all( diff --git a/block.py b/block.py deleted file mode 100644 index d4705c9..0000000 --- a/block.py +++ /dev/null @@ -1,130 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - - -import consts -from consts import U, D -from point import Point -from qt5 import QtCore, QtGui - - -class Block: - """ - Mino or block - Mino : A single square-shaped building block of a shape called a Tetrimino. - Four Minos arranged into any of their various connected patterns is known as a Tetrimino - Block : A single block locked in a cell in the Grid - """ - - # Colors - BORDER_COLOR = consts.BLOCK_BORDER_COLOR - FILL_COLOR = consts.BLOCK_FILL_COLOR - GLOWING_BORDER_COLOR = consts.BLOCK_GLOWING_BORDER_COLOR - GLOWING_FILL_COLOR = consts.BLOCK_GLOWING_FILL_COLOR - LIGHT_COLOR = consts.BLOCK_LIGHT_COLOR - TRANSPARENT = consts.BLOCK_TRANSPARENT - GLOWING = consts.BLOCK_GLOWING - - side = consts.BLOCK_INITIAL_SIDE - - def __init__(self, coord, trail=0): - self.coord = coord - self.trail = trail - self.border_color = self.BORDER_COLOR - self.fill_color = self.FILL_COLOR - self.glowing = self.GLOWING - - def paint(self, painter, top_left_corner, spotlight): - p = top_left_corner + self.coord * Block.side - block_center = Point(Block.side / 2, Block.side / 2) - self.center = p + block_center - spotlight = top_left_corner + Block.side * spotlight + block_center - self.glint = 0.15 * spotlight + 0.85 * self.center - - if self.trail: - start = ( - top_left_corner + (self.coord + Point(0, self.trail * U)) * Block.side - ) - stop = top_left_corner + (self.coord + Point(0, 2 * D)) * Block.side - fill = QtGui.QLinearGradient(start, stop) - fill.setColorAt(0, self.LIGHT_COLOR) - fill.setColorAt(1, self.GLOWING_FILL_COLOR) - painter.setBrush(fill) - painter.setPen(QtCore.Qt.NoPen) - painter.drawRoundedRect( - start.x(), - start.y(), - Block.side, - Block.side * (1 + self.trail), - 20, - 20, - QtCore.Qt.RelativeSize, - ) - - if self.glowing: - fill = QtGui.QRadialGradient(self.center, self.glowing * Block.side) - fill.setColorAt(0, self.TRANSPARENT) - fill.setColorAt(0.5 / self.glowing, self.LIGHT_COLOR) - fill.setColorAt(1, self.TRANSPARENT) - painter.setBrush(QtGui.QBrush(fill)) - painter.setPen(QtCore.Qt.NoPen) - painter.drawEllipse( - self.center.x() - self.glowing * Block.side, - self.center.y() - self.glowing * Block.side, - 2 * self.glowing * Block.side, - 2 * self.glowing * Block.side, - ) - - painter.setBrush(self.brush()) - painter.setPen(self.pen()) - painter.drawRoundedRect( - p.x() + 1, - p.y() + 1, - Block.side - 2, - Block.side - 2, - 20, - 20, - QtCore.Qt.RelativeSize, - ) - - def brush(self): - if self.fill_color is None: - return QtCore.Qt.NoBrush - - fill = QtGui.QRadialGradient(self.glint, 1.5 * Block.side) - fill.setColorAt(0, self.fill_color.lighter()) - fill.setColorAt(1, self.fill_color) - return QtGui.QBrush(fill) - - def pen(self): - if self.border_color is None: - return QtCore.Qt.NoPen - - border = QtGui.QRadialGradient(self.glint, Block.side) - border.setColorAt(0, self.border_color.lighter()) - border.setColorAt(1, self.border_color.darker()) - return QtGui.QPen(QtGui.QBrush(border), 1, join=QtCore.Qt.RoundJoin) - - def shine(self, glowing=2, delay=None): - self.border_color = Block.GLOWING_BORDER_COLOR - self.fill_color = Block.GLOWING_FILL_COLOR - self.glowing = glowing - if delay: - QtCore.QTimer.singleShot(delay, self.fade) - - def fade(self): - self.border_color = Block.BORDER_COLOR - self.fill_color = Block.FILL_COLOR - self.glowing = 0 - self.trail = 0 - - -class GhostBlock(Block): - """ - Mino of the ghost piece - """ - - BORDER_COLOR = consts.GHOST_BLOCK_BORDER_COLOR - FILL_COLOR = consts.GHOST_BLOCK_FILL_COLOR - GLOWING_FILL_COLOR = consts.GHOST_BLOCK_GLOWING_FILL_COLOR - GLOWING = consts.GHOST_BLOCK_GLOWING diff --git a/consts.py b/consts.py index 5af9e7d..377c979 100644 --- a/consts.py +++ b/consts.py @@ -32,7 +32,7 @@ L, R, U, D = -1, 1, -1, 1 # Left, Right, Up, Down CLOCKWISE, COUNTERCLOCKWISE = 1, -1 # Delays in milliseconds -ANIMATION_DELAY = 100 +ANIMATION_DELAY = 67 INITIAL_SPEED = 1000 ENTRY_DELAY = 80 LINE_CLEAR_DELAY = 80 diff --git a/tetromino.py b/tetromino.py index c128bac..c218695 100644 --- a/tetromino.py +++ b/tetromino.py @@ -4,9 +4,132 @@ import random +import consts from consts import L, R, U, D, CLOCKWISE, COUNTERCLOCKWISE from point import Point -from block import Block, GhostBlock +from qt5 import QtCore, QtGui + + +class Block: + """ + Mino or block + Mino : A single square-shaped building block of a shape called a Tetrimino. + Four Minos arranged into any of their various connected patterns is known as a Tetrimino + Block : A single block locked in a cell in the Grid + """ + + # Colors + BORDER_COLOR = consts.BLOCK_BORDER_COLOR + FILL_COLOR = consts.BLOCK_FILL_COLOR + GLOWING_BORDER_COLOR = consts.BLOCK_GLOWING_BORDER_COLOR + GLOWING_FILL_COLOR = consts.BLOCK_GLOWING_FILL_COLOR + LIGHT_COLOR = consts.BLOCK_LIGHT_COLOR + TRANSPARENT = consts.BLOCK_TRANSPARENT + GLOWING = consts.BLOCK_GLOWING + + side = consts.BLOCK_INITIAL_SIDE + + def __init__(self, coord, trail=0): + self.coord = coord + self.trail = trail + self.border_color = self.BORDER_COLOR + self.fill_color = self.FILL_COLOR + self.glowing = self.GLOWING + + def paint(self, painter, top_left_corner, spotlight): + p = top_left_corner + self.coord * Block.side + block_center = Point(Block.side / 2, Block.side / 2) + self.center = p + block_center + spotlight = top_left_corner + Block.side * spotlight + block_center + self.glint = 0.15 * spotlight + 0.85 * self.center + + if self.trail: + start = ( + top_left_corner + (self.coord + Point(0, self.trail * U)) * Block.side + ) + stop = top_left_corner + (self.coord + Point(0, 2 * D)) * Block.side + fill = QtGui.QLinearGradient(start, stop) + fill.setColorAt(0, self.LIGHT_COLOR) + fill.setColorAt(1, self.GLOWING_FILL_COLOR) + painter.setBrush(fill) + painter.setPen(QtCore.Qt.NoPen) + painter.drawRoundedRect( + start.x(), + start.y(), + Block.side, + Block.side * (1 + self.trail), + 20, + 20, + QtCore.Qt.RelativeSize, + ) + + if self.glowing: + fill = QtGui.QRadialGradient(self.center, self.glowing * Block.side) + fill.setColorAt(0, self.TRANSPARENT) + fill.setColorAt(0.5 / self.glowing, self.LIGHT_COLOR) + fill.setColorAt(1, self.TRANSPARENT) + painter.setBrush(QtGui.QBrush(fill)) + painter.setPen(QtCore.Qt.NoPen) + painter.drawEllipse( + self.center.x() - self.glowing * Block.side, + self.center.y() - self.glowing * Block.side, + 2 * self.glowing * Block.side, + 2 * self.glowing * Block.side, + ) + + painter.setBrush(self.brush()) + painter.setPen(self.pen()) + painter.drawRoundedRect( + p.x() + 1, + p.y() + 1, + Block.side - 2, + Block.side - 2, + 20, + 20, + QtCore.Qt.RelativeSize, + ) + + def brush(self): + if self.fill_color is None: + return QtCore.Qt.NoBrush + + fill = QtGui.QRadialGradient(self.glint, 1.5 * Block.side) + fill.setColorAt(0, self.fill_color.lighter()) + fill.setColorAt(1, self.fill_color) + return QtGui.QBrush(fill) + + def pen(self): + if self.border_color is None: + return QtCore.Qt.NoPen + + border = QtGui.QRadialGradient(self.glint, Block.side) + border.setColorAt(0, self.border_color.lighter()) + border.setColorAt(1, self.border_color.darker()) + return QtGui.QPen(QtGui.QBrush(border), 1, join=QtCore.Qt.RoundJoin) + + def shine(self, glowing=2, delay=None): + self.border_color = Block.GLOWING_BORDER_COLOR + self.fill_color = Block.GLOWING_FILL_COLOR + self.glowing = glowing + if delay: + QtCore.QTimer.singleShot(delay, self.fade) + + def fade(self): + self.border_color = Block.BORDER_COLOR + self.fill_color = Block.FILL_COLOR + self.glowing = 0 + self.trail = 0 + + +class GhostBlock(Block): + """ + Mino of the ghost piece + """ + + BORDER_COLOR = consts.GHOST_BLOCK_BORDER_COLOR + FILL_COLOR = consts.GHOST_BLOCK_FILL_COLOR + GLOWING_FILL_COLOR = consts.GHOST_BLOCK_GLOWING_FILL_COLOR + GLOWING = consts.GHOST_BLOCK_GLOWING class MetaTetro(type): @@ -76,7 +199,7 @@ class Tetromino: self.matrix = matrix self.minoes = tuple(Block(Point(*coord) + position) for coord in self.COORDS) - def _try_movement(self, next_coords_generator, trail=0): + def _try_movement(self, next_coords_generator, trail=0, update=True): """ Test if self can fit in the Grid with new coordinates, i.e. all cells are empty. @@ -93,10 +216,11 @@ class Tetromino: for block, future_coord in zip(self.minoes, futures_coords): block.coord = future_coord block.trail = trail - self.matrix.update() + if update: + self.matrix.update() return True - def move(self, horizontally, vertically, trail=0): + def move(self, horizontally, vertically, trail=0, update=True): """ Try to translate self horizontally or vertically The Tetrimino in play falls from just above the Skyline one cell at a time, @@ -110,6 +234,7 @@ class Tetromino: return self._try_movement( (block.coord + Point(horizontally, vertically) for block in self.minoes), trail, + update ) def rotate(self, direction=CLOCKWISE): @@ -141,15 +266,16 @@ class Tetromino: """ return self.move(0, D, trail=1) - def hard_drop(self): + def hard_drop(self, show_trail=True, update=True): """ Causes the Tetrimino in play to drop straight down instantly from its current location and Lock Down on the first Surface it lands on. It does not allow for further player manipulation of the Tetrimino in play. """ trail = 0 - while self.move(0, D, trail=trail): - trail += 1 + while self.move(0, D, trail=trail, update=update): + if show_trail: + trail += 1 return trail @@ -293,8 +419,4 @@ class GhostPiece(Tetromino): self.minoes = tuple( GhostBlock(Point(mino.coord.x(), mino.coord.y())) for mino in piece.minoes ) - self.hard_drop() - - def hard_drop(self): - while self.move(0, D): - pass + self.hard_drop(show_trail=False, update=False)