sports_esportsШаг 4 из 4
Полный код Тетриса
Физика падения, коллизии, удаление линий, счёт — всё вместе
keyboard Управление в игре
⬅️ ➡️
Стрелки
Движение влево/вправо
⬇️
Стрелка вниз
Ускорить падение
⬆️
Стрелка вверх
Повернуть фигуру
⎵
Пробел
Мгновенный сброс
1 Импорты и константы
Начнём файл с импортов и настроек размеров.
tetris.py — часть 1/6
editВведите вручную
import pygame import random # ── Константы ───────────────────── COLS, ROWS = 10, 20 BLOCK = 30 WIDTH = COLS * BLOCK # 300 px HEIGHT = ROWS * BLOCK # 600 px FPS = 60 COLORS = [ (0,188,212), (253,216,53), (156,39,176), (76,175,80), (244,67,54), (255,152,0), (33,150,243), ] SHAPES = [ [[1,1,1,1]], [[1,1],[1,1]], [[0,1,0],[1,1,1]], [[0,1,1],[1,1,0]], [[1,1,0],[0,1,1]], [[1,0,0],[1,1,1]], [[0,0,1],[1,1,1]], ]
2 Создание поля и новой фигуры
tetris.py — часть 2/6
editВведите вручную
def new_board(): # Создаём пустое поле (матрица нулей) return [[0] * COLS for _ in range(ROWS)] def new_piece(): # Выбираем случайную фигуру и цвет idx = random.randint(0, len(SHAPES) - 1) shape = SHAPES[idx] color = idx + 1 # 1-7 (0 = пусто) # Стартовая позиция: сверху по центру x = COLS // 2 - len(shape[0]) // 2 y = 0 return {'shape': shape, 'color': color, 'x': x, 'y': y} def rotate(shape): # Поворот фигуры на 90° по часовой стрелке return [list(row) for row in zip(*shape[::-1])]
3 Проверка коллизий
Коллизия — когда фигура упирается в стену, дно или другой блок. Здесь активно используются if/elif/else из ЛР №3.
tetris.py — часть 3/6
editВведите вручную
def can_move(board, piece, dx=0, dy=0, shape=None): """Проверяем — можно ли сдвинуть фигуру на (dx, dy)""" if shape is None: shape = piece['shape'] nx = piece['x'] + dx ny = piece['y'] + dy for r, row in enumerate(shape): for c, cell in enumerate(row): if cell == 0: continue # пустая ячейка фигуры new_c = nx + c new_r = ny + r if new_c < 0 or new_c >= COLS: return False # вышли за левую/правую стену if new_r >= ROWS: return False # вышли за нижнюю стену if board[new_r][new_c] != 0: return False # ячейка уже занята return True
4 Фиксация фигуры и удаление линий
Когда фигура не может упасть дальше — фиксируем её на поле. Затем ищем заполненные строки и удаляем их (ЛР №7 — операции со списками!).
tetris.py — часть 4/6
editВведите вручную
def lock_piece(board, piece): """Записываем фигуру на поле""" for r, row in enumerate(piece['shape']): for c, cell in enumerate(row): if cell: board[piece['y']+r][piece['x']+c] = piece['color'] def clear_lines(board): """Удаляем заполненные строки, возвращаем их количество""" # Фильтрация: оставляем только НЕзаполненные строки new_board = [row for row in board if 0 in row] cleared = ROWS - len(new_board) # Добавляем пустые строки сверху for _ in range(cleared): new_board.insert(0, [0] * COLS) board[:] = new_board # обновляем поле на месте return cleared
List comprehension из ЛР №7: строка [row for row in board if 0 in row] — это именно фильтрация списка, которую вы изучали!
5 Отрисовка и счёт
tetris.py — часть 5/6
editВведите вручную
def draw_board(screen, board): for r in range(ROWS): for c in range(COLS): color_idx = board[r][c] color = COLORS[color_idx-1] if color_idx > 0 else (25,25,25) pygame.draw.rect(screen, color, (c*BLOCK, r*BLOCK, BLOCK-1, BLOCK-1)) def draw_piece(screen, piece): color = COLORS[piece['color']-1] for r, row in enumerate(piece['shape']): for c, cell in enumerate(row): if cell: x = (piece['x'] + c) * BLOCK y = (piece['y'] + r) * BLOCK pygame.draw.rect(screen, color, (x, y, BLOCK-1, BLOCK-1)) def draw_score(screen, font, score): text = font.render(f"Счёт: {score}", True, (255,255,255)) screen.blit(text, (5, 5))
6 Главный игровой цикл
tetris.py — часть 6/6 (финал)
editВведите вручную
pygame.init() screen = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("Тетрис") clock = pygame.time.Clock() font = pygame.font.SysFont(None, 28) board = new_board() piece = new_piece() score = 0 fall_timer = 0 fall_speed = 500 # мс до автоматического падения running = True while running: dt = clock.tick(FPS) fall_timer += dt # ── Обработка событий ────────────────── for event in pygame.event.get(): if event.type == pygame.QUIT: running = False if event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: if can_move(board, piece, dx=-1): piece['x'] -= 1 elif event.key == pygame.K_RIGHT: if can_move(board, piece, dx=1): piece['x'] += 1 elif event.key == pygame.K_DOWN: if can_move(board, piece, dy=1): piece['y'] += 1 elif event.key == pygame.K_UP: rotated = rotate(piece['shape']) if can_move(board, piece, shape=rotated): piece['shape'] = rotated elif event.key == pygame.K_SPACE: # Мгновенный сброс вниз while can_move(board, piece, dy=1): piece['y'] += 1 # ── Автоматическое падение ───────────── if fall_timer >= fall_speed: fall_timer = 0 if can_move(board, piece, dy=1): piece['y'] += 1 else: lock_piece(board, piece) lines = clear_lines(board) score += lines * 100 piece = new_piece() # Если новая фигура не помещается — конец игры if not can_move(board, piece): running = False # ── Отрисовка ────────────────────────── screen.fill((0, 0, 0)) draw_board(screen, board) draw_piece(screen, piece) draw_score(screen, font, score) pygame.display.flip() # ── Экран Game Over ──────────────────── screen.fill((0, 0, 0)) text = font.render(f"Game Over! Счёт: {score}", True, (255,100,100)) screen.blit(text, (20, HEIGHT // 2)) pygame.display.flip() pygame.time.wait(3000) pygame.quit()
🎉
Поздравляем! Вы написали Тетрис на Python!
Теперь вы знаете как работает настоящая игра. Попробуйте улучшить её самостоятельно:
- 🎵 Звук — добавьте музыку через
pygame.mixer - 👻 Призрак — показывайте куда упадёт фигура
- 📈 Уровни — ускоряйте падение с каждым уровнем
- 💾 Рекорды — сохраняйте лучший счёт в файл