🐍
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
  • 👻 Призрак — показывайте куда упадёт фигура
  • 📈 Уровни — ускоряйте падение с каждым уровнем
  • 💾 Рекорды — сохраняйте лучший счёт в файл
home На главную