Files
tetri5/entity/Piece.py
2021-06-10 18:25:54 -04:00

138 lines
6.1 KiB
Python

from typing import List, Tuple
from pygame import mixer
import pygame
import copy
from entity.Entity import Entity
from util.ConfigurationManager import ConfigurationManager
'''
For information on the Tetris piece Tetromino go here:
https://tetris.fandom.com/wiki/Tetromino
'''
class Piece(Entity):
def __init__(self, shape: Tuple, position: Tuple, color: str, inner_border_color: str, border_color: str):
super().__init__(self.__get_points(shape, position), color, border_color)
self.inner_border_color = inner_border_color
self.center = self.__get_center(shape, position)
self.gravity_time = ConfigurationManager.configuration["engine"]["piece-gravity-time"]
self.current_gravity_time = 0
self.set_time = ConfigurationManager.configuration["engine"]["piece-set-time"]
self.current_set_time = 0
self.piece_set_sound = mixer.Channel(2)
self.previous_points = None
self.previous_center = None
def update(self, elapsed_time: int, tetris) -> None:
super().update(elapsed_time)
well = tetris.well
stack = tetris.stack
tile_size = ConfigurationManager.configuration["engine"]["tile-size"]
if self.elapsed_time >= self.gravity_time and self.current_set_time == 0:
self.elapsed_time = 0
self.move((0, tile_size))
if well and self.collide(well) or stack and self.collide(stack):
self.revert()
self.current_set_time += elapsed_time
if self.current_set_time > 0:
self.current_set_time += elapsed_time
if self.current_set_time >= self.set_time:
self.__play_piece_set_sound()
self.current_set_time = 0
stack.add_piece(self)
tetris.current_piece = None
def draw(self, surface: pygame.Surface) -> None:
super().draw(surface)
tile_size = ConfigurationManager.configuration["engine"]["tile-size"]
for square in self.points:
if self.inner_border_color:
vertex_one = (square[0][0] + (tile_size // 10), square[0][1] + (tile_size // 10))
vertex_two = (square[1][0] - (tile_size // 10), square[1][1] + (tile_size // 10))
vertex_three = (square[2][0] - (tile_size // 10), square[2][1] - (tile_size // 10))
vertex_four = (square[3][0] + (tile_size // 10), square[3][1] - (tile_size // 10))
new_square = (vertex_one, vertex_two, vertex_three, vertex_four)
pygame.draw.polygon(surface, pygame.Color(self.inner_border_color), new_square, max(tile_size // 6, 1))
def move(self, vector: Tuple) -> None:
# reset elapsed time if user moves down to stall gravity
if vector[1] > 0:
self.elapsed_time = 0
self.previous_points = copy.deepcopy(self.points)
self.previous_center = copy.deepcopy(self.center)
self.center[0] += vector[0]
self.center[1] += vector[1]
for sub_points in self.points:
for point in sub_points:
point[0] += vector[0]
point[1] += vector[1]
'''
For more information on a rotation of a piece go here:
https://gamedev.stackexchange.com/questions/17974/how-to-rotate-blocks-in-tetris
'''
def rotate(self) -> None:
self.previous_points = copy.deepcopy(self.points)
self.previous_center = copy.deepcopy(self.center)
new_points = []
for square in self.points:
for vertex in square:
h = vertex[0] - self.center[0]
k = vertex[1] - self.center[1]
vertex[0] = (k * -1) + self.center[0]
vertex[1] = h + self.center[1]
new_points.append([square[-1]] + square[0:-1])
self.points = new_points
def revert(self) -> None:
if self.previous_points and self.previous_center:
self.points = self.previous_points
self.center = self.previous_center
def __play_piece_set_sound(self) -> None:
piece_set_sound_file = ConfigurationManager.configuration["sound"]["piece-set"]
self.piece_set_sound.play(mixer.Sound(piece_set_sound_file))
def __get_points(self, shape: Tuple, position: Tuple) -> List:
tile_size = ConfigurationManager.configuration["engine"]["tile-size"]
points = []
for square in shape[:-1]:
sub_points = []
for vertex in square:
point = [vertex[0] * tile_size + position[0], vertex[1] * tile_size + position[1]]
sub_points.append(point)
points.append(sub_points)
return points
def __get_center(self, shape: Tuple, position: Tuple) -> List:
tile_size = ConfigurationManager.configuration["engine"]["tile-size"]
center = shape[-1]
# cast to int and avoid exception from pygame
return [int(center[0] * tile_size + position[0]), int(center[1] * tile_size + position[1])]
# shape attributes
I_SHAPE = (((0, 0), (1, 0), (1, 1), (0, 1)), ((1, 0), (2, 0), (2, 1), (1, 1)), ((2, 0), (3, 0), (3, 1), (2, 1)), ((3, 0), (4, 0), (4, 1), (3, 1)), (2, 0))
J_SHAPE = (((0, 0), (1, 0), (1, 1), (0, 1)), ((1, 0), (2, 0), (2, 1), (1, 1)), ((2, 0), (3, 0), (3, 1), (2, 1)), ((2, 1), (3, 1), (3, 2), (2, 2)), (1.5, 0.5))
L_SHAPE = (((0, 0), (1, 0), (1, 1), (0, 1)), ((1, 0), (2, 0), (2, 1), (1, 1)), ((2, 0), (3, 0), (3, 1), (2, 1)), ((0, 1), (1, 1), (1, 2), (0, 2)), (1.5, 0.5))
O_SHAPE = (((0, 0), (1, 0), (1, 1), (0, 1)), ((1, 0), (2, 0), (2, 1), (1, 1)), ((1, 1), (2, 1), (2, 2), (1, 2)), ((0, 1), (1, 1), (1, 2), (0, 2)), (1, 1))
S_SHAPE = (((0, 1), (1, 1), (1, 2), (0, 2)), ((1, 0), (2, 0), (2, 1), (1, 1)), ((1, 1), (2, 1), (2, 2), (1, 2)), ((2, 0), (3, 0), (3, 1), (2, 1)), (1.5, 0.5))
T_SHAPE = (((0, 0), (1, 0), (1, 1), (0, 1)), ((1, 0), (2, 0), (2, 1), (1, 1)), ((1, 1), (2, 1), (2, 2), (1, 2)), ((2, 0), (3, 0), (3, 1), (2, 1)), (1.5, 0.5))
Z_SHAPE = (((0, 0), (1, 0), (1, 1), (0, 1)), ((1, 0), (2, 0), (2, 1), (1, 1)), ((1, 1), (2, 1), (2, 2), (1, 2)), ((2, 1), (3, 1), (3, 2), (2, 2)), (1.5, 0.5))