Загрузка данных
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()