Reduce latency with no updating on ghost hard drop, merge block.py with tetromino.py
This commit is contained in:
parent
3bd090b38e
commit
095e0ebf62
@ -21,9 +21,8 @@ import consts
|
|||||||
from consts import L, R, CLOCKWISE, COUNTERCLOCKWISE
|
from consts import L, R, CLOCKWISE, COUNTERCLOCKWISE
|
||||||
from qt5 import QtWidgets, QtCore, QtGui, QtMultimedia
|
from qt5 import QtWidgets, QtCore, QtGui, QtMultimedia
|
||||||
from __version__ import __title__, __author__, __version__
|
from __version__ import __title__, __author__, __version__
|
||||||
from block import Block
|
|
||||||
from point import Point
|
from point import Point
|
||||||
from tetromino import Tetromino, GhostPiece
|
from tetromino import Block, Tetromino, GhostPiece
|
||||||
|
|
||||||
|
|
||||||
class Grid(QtWidgets.QWidget):
|
class Grid(QtWidgets.QWidget):
|
||||||
@ -113,6 +112,7 @@ class Matrix(Grid):
|
|||||||
|
|
||||||
self.setFocusPolicy(QtCore.Qt.StrongFocus)
|
self.setFocusPolicy(QtCore.Qt.StrongFocus)
|
||||||
|
|
||||||
|
self.auto_repeat_delay = 0
|
||||||
self.auto_repeat_timer = QtCore.QTimer()
|
self.auto_repeat_timer = QtCore.QTimer()
|
||||||
self.auto_repeat_timer.setTimerType(QtCore.Qt.PreciseTimer)
|
self.auto_repeat_timer.setTimerType(QtCore.Qt.PreciseTimer)
|
||||||
self.auto_repeat_timer.timeout.connect(self.auto_repeat)
|
self.auto_repeat_timer.timeout.connect(self.auto_repeat)
|
||||||
@ -175,8 +175,8 @@ class Matrix(Grid):
|
|||||||
self.do(action)
|
self.do(action)
|
||||||
if action in (s.MOVE_LEFT, s.MOVE_RIGHT, s.SOFT_DROP):
|
if action in (s.MOVE_LEFT, s.MOVE_RIGHT, s.SOFT_DROP):
|
||||||
if action not in self.actions_to_repeat:
|
if action not in self.actions_to_repeat:
|
||||||
self.actions_to_repeat.append(action)
|
|
||||||
self.auto_repeat_wait()
|
self.auto_repeat_wait()
|
||||||
|
self.actions_to_repeat.append(action)
|
||||||
|
|
||||||
def keyReleaseEvent(self, event):
|
def keyReleaseEvent(self, event):
|
||||||
if event.isAutoRepeat():
|
if event.isAutoRepeat():
|
||||||
@ -339,6 +339,7 @@ class Matrix(Grid):
|
|||||||
if mino.coord.y() >= 0:
|
if mino.coord.y() >= 0:
|
||||||
self.cells[mino.coord.y()][mino.coord.x()] = mino
|
self.cells[mino.coord.y()][mino.coord.x()] = mino
|
||||||
mino.shine(glowing=2, delay=consts.ANIMATION_DELAY)
|
mino.shine(glowing=2, delay=consts.ANIMATION_DELAY)
|
||||||
|
QtCore.QTimer.singleShot(consts.ANIMATION_DELAY, self.update)
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
if all(
|
if all(
|
||||||
|
130
block.py
130
block.py
@ -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
|
|
@ -32,7 +32,7 @@ L, R, U, D = -1, 1, -1, 1 # Left, Right, Up, Down
|
|||||||
CLOCKWISE, COUNTERCLOCKWISE = 1, -1
|
CLOCKWISE, COUNTERCLOCKWISE = 1, -1
|
||||||
|
|
||||||
# Delays in milliseconds
|
# Delays in milliseconds
|
||||||
ANIMATION_DELAY = 100
|
ANIMATION_DELAY = 67
|
||||||
INITIAL_SPEED = 1000
|
INITIAL_SPEED = 1000
|
||||||
ENTRY_DELAY = 80
|
ENTRY_DELAY = 80
|
||||||
LINE_CLEAR_DELAY = 80
|
LINE_CLEAR_DELAY = 80
|
||||||
|
146
tetromino.py
146
tetromino.py
@ -4,9 +4,132 @@
|
|||||||
|
|
||||||
import random
|
import random
|
||||||
|
|
||||||
|
import consts
|
||||||
from consts import L, R, U, D, CLOCKWISE, COUNTERCLOCKWISE
|
from consts import L, R, U, D, CLOCKWISE, COUNTERCLOCKWISE
|
||||||
from point import Point
|
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):
|
class MetaTetro(type):
|
||||||
@ -76,7 +199,7 @@ class Tetromino:
|
|||||||
self.matrix = matrix
|
self.matrix = matrix
|
||||||
self.minoes = tuple(Block(Point(*coord) + position) for coord in self.COORDS)
|
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,
|
Test if self can fit in the Grid with new coordinates,
|
||||||
i.e. all cells are empty.
|
i.e. all cells are empty.
|
||||||
@ -93,10 +216,11 @@ class Tetromino:
|
|||||||
for block, future_coord in zip(self.minoes, futures_coords):
|
for block, future_coord in zip(self.minoes, futures_coords):
|
||||||
block.coord = future_coord
|
block.coord = future_coord
|
||||||
block.trail = trail
|
block.trail = trail
|
||||||
self.matrix.update()
|
if update:
|
||||||
|
self.matrix.update()
|
||||||
return True
|
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
|
Try to translate self horizontally or vertically
|
||||||
The Tetrimino in play falls from just above the Skyline one cell at a time,
|
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(
|
return self._try_movement(
|
||||||
(block.coord + Point(horizontally, vertically) for block in self.minoes),
|
(block.coord + Point(horizontally, vertically) for block in self.minoes),
|
||||||
trail,
|
trail,
|
||||||
|
update
|
||||||
)
|
)
|
||||||
|
|
||||||
def rotate(self, direction=CLOCKWISE):
|
def rotate(self, direction=CLOCKWISE):
|
||||||
@ -141,15 +266,16 @@ class Tetromino:
|
|||||||
"""
|
"""
|
||||||
return self.move(0, D, trail=1)
|
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
|
Causes the Tetrimino in play to drop straight down instantly from its
|
||||||
current location and Lock Down on the first Surface it lands on.
|
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.
|
It does not allow for further player manipulation of the Tetrimino in play.
|
||||||
"""
|
"""
|
||||||
trail = 0
|
trail = 0
|
||||||
while self.move(0, D, trail=trail):
|
while self.move(0, D, trail=trail, update=update):
|
||||||
trail += 1
|
if show_trail:
|
||||||
|
trail += 1
|
||||||
return trail
|
return trail
|
||||||
|
|
||||||
|
|
||||||
@ -293,8 +419,4 @@ class GhostPiece(Tetromino):
|
|||||||
self.minoes = tuple(
|
self.minoes = tuple(
|
||||||
GhostBlock(Point(mino.coord.x(), mino.coord.y())) for mino in piece.minoes
|
GhostBlock(Point(mino.coord.x(), mino.coord.y())) for mino in piece.minoes
|
||||||
)
|
)
|
||||||
self.hard_drop()
|
self.hard_drop(show_trail=False, update=False)
|
||||||
|
|
||||||
def hard_drop(self):
|
|
||||||
while self.move(0, D):
|
|
||||||
pass
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user