pygame-tetris/tetris_pygame_hatch/tetromino.py

105 lines
3.1 KiB
Python
Raw Permalink Normal View History

2024-01-19 16:39:03 +08:00
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')