Загрузка данных


import pygame, math

pygame.init()
W, H = 900, 700
screen = pygame.display.set_mode((W, H))
pygame.display.set_caption("Racing Game")
clock = pygame.time.Clock()
font = pygame.font.SysFont("arial", 28)
big_font = pygame.font.SysFont("arial", 60)

# ---------- ТРАССА ----------
# Центральная линия трассы (точки), по ним строим полосу
center_points = [
    (150, 150), (450, 100), (700, 150), (800, 300),
    (750, 500), (600, 600), (400, 620), (200, 580),
    (100, 400), (120, 250)
]

TRACK_WIDTH = 110

def catmull_rom(points, n=8):
    """Сглаживание центральной линии для плавных поворотов"""
    result = []
    pts = points + points[:3]
    for i in range(len(points)):
        p0, p1, p2, p3 = pts[i], pts[i+1], pts[i+2], pts[i+3]
        for t in [j / n for j in range(n)]:
            t2, t3 = t*t, t*t*t
            x = 0.5 * ((2*p1[0]) + (-p0[0]+p2[0])*t +
                       (2*p0[0]-5*p1[0]+4*p2[0]-p3[0])*t2 +
                       (-p0[0]+3*p1[0]-3*p2[0]+p3[0])*t3)
            y = 0.5 * ((2*p1[1]) + (-p0[1]+p2[1])*t +
                       (2*p0[1]-5*p1[1]+4*p2[1]-p3[1])*t2 +
                       (-p0[1]+3*p1[1]-3*p2[1]+p3[1])*t3)
            result.append((x, y))
    return result

smooth_line = catmull_rom(center_points, n=12)

def build_track_polygons(line, width):
    inner, outer = [], []
    n = len(line)
    for i in range(n):
        x, y = line[i]
        x2, y2 = line[(i+1) % n]
        dx, dy = x2 - x, y2 - y
        length = math.hypot(dx, dy) or 1
        nx, ny = -dy/length, dx/length
        inner.append((x - nx*width/2, y - ny*width/2))
        outer.append((x + nx*width/2, y + ny*width/2))
    return inner, outer

inner_line, outer_line = build_track_polygons(smooth_line, TRACK_WIDTH)

# Чекпоинты для подсчёта кругов (каждые N точек трассы)
CHECKPOINT_STEP = len(smooth_line) // 8
checkpoints = [smooth_line[i] for i in range(0, len(smooth_line), CHECKPOINT_STEP)]

start_pos = smooth_line[0]
start_angle = math.atan2(
    smooth_line[1][1] - smooth_line[0][1],
    smooth_line[1][0] - smooth_line[0][0]
)

def point_in_track(x, y):
    """Проверка: находится ли точка внутри полосы трассы (примерно, по ближайшему сегменту)"""
    min_dist = 999999
    for (cx, cy) in smooth_line:
        d = (cx-x)**2 + (cy-y)**2
        if d < min_dist:
            min_dist = d
    return min_dist < (TRACK_WIDTH/2)**2


class Car:
    def __init__(self, x, y, angle, color, is_player=True):
        self.x, self.y = x, y
        self.angle = angle
        self.speed = 0
        self.color = color
        self.is_player = is_player
        self.max_speed = 6.5
        self.accel = 0.18
        self.friction = 0.06
        self.turn_speed = 3.6
        self.lap = 0
        self.next_checkpoint = 1
        self.ai_target_index = 5
        self.finished_time = None

    def update(self, keys=None, dt=1):
        if self.is_player and keys:
            if keys[pygame.K_UP] or keys[pygame.K_w]:
                self.speed += self.accel
            if keys[pygame.K_DOWN] or keys[pygame.K_s]:
                self.speed -= self.accel * 1.3
            turn_input = 0
            if keys[pygame.K_LEFT] or keys[pygame.K_a]:
                turn_input = -1
            if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
                turn_input = 1
            if abs(self.speed) > 0.3:
                self.angle += turn_input * self.turn_speed * (self.speed / self.max_speed)
        else:
            self.ai_drive()

        # трение / замедление
        if self.speed > 0:
            self.speed -= self.friction
        elif self.speed < 0:
            self.speed += self.friction
        if abs(self.speed) < self.friction:
            self.speed = 0

        self.speed = max(-self.max_speed/1.6, min(self.max_speed, self.speed))

        rad = math.radians(self.angle)
        new_x = self.x + math.cos(rad) * self.speed
        new_y = self.y + math.sin(rad) * self.speed

        # если съехал с трассы — сильно тормозим (типа трава/грязь)
        if not point_in_track(new_x, new_y):
            self.speed *= 0.85

        self.x, self.y = new_x, new_y

        self.check_lap()

    def ai_drive(self):
        target = smooth_line[self.ai_target_index]
        dx, dy = target[0] - self.x, target[1] - self.y
        dist = math.hypot(dx, dy)
        target_angle = math.degrees(math.atan2(dy, dx))
        diff = (target_angle - self.angle + 180) % 360 - 180
        turn = max(-1, min(1, diff / 30))
        self.angle += turn * self.turn_speed
        self.speed += self.accel * 0.9
        if dist < 40:
            self.ai_target_index = (self.ai_target_index + 3) % len(smooth_line)

    def check_lap(self):
        cx, cy = checkpoints[self.next_checkpoint]
        if math.hypot(self.x - cx, self.y - cy) < 55:
            self.next_checkpoint += 1
            if self.next_checkpoint >= len(checkpoints):
                self.next_checkpoint = 0
                self.lap += 1

    def draw(self, surf):
        car_len, car_wid = 22, 12
        rad = math.radians(self.angle)
        cos_a, sin_a = math.cos(rad), math.sin(rad)
        corners = [(-car_len/2, -car_wid/2), (car_len/2, -car_wid/2),
                   (car_len/2, car_wid/2), (-car_len/2, car_wid/2)]
        points = []
        for cx, cy in corners:
            rx = cx*cos_a - cy*sin_a + self.x
            ry = cx*sin_a + cy*cos_a + self.y
            points.append((rx, ry))
        pygame.draw.polygon(surf, (20, 20, 20), points, 0)
        inner_pts = []
        for cx, cy in [(-car_len/2+3, -car_wid/2+2), (car_len/2-2, -car_wid/2+2),
                       (car_len/2-2, car_wid/2-2), (-car_len/2+3, car_wid/2-2)]:
            rx = cx*cos_a - cy*sin_a + self.x
            ry = cx*sin_a + cy*cos_a + self.y
            inner_pts.append((rx, ry))
        pygame.draw.polygon(surf, self.color, inner_pts, 0)


player = Car(start_pos[0], start_pos[1], math.degrees(start_angle), (220, 50, 50), True)
ai = Car(start_pos[0] - 15*math.sin(start_angle), start_pos[1] + 15*math.cos(start_angle),
          math.degrees(start_angle), (50, 100, 220), False)

TOTAL_LAPS = 3
start_ticks = pygame.time.get_ticks()
race_over = False

running = True
while running:
    dt = clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    keys = pygame.key.get_pressed()
    if not race_over:
        player.update(keys)
        ai.update()

        if player.lap >= TOTAL_LAPS and player.finished_time is None:
            player.finished_time = (pygame.time.get_ticks() - start_ticks) / 1000
        if ai.lap >= TOTAL_LAPS and ai.finished_time is None:
            ai.finished_time = (pygame.time.get_ticks() - start_ticks) / 1000
        if player.finished_time or ai.finished_time:
            race_over = True

    # ---------- ОТРИСОВКА ----------
    screen.fill((70, 150, 60))  # трава

    # трасса (асфальт)
    pygame.draw.polygon(screen, (60, 60, 65), outer_line)
    pygame.draw.polygon(screen, (70, 150, 60), inner_line)

    # бордюры (полосатые)
    for i in range(0, len(outer_line), 4):
        color = (230, 40, 40) if (i // 4) % 2 == 0 else (240, 240, 240)
        pygame.draw.circle(screen, color, (int(outer_line[i][0]), int(outer_line[i][1])), 6)
        pygame.draw.circle(screen, color, (int(inner_line[i][0]), int(inner_line[i][1])), 6)

    # осевая разметка
    for i in range(0, len(smooth_line), 3):
        p = smooth_line[i]
        pygame.draw.circle(screen, (255, 255, 255), (int(p[0]), int(p[1])), 2)

    # линия старта/финиша
    sx, sy = start_pos
    pygame.draw.line(screen, (255, 255, 255),
                      (sx, sy - TRACK_WIDTH/2), (sx, sy + TRACK_WIDTH/2), 5)

    ai.draw(screen)
    player.draw(screen)

    # HUD
    timer = (pygame.time.get_ticks() - start_ticks) / 1000 if not race_over else min(
        player.finished_time or 999, ai.finished_time or 999)
    hud1 = font.render(f"Круг: {min(player.lap+1, TOTAL_LAPS)}/{TOTAL_LAPS}", True, (255,255,255))
    hud2 = font.render(f"Время: {timer:.1f}с", True, (255,255,255))
    screen.blit(hud1, (20, 20))
    screen.blit(hud2, (20, 55))

    if race_over:
        if player.finished_time and (ai.finished_time is None or player.finished_time <= ai.finished_time):
            msg = "ТЫ ПОБЕДИЛ!"
        else:
            msg = "СОПЕРНИК ПОБЕДИЛ"
        text = big_font.render(msg, True, (255, 255, 0))
        screen.blit(text, (W//2 - text.get_width()//2, H//2 - 40))

    pygame.display.flip()

pygame.quit()