Загрузка данных
import pygame as pg
import random
import sys
import time
import pygame_menu
from pygame_menu import themes
try:
pg.mixer.init()
sound_start = pg.mixer.Sound("start.wav")
sound_gameover = pg.mixer.Sound("gameover.wav")
sound_move = pg.mixer.Sound("move.wav")
sound_rotate = pg.mixer.Sound("rotate.wav")
sound_drop = pg.mixer.Sound("drop.wav")
except:
sound_start = sound_gameover = sound_move = sound_rotate = sound_drop = None
fps = 25
window_w, window_h = 600, 500
block, cup_h, cup_w = 20, 20, 10
side_margin = int((window_w - cup_w * block) / 2)
top_margin = window_h - (cup_h * block) - 5
fig_w, fig_h = 5, 5
empty = 'o'
colors = (
(0, 0, 0),
(255, 0, 0),
(0, 150, 0),
(0, 0, 255),
(255, 120, 0),
(255, 255, 0),
(180, 0, 255),
(0, 220, 220)
)
lightcolors = (
(0, 0, 0),
(255, 120, 120),
(120, 255, 120),
(120, 120, 255),
(255, 200, 120),
(255, 255, 120),
(220, 120, 255),
(120, 220, 220)
)
bg_color = (30, 30, 40)
figures = {
'O': [['oooo', 'oooo', 'oxxo', 'oxxo', 'oooo']],
'I': [['oooo', 'oxxxo', 'oxxxo', 'oxxxo', 'oooo'], ['oooo', 'oooox', 'oooox', 'oooox', 'oooo']],
'S': [['oooo', 'oxxo', 'oxxo', 'oxxo', 'oooo']],
'Z': [['oooo', 'oxxo', 'oxxo', 'oxxo', 'oooo']],
'L': [['oooo', 'oxxx', 'oxxx', 'oxxx', 'oooo']],
'J': [['oooo', 'oxxx', 'oxxx', 'oxxx', 'oooo']],
'T': [['oooo', 'oxxx', 'oxxx', 'oxxx', 'oooo']]
}
figures = {
'O': [[list('oooo'), list('oooo'), list('oxxo'), list('oxxo'), list('oooo')]],
'I': [
[list('oooo'), list('oxxx'), list('oxxx'), list('oxxx'), list('oooo')],
[list('oooo'), list('oooox'), list('oooox'), list('oooox'), list('oooo')]
],
'S': [
[list('oooo'), list('oxxo'), list('oxxo'), list('oxxo'), list('oooo')]
],
'Z': [
[list('oooo'), list('oxxo'), list('oxxo'), list('oxxo'), list('oooo')]
],
'L': [
[list('oooo'), list('oxxx'), list('oxxx'), list('oxxx'), list('oooo')]
],
'J': [
[list('oooo'), list('oxxx'), list('oxxx'), list('oxxx'), list('oooo')]
],
'T': [
[list('oooo'), list('oxxx'), list('oxxx'), list('oxxx'), list('oooo')]
]
}
for shape in ('S', 'Z', 'L', 'J', 'T'):
base = figures[shape][0]
rot = []
for _ in range(4):
rot.append(base)
figures[shape] = rot
def getNewFig():
shape = random.choice(list(figures.keys()))
rotation = 0
color = list(figures.keys()).index(shape) + 1
fig = {'shape': shape, 'rotation': rotation, 'color': color, 'x': cup_w // 2 - 2, 'y': -2}
return fig
def emptycup():
return [[empty] * cup_h for _ in range(cup_w)]
def incup(x, y):
return 0 <= x < cup_w and 0 <= y < cup_h
def checkPos(cup, fig, adjX=0, adjY=0):
shape_data = figures[fig['shape']][fig['rotation']]
for x in range(fig_w):
for y in range(fig_h):
if shape_data[y][x] == 'x':
cx = x + fig['x'] + adjX
cy = y + fig['y'] + adjY
if not incup(cx, cy):
return False
if cup[cx][cy] != empty:
return False
return True
def addToCup(cup, fig):
shape_data = figures[fig['shape']][fig['rotation']]
for x in range(fig_w):
for y in range(fig_h):
if shape_data[y][x] == 'x':
cup[x + fig['x']][y + fig['y']] = fig['color']
def isCompleted(cup, y):
for x in range(cup_w):
if cup[x][y] == empty:
return False
return True
def clearCompleted(cup):
removed = 0
y = cup_h - 1
while y >= 0:
if isCompleted(cup, y):
for pushY in range(y, 0, -1):
for x in range(cup_w):
cup[x][pushY] = cup[x][pushY-1]
for x in range(cup_w):
cup[x][0] = empty
removed += 1
else:
y -= 1
return removed
def calcSpeed(points):
level = points // 10 + 1
fall_speed = max(0.05, 0.5 - (level-1)*0.03)
return level, fall_speed
def convertCoords(x, y):
return side_margin + x * block, top_margin + y * block
def drawBlock(x, y, color, pixelx=None, pixely=None):
if color == empty:
return
if pixelx is None:
pixelx, pixely = convertCoords(x, y)
pg.draw.rect(display_surf, colors[color], (pixelx+1, pixely+1, block-1, block-1), 0, 3)
pg.draw.rect(display_surf, lightcolors[color], (pixelx+1, pixely+1, block-4, block-4), 0, 3)
pg.draw.circle(display_surf, colors[color], (pixelx+block//2, pixely+block//2), 5)
def drawFig(fig):
shape_data = figures[fig['shape']][fig['rotation']]
for x in range(fig_w):
for y in range(fig_h):
if shape_data[y][x] == 'x':
drawBlock(x + fig['x'], y + fig['y'], fig['color'])
def gamecup(cup):
for x in range(cup_w):
for y in range(cup_h):
if cup[x][y] != empty:
drawBlock(x, y, cup[x][y])
def drawnextFig(fig):
title = basic_font.render("Следующая:", True, (255,255,200))
display_surf.blit(title, (window_w - 150, 50))
shape_data = figures[fig['shape']][fig['rotation']]
start_x = window_w - 130
start_y = 100
for x in range(fig_w):
for y in range(fig_h):
if shape_data[y][x] == 'x':
px = start_x + x * (block-2)
py = start_y + y * (block-2)
drawBlock(0,0,fig['color'], pixelx=px, pixely=py)
def drawInfo(points, level):
txt = basic_font.render(f"Очки: {points}", True, (255,255,200))
display_surf.blit(txt, (window_w - 150, 250))
txt = basic_font.render(f"Уровень: {level}", True, (255,255,200))
display_surf.blit(txt, (window_w - 150, 280))
def drawTitle():
title = big_font.render("ТЕТРИС", True, (220,220,255))
display_surf.blit(title, (side_margin + cup_w*block//2 - title.get_width()//2, 10))
def showText(text):
surf = big_font.render(text, True, (255,100,100))
rect = surf.get_rect(center=(window_w//2, window_h//2))
display_surf.blit(surf, rect)
pg.display.update()
time.sleep(2)
def pauseScreen():
pause = pg.Surface((window_w, window_h), pg.SRCALPHA)
pause.fill((0,0,255,127))
display_surf.blit(pause, (0,0))
pg.display.update()
waiting = True
while waiting:
for e in pg.event.get():
if e.type == pg.KEYDOWN:
if e.key == pg.K_SPACE:
waiting = False
if e.type == pg.QUIT:
sys.exit()
def stopGame():
pg.quit()
sys.exit()
def runTetris(player_name):
cup = emptycup()
last_move_down = time.time()
last_side_move = time.time()
last_fall = time.time()
going_down = False
going_left = False
going_right = False
points = 0
level, fall_speed = calcSpeed(points)
fallingFig = getNewFig()
nextFig = getNewFig()
side_freq = 0.15
down_freq = 0.1
if sound_start:
sound_start.play()
while True:
if fallingFig is None:
fallingFig = nextFig
nextFig = getNewFig()
last_fall = time.time()
if not checkPos(cup, fallingFig):
if sound_gameover:
sound_gameover.play()
return points
for event in pg.event.get():
if event.type == pg.QUIT:
stopGame()
if event.type == pg.KEYDOWN:
if event.key == pg.K_SPACE:
pauseScreen()
elif event.key == pg.K_LEFT:
if checkPos(cup, fallingFig, adjX=-1):
fallingFig['x'] -= 1
if sound_move: sound_move.play()
going_left = True
going_right = False
last_side_move = time.time()
elif event.key == pg.K_RIGHT:
if checkPos(cup, fallingFig, adjX=1):
fallingFig['x'] += 1
if sound_move: sound_move.play()
going_right = True
going_left = False
last_side_move = time.time()
elif event.key == pg.K_UP:
old_rot = fallingFig['rotation']
fallingFig['rotation'] = (fallingFig['rotation'] + 1) % len(figures[fallingFig['shape']])
if not checkPos(cup, fallingFig):
fallingFig['rotation'] = old_rot
else:
if sound_rotate: sound_rotate.play()
elif event.key == pg.K_DOWN:
if checkPos(cup, fallingFig, adjY=1):
fallingFig['y'] += 1
last_move_down = time.time()
if sound_move: sound_move.play()
going_down = True
elif event.key == pg.K_RETURN:
for i in range(1, cup_h):
if not checkPos(cup, fallingFig, adjY=i):
break
fallingFig['y'] += i - 1
if sound_drop: sound_drop.play()
going_down = False
going_left = False
going_right = False
if event.type == pg.KEYUP:
if event.key == pg.K_LEFT:
going_left = False
elif event.key == pg.K_RIGHT:
going_right = False
elif event.key == pg.K_DOWN:
going_down = False
if (going_left or going_right) and time.time() - last_side_move > side_freq:
if going_left and checkPos(cup, fallingFig, adjX=-1):
fallingFig['x'] -= 1
if sound_move: sound_move.play()
elif going_right and checkPos(cup, fallingFig, adjX=1):
fallingFig['x'] += 1
if sound_move: sound_move.play()
last_side_move = time.time()
if going_down and time.time() - last_move_down > down_freq:
if checkPos(cup, fallingFig, adjY=1):
fallingFig['y'] += 1
if sound_move: sound_move.play()
last_move_down = time.time()
if time.time() - last_fall > fall_speed:
if not checkPos(cup, fallingFig, adjY=1):
addToCup(cup, fallingFig)
cleared = clearCompleted(cup)
points += cleared
level, fall_speed = calcSpeed(points)
fallingFig = None
else:
fallingFig['y'] += 1
last_fall = time.time()
display_surf.fill(bg_color)
drawTitle()
gamecup(cup)
drawInfo(points, level)
drawnextFig(nextFig)
if fallingFig is not None:
drawFig(fallingFig)
pg.display.update()
fps_clock.tick(fps)
def game_loop(player_name, difficulty):
global fps_clock, display_surf, basic_font, big_font
pg.init()
fps_clock = pg.time.Clock()
display_surf = pg.display.set_mode((window_w, window_h))
basic_font = pg.font.Font(None, 18)
big_font = pg.font.Font(None, 45)
pg.display.set_caption("Тетрис")
score = runTetris(player_name)
show_gameover(player_name, score)
def show_gameover(player_name, score):
display_surf.fill(bg_color)
msg1 = big_font.render("ИГРА ЗАКОНЧЕНА", True, (255,100,100))
msg2 = basic_font.render(f"{player_name}, ваш счёт: {score}", True, (255,255,200))
msg3 = basic_font.render("Нажмите любую клавишу для возврата в меню", True, (200,200,200))
display_surf.blit(msg1, (window_w//2 - msg1.get_width()//2, window_h//2 - 60))
display_surf.blit(msg2, (window_w//2 - msg2.get_width()//2, window_h//2))
display_surf.blit(msg3, (window_w//2 - msg3.get_width()//2, window_h//2 + 50))
pg.display.update()
waiting = True
while waiting:
for e in pg.event.get():
if e.type == pg.QUIT:
sys.exit()
if e.type == pg.KEYDOWN:
waiting = False
def start_game():
player_name = name_input.get_value()
diff = difficulty.get_value()[0]
speeds = {"Нормальная": 25, "Быстрая": 40, "Медленная": 15}
global fps
fps = speeds[diff]
game_loop(player_name, diff)
def main_menu():
global name_input, difficulty
menu = pygame_menu.Menu("ТЕТРИС", window_w, window_h, theme=themes.THEME_DARK)
name_input = menu.add.text_input("Имя игрока:", default="Игрок", maxchar=20)
difficulty = menu.add.selector("Сложность:", [("Нормальная", 0), ("Быстрая", 1), ("Медленная", 2)])
menu.add.button("СТАРТ", start_game)
menu.add.button("ВЫХОД", pygame_menu.events.EXIT)
menu.mainloop(display_surf)
if __name__ == "__main__":
pg.init()
display_surf = pg.display.set_mode((window_w, window_h))
pg.display.set_caption("Тетрис")
main_menu()
pg.quit()