import pygame
import sys
import math
import numpy as np
# Инициализация Pygame
pygame.init()
# Параметры экрана
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Мяч в шестиугольнике")
# Цвета
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
# Параметры физики
FPS = 60
GRAVITY = 0.5
FRICTION = 0.99
RESTITUTION = 0.8 # Коэффициент восстановления при ударе
# Параметры шестиугольника
HEX_RADIUS = 200
hex_center = [WIDTH // 2, HEIGHT // 2]
hex_angle = 0
hex_rotation_speed = 0.01
# Параметры мяча
ball_radius = 15
ball_pos = [WIDTH // 2, HEIGHT // 2 - 100]
ball_vel = [0, 0]
# Функция для получения вершин шестиугольника
def get_hex_vertices():
vertices = []
for i in range(6):
angle = hex_angle + i * math.pi / 3
x = hex_center[0] + HEX_RADIUS * math.cos(angle)
y = hex_center[1] + HEX_RADIUS * math.sin(angle)
vertices.append((x, y))
return vertices
# Функция для определения расстояния от точки до отрезка
def point_to_line_distance(point, line_start, line_end):
# Вектор линии
line_vec = (line_end[0] - line_start[0], line_end[1] - line_start[1])
# Вектор от начала линии до точки
point_vec = (point[0] - line_start[0], point[1] - line_start[1])
# Длина линии в квадрате
line_len_sq = line_vec[0]**2 + line_vec[1]**2
# Проекция point_vec на line_vec
t = max(0, min(1, (point_vec[0]*line_vec[0] + point_vec[1]*line_vec[1]) / line_len_sq))
# Ближайшая точка на линии
projection = (
line_start[0] + t * line_vec[0],
line_start[1] + t * line_vec[1]
)
# Расстояние от точки до проекции
return (
math.sqrt((point[0] - projection[0])**2 + (point[1] - projection[1])**2),
projection,
t
)
# Основной игровой цикл
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# Очистка экрана
screen.fill(BLACK)
# Обновление угла шестиугольника
hex_angle += hex_rotation_speed
# Получение вершин шестиугольника
vertices = get_hex_vertices()
# Рисование шестиугольника
pygame.draw.polygon(screen, WHITE, vertices, 2)
# Применение гравитации к мячу
ball_vel[1] += GRAVITY
# Обновление позиции мяча
ball_pos[0] += ball_vel[0]
ball_pos[1] += ball_vel[1]
# Проверка столкновений со стенками шестиугольника
for i in range(6):
v1 = vertices[i]
v2 = vertices[(i + 1) % 6]
# Расстояние от мяча до стороны шестиугольника
distance, projection, t = point_to_line_distance(ball_pos, v1, v2)
# Если мяч касается или пересекает стенку
if distance <= ball_radius and 0 <= t <= 1:
# Нормаль к стенке (перпендикуляр)
normal = (
-(v2[1] - v1[1]),
v2[0] - v1[0]
)
# Нормализация вектора нормали
normal_length = math.sqrt(normal[0]**2 + normal[1]**2)
normal = (normal[0] / normal_length, normal[1] / normal_length)
# Направление от стенки к мячу
if (ball_pos[0] - projection[0]) * normal[0] + (ball_pos[1] - projection[1]) * normal[1] < 0:
normal = (-normal[0], -normal[1])
# Коррекция позиции мяча
overlap = ball_radius - distance
ball_pos[0] += normal[0] * overlap
ball_pos[1] += normal[1] * overlap
# Скорость стенки в точке удара из-за вращения
wall_vel = [
-hex_rotation_speed * (projection[1] - hex_center[1]),
hex_rotation_speed * (projection[0] - hex_center[0])
]
# Относительная скорость мяча к стенке
rel_vel = [
ball_vel[0] - wall_vel[0],
ball_vel[1] - wall_vel[1]
]
# Проекция относительной скорости на нормаль
normal_vel = rel_vel[0] * normal[0] + rel_vel[1] * normal[1]
# Отражение только если мяч движется в сторону стенки
if normal_vel < 0:
# Изменение скорости мяча при отражении
ball_vel[0] -= (1 + RESTITUTION) * normal_vel * normal[0]
ball_vel[1] -= (1 + RESTITUTION) * normal_vel * normal[1]
# Добавление скорости стенки
ball_vel[0] += wall_vel[0]
ball_vel[1] += wall_vel[1]
# Применение трения
tangent = (-normal[1], normal[0])
tangent_vel = rel_vel[0] * tangent[0] + rel_vel[1] * tangent[1]
ball_vel[0] -= tangent_vel * tangent[0] * (1 - FRICTION)
ball_vel[1] -= tangent_vel * tangent[1] * (1 - FRICTION)
# Применение общего трения
ball_vel[0] *= FRICTION
ball_vel[1] *= FRICTION
# Рисование мяча
pygame.draw.circle(screen, RED, (int(ball_pos[0]), int(ball_pos[1])), ball_radius)
# Обновление экрана
pygame.display.flip()
clock.tick(FPS)