import pygame
import random
# 屏幕大小
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 700
PLAY_WIDTH = 300 # 10 * 30
PLAY_HEIGHT = 600 # 20 * 30
BLOCK_SIZE = 30
# 坐标偏移量
TOP_LEFT_X = (SCREEN_WIDTH - PLAY_WIDTH) // 2
TOP_LEFT_Y = SCREEN_HEIGHT - PLAY_HEIGHT - 50
# 形状格式
SHAPES = [
[['.....',
'.....',
'..00.',
'.00..',
'.....'],
['.....',
'..0..',
'..00.',
'...0.',
'.....']],
[['.....',
'.....',
'.00..',
'..00.',
'.....'],
['.....',
'..0..',
'.00..',
'.0...',
'.....']],
[['.....',
'..0..',
'..0..',
'..0..',
'..0..'],
['.....',
'0000.',
'.....',
'.....',
'.....']],
[['.....',
'.....',
'.00..',
'.00..',
'.....']],
[['.....',
'..0..',
'.000.',
'.....',
'.....'],
['.....',
'..0..',
'..00.',
'..0..',
'.....'],
['.....',
'.....',
'.000.',
'..0..',
'.....'],
['.....',
'..0..',
'.00..',
'..0..',
'.....']],
[['.....',
'.....',
'.000.',
'...0.',
'.....'],
['.....',
'..00.',
'..0..',
'..0..',
'.....'],
['.....',
'.....',
'.000.',
'.0...',
'.....'],
['.....',
'..0..',
'..0..',
'.00..',
'.....']],
[['.....',
'.....',
'.000.',
'.0...',
'.....'],
['.....',
'..0..',
'..0..',
'..00.',
'.....'],
['.....',
'.....',
'.000.',
'...0.',
'.....'],
['.....',
'..00.',
'..0..',
'..0..',
'.....']]
]
# 颜色
SHAPE_COLORS = [(0, 255, 0), (255, 0, 0), (0, 0, 255), (255, 255, 0), (255, 165, 0), (0, 255, 255), (128, 0, 128)]
class Piece(object):
def __init__(self, x, y, shape):
self.x = x
self.y = y
self.shape = shape
self.color = SHAPE_COLORS[SHAPES.index(shape)]
self.rotation = 0
def create_grid(locked_positions={}):
grid = [[(0,0,0) for x in range(10)] for y in range(20)]
for y in range(len(grid)):
for x in range(len(grid[y])):
if (x,y) in locked_positions:
color = locked_positions[(x,y)]
grid[y][x] = color
return grid
def convert_shape_format(piece):
positions = []
format = piece.shape[piece.rotation % len(piece.shape)]
for i, line in enumerate(format):
row = list(line)
for j, column in enumerate(row):
if column == '0':
positions.append((piece.x + j, piece.y + i))
for i, pos in enumerate(positions):
positions[i] = (pos[0] - 2, pos[1] - 4)
return positions
def valid_space(piece, grid):
accepted_positions = [[(x, y) for x in range(10) if grid[y][x] == (0,0,0)] for y in range(20)]
accepted_positions = [x for item in accepted_positions for x in item]
formatted = convert_shape_format(piece)
for pos in formatted:
if pos not in accepted_positions:
if pos[1] > -1:
return False
return True
def check_lost(positions):
for pos in positions:
x, y = pos
if y < 1:
return True
return False
def get_shape():
return Piece(5, 0, random.choice(SHAPES))
def draw_text_middle(text, size, color, surface):
font = pygame.font.SysFont('comicsans', size, bold=True)
label = font.render(text, 1, color)
surface.blit(label, (TOP_LEFT_X + PLAY_WIDTH/2 - (label.get_width()/2),
TOP_LEFT_Y + PLAY_HEIGHT/2 - (label.get_height()/2)))
def draw_grid(surface, grid):
sx = TOP_LEFT_X
sy = TOP_LEFT_Y
for i in range(len(grid)):
pygame.draw.line(surface, (128,128,128), (sx, sy + i*BLOCK_SIZE), (sx + PLAY_WIDTH, sy + i * BLOCK_SIZE))
for j in range(len(grid[i])):
pygame.draw.line(surface, (128,128,128), (sx + j*BLOCK_SIZE, sy), (sx + j*BLOCK_SIZE, sy + PLAY_HEIGHT))
def clear_rows(grid, locked):
increment = 0
for i in range(len(grid)-1, -1, -1):
row = grid[i]
if (0, 0, 0) not in row:
increment += 1
ind = i
for j in range(len(row)):
try:
del locked[(j, i)]
except:
continue
if increment > 0:
for key in sorted(list(locked), key=lambda x: x[1])[::-1]:
x, y = key
if y < ind:
newKey = (x, y + increment)
locked[newKey] = locked.pop(key)
return increment
def draw_next_shape(piece, surface):
font = pygame.font.SysFont('comicsans', 30)
label = font.render('Next Shape', 1, (255, 255, 255))
sx = TOP_LEFT_X + PLAY_WIDTH + 50
sy = TOP_LEFT_Y + PLAY_HEIGHT / 2 - 100
format = piece.shape[piece.rotation % len(piece.shape)]
for i, line in enumerate(format):
row = list(line)
for j, column in enumerate(row):
if column == '0':
pygame.draw.rect(surface, piece.color, (sx + j*BLOCK_SIZE, sy + i*BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE), 0)
surface.blit(label, (sx + 10, sy - 30))
def draw_window(surface, grid, score=0):
surface.fill((0, 0, 0))
font = pygame.font.SysFont('comicsans', 60)
label = font.render('Tetris', 1, (255, 255, 255))
surface.blit(label, (TOP_LEFT_X + PLAY_WIDTH / 2 - (label.get_width() / 2), 30))
font = pygame.font.SysFont('comicsans', 30)
label = font.render('Score: ' + str(score), 1, (255, 255, 255))
sx = TOP_LEFT_X + PLAY_WIDTH + 50
sy = TOP_LEFT_Y + PLAY_HEIGHT / 2 - 100
surface.blit(label, (sx + 20, sy + 160))
for i in range(len(grid)):
for j in range(len(grid[i])):
pygame.draw.rect(surface, grid[i][j], (TOP_LEFT_X + j*BLOCK_SIZE, TOP_LEFT_Y + i*BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE), 0)
draw_grid(surface, grid)
pygame.draw.rect(surface, (255, 0, 0), (TOP_LEFT_X, TOP_LEFT_Y, PLAY_WIDTH, PLAY_HEIGHT), 5)
def main():
locked_positions = {}
grid = create_grid(locked_positions)
change_piece = False
run = True
current_piece = get_shape()
next_piece = get_shape()
clock = pygame.time.Clock()
fall_time = 0
score = 0
while run:
grid = create_grid(locked_positions)
fall_speed = 0.27
fall_time += clock.get_rawtime()
clock.tick()
if fall_time / 1000 >= fall_speed:
fall_time = 0
current_piece.y += 1
if not (valid_space(current_piece, grid)) and current_piece.y > 0:
current_piece.y -= 1
change_piece = True
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.display.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
current_piece.x -= 1
if not valid_space(current_piece, grid):