import random import pygame as pg from .settings import * class Block(pg.sprite.Sprite): def __init__(self, tetromino, pos, color) -> None: from .tetromino import Tetromino self.tetromino: Tetromino = tetromino self.pos = vec(pos) + vec((FIELD_W//2, 0)) self.dead = False super().__init__(tetromino.tetris.sprite_group) self.image = pg.Surface([TILE_SIZE, TILE_SIZE]) # TODO user custom border radius pg.draw.rect(self.image, color, (1, 1, TILE_SIZE, TILE_SIZE), border_radius=TILE_SIZE//2-5) self.rect = self.image.get_rect() def rotate(self, pivot: vec) -> vec: # because pygame rotates by origin, need to specify pivot ''' Rotate 90 degress with pivot as origin Parameters ---------- pivot : vec origin port for block rotation. Returns ------- Vector2 rotated position. ''' return (self.pos - pivot).rotate(90) + pivot def set_rect_pos(self): self.rect.topleft = int(self.pos[0]) * TILE_SIZE, int(self.pos[1]) * TILE_SIZE def is_collide(self, dt: vec) -> bool: x, y = tuple(map(int, self.pos + dt)) if (0 <= x < FIELD_W and y < FIELD_H) and (y < 0 or not self.tetromino.tetris.blocks[y][x]): return False return True def update(self): ''' make pos update ease, should update in tetromino class though ''' if self.dead: self.kill() else: self.set_rect_pos() class Tetromino: def __init__(self, tetris, shape: str) -> None: from .tetris import Tetris self.tetris: Tetris = tetris self.shape = shape self.color = TETROMINO_COLORS[shape] self.blocks = [Block(self, pos, self.color) for pos in TETROMINOES[self.shape]] self.landed = False # hack to display full block for i in range(-min((pos_y for _pos_x, pos_y in TETROMINOES[self.shape])) - 1): self.move('d') min((float(i) for i in range(5))) def is_collide(self, dt: vec) -> bool: ''' check every block if is collided. Returns ------- bool True if collide ''' return any((i.is_collide(dt) for i in self.blocks)) def rotate(self): ''' Rotate the tetromino if possible, say not collide. ''' rotatable = True pivot_pos = self.blocks[0].pos for i in self.blocks[1:]: if i.is_collide(i.rotate(pivot_pos) - i.pos): rotatable = False break if rotatable: for i in self.blocks: i.pos = i.rotate(pivot_pos) def move(self, direction): movevec = MOVE_DIRECTIONS[direction] # landing check if not self.is_collide(movevec): for block in self.blocks: block.pos += movevec elif direction == 'd': self.landed = True def update(self): ''' update function called every time need to fall a cell ''' self.move('d')