192 lines
8.5 KiB
Python
192 lines
8.5 KiB
Python
import pygame
|
||
import sys
|
||
|
||
# Инициализация pygame
|
||
pygame.init()
|
||
|
||
# Константы
|
||
WIDTH, HEIGHT = 800, 600
|
||
PADDLE_WIDTH, PADDLE_HEIGHT = 10, 100
|
||
BALL_SIZE = 15
|
||
WHITE = (255, 255, 255)
|
||
FPS = 60
|
||
WINNING_SCORE = 10 # Основной счёт для победы
|
||
TIE_BREAK_REQUIRED_DIFFERENCE = 2 # Разница для победы в тай-брейке
|
||
AI_SPEED = 0.7 # Уровень "умения" ИИ (0.5 - очень медленный, 1.0 - идеальный)
|
||
|
||
# Создание экрана
|
||
screen = pygame.display.set_mode((WIDTH, HEIGHT))
|
||
pygame.display.set_caption("Pong с ИИ")
|
||
clock = pygame.time.Clock()
|
||
|
||
# Функция для сброса игры
|
||
def reset_game():
|
||
return {
|
||
"player_paddle": pygame.Rect(20, HEIGHT//2 - PADDLE_HEIGHT//2, PADDLE_WIDTH, PADDLE_HEIGHT),
|
||
"ai_paddle": pygame.Rect(WIDTH - 30, HEIGHT//2 - PADDLE_HEIGHT//2, PADDLE_WIDTH, PADDLE_HEIGHT),
|
||
"ball": pygame.Rect(WIDTH//2 - BALL_SIZE//2, HEIGHT//2 - BALL_SIZE//2, BALL_SIZE, BALL_SIZE),
|
||
"ball_speed_x": 5,
|
||
"ball_speed_y": 5,
|
||
"player_score": 0,
|
||
"ai_score": 0,
|
||
"game_over": False,
|
||
"tie_break_active": False,
|
||
"win_message": None,
|
||
"show_win_screen": False,
|
||
"restart_timer": 0
|
||
}
|
||
|
||
# Состояние игры
|
||
game_state = reset_game()
|
||
|
||
# Шрифты
|
||
score_font = pygame.font.Font(None, 74)
|
||
win_font = pygame.font.Font(None, 100)
|
||
|
||
def move_ai_paddle(paddle, ball):
|
||
"""Логика ИИ: ракетка следует за мячом с задержкой"""
|
||
if ball.centerx > WIDTH/2: # Реагируем только на мяч, приближающийся к ИИ
|
||
if paddle.centery < ball.centery:
|
||
paddle.y += min(7 * AI_SPEED, ball.centery - paddle.centery)
|
||
elif paddle.centery > ball.centery:
|
||
paddle.y -= min(7 * AI_SPEED, paddle.centery - ball.centery)
|
||
|
||
# Ограничение границ экрана
|
||
paddle.y = max(0, min(HEIGHT - PADDLE_HEIGHT, paddle.y))
|
||
|
||
def calculate_ball_angle(contact_point, paddle_center):
|
||
"""Рассчитывает угол отскока мяча в зависимости от точки контакта"""
|
||
contact_diff = contact_point - paddle_center
|
||
angle_factor = contact_diff / (PADDLE_HEIGHT/2) # От -1 до +1
|
||
|
||
# Более резкий угол для ударов по краям ракетки
|
||
return angle_factor * 0.5 # 0.5 - коэффициент максимального изменения угла
|
||
|
||
# Основной цикл игры
|
||
while True:
|
||
for event in pygame.event.get():
|
||
if event.type == pygame.QUIT:
|
||
pygame.quit()
|
||
sys.exit()
|
||
|
||
if not game_state["show_win_screen"]:
|
||
# Обработка управления
|
||
keys = pygame.key.get_pressed()
|
||
if keys[pygame.K_w] and game_state["player_paddle"].top > 0:
|
||
game_state["player_paddle"].y -= 7
|
||
if keys[pygame.K_s] and game_state["player_paddle"].bottom < HEIGHT:
|
||
game_state["player_paddle"].y += 7
|
||
|
||
# Движение мяча
|
||
game_state["ball"].x += game_state["ball_speed_x"]
|
||
game_state["ball"].y += game_state["ball_speed_y"]
|
||
|
||
# Отскок от стен
|
||
if game_state["ball"].top <= 0 or game_state["ball"].bottom >= HEIGHT:
|
||
game_state["ball_speed_y"] *= -1
|
||
|
||
# Проверка на гол
|
||
if game_state["ball"].left <= 0:
|
||
game_state["ai_score"] += 1
|
||
|
||
# Проверка условий победы после гола
|
||
if game_state["ai_score"] == WINNING_SCORE:
|
||
if game_state["player_score"] == WINNING_SCORE - 1:
|
||
game_state["tie_break_active"] = True
|
||
elif game_state["player_score"] <= WINNING_SCORE - 2:
|
||
game_state["win_message"] = "КОМПЬЮТЕР ПОБЕДИЛ!"
|
||
game_state["show_win_screen"] = True
|
||
game_state["game_over"] = True
|
||
game_state["restart_timer"] = pygame.time.get_ticks() + 1000
|
||
|
||
# Проверка условий победы в тай-брейке
|
||
if game_state["tie_break_active"] and abs(game_state["ai_score"] - game_state["player_score"]) >= TIE_BREAK_REQUIRED_DIFFERENCE:
|
||
game_state["win_message"] = "КОМПЬЮТЕР ПОБЕДИЛ!"
|
||
game_state["show_win_screen"] = True
|
||
game_state["game_over"] = True
|
||
game_state["restart_timer"] = pygame.time.get_ticks() + 1000
|
||
|
||
game_state["ball"].center = (WIDTH//2, HEIGHT//2)
|
||
game_state["ball_speed_x"] = 5
|
||
game_state["ball_speed_y"] = 5 * random.choice([-1, 1])
|
||
pygame.time.delay(500)
|
||
|
||
elif game_state["ball"].right >= WIDTH:
|
||
game_state["player_score"] += 1
|
||
|
||
# Проверка условий победы после гола
|
||
if game_state["player_score"] == WINNING_SCORE:
|
||
if game_state["ai_score"] == WINNING_SCORE - 1:
|
||
game_state["tie_break_active"] = True
|
||
elif game_state["ai_score"] <= WINNING_SCORE - 2:
|
||
game_state["win_message"] = "ТЫ ПОБЕДИЛ!"
|
||
game_state["show_win_screen"] = True
|
||
game_state["game_over"] = True
|
||
game_state["restart_timer"] = pygame.time.get_ticks() + 1000
|
||
|
||
# Проверка условий победы в тай-брейке
|
||
if game_state["tie_break_active"] and abs(game_state["player_score"] - game_state["ai_score"]) >= TIE_BREAK_REQUIRED_DIFFERENCE:
|
||
game_state["win_message"] = "ТЫ ПОБЕДИЛ!"
|
||
game_state["show_win_screen"] = True
|
||
game_state["game_over"] = True
|
||
game_state["restart_timer"] = pygame.time.get_ticks() + 1000
|
||
|
||
game_state["ball"].center = (WIDTH//2, HEIGHT//2)
|
||
game_state["ball_speed_x"] = -5
|
||
game_state["ball_speed_y"] = 5 * random.choice([-1, 1])
|
||
pygame.time.delay(500)
|
||
|
||
# Отскок от ракеток с учётом угла
|
||
if game_state["ball"].colliderect(game_state["player_paddle"]):
|
||
contact_point = game_state["ball"].centery
|
||
paddle_center = game_state["player_paddle"].centery
|
||
|
||
angle_change = calculate_ball_angle(contact_point, paddle_center)
|
||
game_state["ball_speed_y"] += angle_change
|
||
game_state["ball_speed_x"] *= -1.1
|
||
|
||
elif game_state["ball"].colliderect(game_state["ai_paddle"]):
|
||
contact_point = game_state["ball"].centery
|
||
paddle_center = game_state["ai_paddle"].centery
|
||
|
||
angle_change = calculate_ball_angle(contact_point, paddle_center)
|
||
game_state["ball_speed_y"] += angle_change
|
||
game_state["ball_speed_x"] *= -1.1
|
||
|
||
# Обновление позиции ИИ
|
||
if not game_state["game_over"]:
|
||
move_ai_paddle(game_state["ai_paddle"], game_state["ball"])
|
||
|
||
# Обработка события нажатия клавиши для перезапуска
|
||
if game_state["show_win_screen"]:
|
||
keys = pygame.key.get_pressed()
|
||
if any(keys): # Любая клавиша
|
||
game_state = reset_game()
|
||
|
||
# Отрисовка
|
||
screen.fill((0, 0, 0))
|
||
|
||
if not game_state["show_win_screen"]:
|
||
# Отображение счета
|
||
score_text = score_font.render(f"{game_state['player_score']} {game_state['ai_score']}", True, WHITE)
|
||
screen.blit(score_text, (WIDTH//2 - 50, 10))
|
||
|
||
# Текст тай-брейка
|
||
if game_state["tie_break_active"]:
|
||
tie_text = score_font.render("TIE BREAK!", True, WHITE)
|
||
screen.blit(tie_text, (WIDTH//2 - 100, HEIGHT//2))
|
||
|
||
# Основные элементы игры
|
||
pygame.draw.rect(screen, WHITE, game_state["player_paddle"])
|
||
pygame.draw.rect(screen, WHITE, game_state["ai_paddle"])
|
||
pygame.draw.ellipse(screen, WHITE, game_state["ball"])
|
||
pygame.draw.aaline(screen, WHITE, (WIDTH//2, 0), (WIDTH//2, HEIGHT))
|
||
else:
|
||
# Экран победы
|
||
win_text = win_font.render(game_state["win_message"], True, WHITE)
|
||
text_rect = win_text.get_rect(center=(WIDTH//2, HEIGHT//2))
|
||
screen.blit(win_text, text_rect)
|
||
|
||
pygame.display.flip()
|
||
clock.tick(FPS)
|