init
This commit is contained in:
256
tet/tetris.py
Normal file
256
tet/tetris.py
Normal file
@@ -0,0 +1,256 @@
|
||||
import pygame
|
||||
import random
|
||||
|
||||
# Инициализация pygame
|
||||
pygame.init()
|
||||
|
||||
# Цвета
|
||||
BLACK = (0, 0, 0)
|
||||
WHITE = (255, 255, 255)
|
||||
GRAY = (70, 70, 70)
|
||||
COLORS = [
|
||||
(0, 255, 255), # I - голубой
|
||||
(0, 0, 255), # J - синий
|
||||
(255, 165, 0), # L - оранжевый
|
||||
(255, 255, 0), # O - желтый
|
||||
(0, 255, 0), # S - зеленый
|
||||
(128, 0, 128), # T - фиолетовый
|
||||
(255, 0, 0) # Z - красный
|
||||
]
|
||||
|
||||
# Настройки игры
|
||||
BLOCK_SIZE = 30
|
||||
GRID_WIDTH = 10
|
||||
GRID_HEIGHT = 20
|
||||
SCREEN_WIDTH = BLOCK_SIZE * (GRID_WIDTH + 6)
|
||||
SCREEN_HEIGHT = BLOCK_SIZE * GRID_HEIGHT
|
||||
GAME_AREA_LEFT = BLOCK_SIZE
|
||||
|
||||
# Фигуры тетрамино
|
||||
SHAPES = [
|
||||
[[1, 1, 1, 1]], # I
|
||||
[[1, 0, 0], [1, 1, 1]], # J
|
||||
[[0, 0, 1], [1, 1, 1]], # L
|
||||
[[1, 1], [1, 1]], # O
|
||||
[[0, 1, 1], [1, 1, 0]], # S
|
||||
[[0, 1, 0], [1, 1, 1]], # T
|
||||
[[1, 1, 0], [0, 1, 1]] # Z
|
||||
]
|
||||
|
||||
# Создание экрана
|
||||
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
|
||||
pygame.display.set_caption("Тетрис")
|
||||
|
||||
# Часы для управления FPS
|
||||
clock = pygame.time.Clock()
|
||||
|
||||
class Tetris:
|
||||
def __init__(self):
|
||||
self.grid = [[0 for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)]
|
||||
self.current_piece = self.new_piece()
|
||||
self.game_over = False
|
||||
self.score = 0
|
||||
self.level = 1
|
||||
self.fall_speed = 0.5 # секунды между падением на 1 клетку
|
||||
self.fall_time = 0
|
||||
|
||||
def new_piece(self):
|
||||
# Выбираем случайную фигуру
|
||||
shape = random.choice(SHAPES)
|
||||
color = COLORS[SHAPES.index(shape)]
|
||||
|
||||
# Начальная позиция (по центру сверху)
|
||||
x = GRID_WIDTH // 2 - len(shape[0]) // 2
|
||||
y = 0
|
||||
|
||||
return {"shape": shape, "color": color, "x": x, "y": y}
|
||||
|
||||
def valid_move(self, piece, x_offset=0, y_offset=0):
|
||||
for y, row in enumerate(piece["shape"]):
|
||||
for x, cell in enumerate(row):
|
||||
if cell:
|
||||
new_x = piece["x"] + x + x_offset
|
||||
new_y = piece["y"] + y + y_offset
|
||||
|
||||
if (new_x < 0 or new_x >= GRID_WIDTH or
|
||||
new_y >= GRID_HEIGHT or
|
||||
(new_y >= 0 and self.grid[new_y][new_x])):
|
||||
return False
|
||||
return True
|
||||
|
||||
def rotate_piece(self):
|
||||
# Получаем текущую фигуру
|
||||
piece = self.current_piece
|
||||
# Транспонируем матрицу фигуры (поворот на 90 градусов)
|
||||
rotated = [[piece["shape"][y][x] for y in range(len(piece["shape"])-1, -1, -1)]
|
||||
for x in range(len(piece["shape"][0]))]
|
||||
|
||||
old_shape = piece["shape"]
|
||||
piece["shape"] = rotated
|
||||
|
||||
# Если после поворота фигура выходит за границы или пересекается с другими блоками,
|
||||
# отменяем поворот
|
||||
if not self.valid_move(piece):
|
||||
piece["shape"] = old_shape
|
||||
|
||||
def lock_piece(self):
|
||||
piece = self.current_piece
|
||||
for y, row in enumerate(piece["shape"]):
|
||||
for x, cell in enumerate(row):
|
||||
if cell:
|
||||
# Проверяем, не выходит ли фигура за верхнюю границу (игра окончена)
|
||||
if piece["y"] + y < 0:
|
||||
self.game_over = True
|
||||
else:
|
||||
self.grid[piece["y"] + y][piece["x"] + x] = piece["color"]
|
||||
|
||||
# Проверяем заполненные линии
|
||||
self.clear_lines()
|
||||
# Создаем новую фигуру
|
||||
self.current_piece = self.new_piece()
|
||||
|
||||
# Если новая фигура сразу не может разместиться, игра окончена
|
||||
if not self.valid_move(self.current_piece):
|
||||
self.game_over = True
|
||||
|
||||
def clear_lines(self):
|
||||
lines_cleared = 0
|
||||
for y in range(GRID_HEIGHT):
|
||||
if all(self.grid[y]):
|
||||
lines_cleared += 1
|
||||
# Удаляем линию и сдвигаем все вышележащие линии вниз
|
||||
for y2 in range(y, 0, -1):
|
||||
self.grid[y2] = self.grid[y2-1][:]
|
||||
self.grid[0] = [0 for _ in range(GRID_WIDTH)]
|
||||
|
||||
# Обновляем счет
|
||||
if lines_cleared == 1:
|
||||
self.score += 100 * self.level
|
||||
elif lines_cleared == 2:
|
||||
self.score += 300 * self.level
|
||||
elif lines_cleared == 3:
|
||||
self.score += 500 * self.level
|
||||
elif lines_cleared == 4:
|
||||
self.score += 800 * self.level
|
||||
|
||||
# Обновляем уровень (каждые 10 линий)
|
||||
self.level = 1 + self.score // 1000
|
||||
# Увеличиваем скорость (максимум 0.05 секунды между падениями)
|
||||
self.fall_speed = max(0.05, 0.5 - (self.level - 1) * 0.05)
|
||||
|
||||
def update(self, delta_time):
|
||||
if self.game_over:
|
||||
return
|
||||
|
||||
self.fall_time += delta_time
|
||||
|
||||
# Автоматическое падение фигуры
|
||||
if self.fall_time >= self.fall_speed:
|
||||
self.fall_time = 0
|
||||
if self.valid_move(self.current_piece, 0, 1):
|
||||
self.current_piece["y"] += 1
|
||||
else:
|
||||
self.lock_piece()
|
||||
|
||||
def draw(self):
|
||||
# Очищаем экран
|
||||
screen.fill(BLACK)
|
||||
|
||||
# Рисуем игровую область
|
||||
pygame.draw.rect(screen, WHITE, (GAME_AREA_LEFT, 0, BLOCK_SIZE * GRID_WIDTH, SCREEN_HEIGHT), 1)
|
||||
|
||||
# Рисуем сетку
|
||||
for x in range(GRID_WIDTH):
|
||||
for y in range(GRID_HEIGHT):
|
||||
pygame.draw.rect(screen, GRAY,
|
||||
(GAME_AREA_LEFT + x * BLOCK_SIZE, y * BLOCK_SIZE,
|
||||
BLOCK_SIZE, BLOCK_SIZE), 1)
|
||||
|
||||
# Рисуем статичные блоки
|
||||
for y in range(GRID_HEIGHT):
|
||||
for x in range(GRID_WIDTH):
|
||||
if self.grid[y][x]:
|
||||
pygame.draw.rect(screen, self.grid[y][x],
|
||||
(GAME_AREA_LEFT + x * BLOCK_SIZE, y * BLOCK_SIZE,
|
||||
BLOCK_SIZE, BLOCK_SIZE))
|
||||
pygame.draw.rect(screen, WHITE,
|
||||
(GAME_AREA_LEFT + x * BLOCK_SIZE, y * BLOCK_SIZE,
|
||||
BLOCK_SIZE, BLOCK_SIZE), 1)
|
||||
|
||||
# Рисуем текущую фигуру
|
||||
if not self.game_over:
|
||||
piece = self.current_piece
|
||||
for y, row in enumerate(piece["shape"]):
|
||||
for x, cell in enumerate(row):
|
||||
if cell:
|
||||
pygame.draw.rect(screen, piece["color"],
|
||||
(GAME_AREA_LEFT + (piece["x"] + x) * BLOCK_SIZE,
|
||||
(piece["y"] + y) * BLOCK_SIZE,
|
||||
BLOCK_SIZE, BLOCK_SIZE))
|
||||
pygame.draw.rect(screen, WHITE,
|
||||
(GAME_AREA_LEFT + (piece["x"] + x) * BLOCK_SIZE,
|
||||
(piece["y"] + y) * BLOCK_SIZE,
|
||||
BLOCK_SIZE, BLOCK_SIZE), 1)
|
||||
|
||||
# Рисуем информацию (счет, уровень)
|
||||
font = pygame.font.SysFont(None, 36)
|
||||
score_text = font.render(f"Счет: {self.score}", True, WHITE)
|
||||
level_text = font.render(f"Уровень: {self.level}", True, WHITE)
|
||||
screen.blit(score_text, (GAME_AREA_LEFT + GRID_WIDTH * BLOCK_SIZE + 10, 30))
|
||||
screen.blit(level_text, (GAME_AREA_LEFT + GRID_WIDTH * BLOCK_SIZE + 10, 70))
|
||||
|
||||
# Если игра окончена, выводим сообщение
|
||||
if self.game_over:
|
||||
game_over_font = pygame.font.SysFont(None, 48)
|
||||
game_over_text = game_over_font.render("Игра Окончена!", True, (255, 0, 0))
|
||||
screen.blit(game_over_text, (GAME_AREA_LEFT + GRID_WIDTH * BLOCK_SIZE // 2 - 100,
|
||||
SCREEN_HEIGHT // 2 - 24))
|
||||
|
||||
# Создаем экземпляр игры
|
||||
game = Tetris()
|
||||
|
||||
# Основной игровой цикл
|
||||
running = True
|
||||
last_time = pygame.time.get_ticks()
|
||||
|
||||
while running:
|
||||
# Управление FPS
|
||||
current_time = pygame.time.get_ticks()
|
||||
delta_time = (current_time - last_time) / 1000.0 # Конвертируем в секунды
|
||||
last_time = current_time
|
||||
|
||||
# Обработка событий
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
running = False
|
||||
|
||||
if not game.game_over:
|
||||
if event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_LEFT:
|
||||
if game.valid_move(game.current_piece, -1, 0):
|
||||
game.current_piece["x"] -= 1
|
||||
elif event.key == pygame.K_RIGHT:
|
||||
if game.valid_move(game.current_piece, 1, 0):
|
||||
game.current_piece["x"] += 1
|
||||
elif event.key == pygame.K_DOWN:
|
||||
if game.valid_move(game.current_piece, 0, 1):
|
||||
game.current_piece["y"] += 1
|
||||
elif event.key == pygame.K_UP:
|
||||
game.rotate_piece()
|
||||
elif event.key == pygame.K_SPACE:
|
||||
# Мгновенное падение
|
||||
while game.valid_move(game.current_piece, 0, 1):
|
||||
game.current_piece["y"] += 1
|
||||
game.lock_piece()
|
||||
|
||||
# Обновление игры
|
||||
game.update(delta_time)
|
||||
|
||||
# Отрисовка
|
||||
game.draw()
|
||||
pygame.display.flip()
|
||||
|
||||
# Ограничиваем FPS
|
||||
clock.tick(60)
|
||||
|
||||
pygame.quit()
|
||||
Reference in New Issue
Block a user