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):