Files
tetri5/entity/Piece.py

169 lines
7.4 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.piece_set_sound = mixer.Channel(2)
self.previous_points = None
self.previous_center = None
# Gravity
self.gravity_time = ConfigurationManager.configuration["engine"]["piece-gravity-time"]
self.current_gravity_time = 0
self.applying_gravity = True
# Set
self.set_time = ConfigurationManager.configuration["engine"]["piece-set-time"]
self.current_set_time = 0
self.applying_set = False
def update(self, elapsed_time: int, tetris) -> None:
super().update(elapsed_time)
if self.applying_gravity:
self.applying_gravity = self.__apply_gravity(elapsed_time, tetris.well, tetris.stack)
self.applying_set = not self.applying_gravity
if self.applying_set:
self.applying_set = self.__apply_set(elapsed_time, tetris)
self.applying_gravity = not self.applying_set
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:
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 square in self.points:
for vertex in square:
vertex[0] += vector[0]
vertex[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 __mimic_move(self, vector: Tuple): # TODO figure out how to annotate return type as Piece
mimic_points = copy.deepcopy(self.points)
for square in mimic_points:
for vertex in square:
vertex[0] += vector[0]
vertex[1] += vector[1]
return mimic_points
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 (center can be a floating point)
return [int(center[0] * tile_size + position[0]), int(center[1] * tile_size + position[1])]
def __apply_gravity(self, elapsed_time, well, stack) -> bool: # TODO define well and stack type
tile_size = ConfigurationManager.configuration["engine"]["tile-size"]
self.current_gravity_time += elapsed_time
if self.current_gravity_time >= self.gravity_time:
self.current_gravity_time = 0
if not self.__entity_is_below(well) and not self.__entity_is_below(stack):
self.move((0, tile_size))
else:
return False
return True
def __apply_set(self, elapsed_time, tetris) -> bool: # TODO define tetris type
self.current_set_time += elapsed_time
if self.current_set_time >= self.set_time:
self.current_set_time = 0
if self.__entity_is_below(tetris.well) or self.__entity_is_below(tetris.stack):
self.__play_piece_set_sound()
tetris.stack.add_piece(self) # TODO do on tetris object level?
tetris.current_piece = None # TODO turn into a method
else:
return False
return True
def __entity_is_below(self, entity: Entity) -> bool: # TODO
tile_size = ConfigurationManager.configuration["engine"]["tile-size"]
mimic_points = self.__mimic_move((0, tile_size))
return entity and entity.collide_points(mimic_points)
# 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))