123Aadidev

Untitled

Jul 24th, 2026
39
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 19.32 KB | None | 0 0
  1. """
  2. SUPER DETAILED CAR GAME
  3. ------------------------
  4. A top-down car racing / dodging game built with Pygame.
  5.  
  6. Features:
  7. - Smooth accelerating/braking/steering car physics
  8. - Scrolling multi-lane highway with lane markings
  9. - Randomly spawning traffic cars you must dodge
  10. - Collision detection with crash effect
  11. - Score based on distance survived + near-misses
  12. - Increasing difficulty (traffic speed & spawn rate) over time
  13. - Fuel/boost meter with a nitro boost (Shift key)
  14. - Particle effects for exhaust smoke and crashes
  15. - Start menu, pause menu, and game-over screen with high score tracking
  16. - On-screen HUD (speed, score, high score, fuel)
  17.  
  18. Controls:
  19. LEFT / RIGHT or A / D - Steer
  20. UP / W - Accelerate
  21. DOWN / S - Brake / Reverse
  22. SHIFT - Nitro boost (uses fuel)
  23. P - Pause
  24. ENTER - Start / Restart
  25. ESC - Quit
  26.  
  27. Run with: python car_game.py
  28. (Requires: pip install pygame)
  29. """
  30.  
  31. import pygame
  32. import random
  33. import sys
  34. import math
  35. import json
  36. import os
  37.  
  38. # --------------------------------------------------------------------------
  39. # CONFIG / CONSTANTS
  40. # --------------------------------------------------------------------------
  41.  
  42. SCREEN_WIDTH = 800
  43. SCREEN_HEIGHT = 700
  44. FPS = 60
  45.  
  46. ROAD_WIDTH = 480
  47. ROAD_LEFT = (SCREEN_WIDTH - ROAD_WIDTH) // 2
  48. ROAD_RIGHT = ROAD_LEFT + ROAD_WIDTH
  49. NUM_LANES = 4
  50. LANE_WIDTH = ROAD_WIDTH // NUM_LANES
  51.  
  52. GRASS_COLOR = (34, 120, 45)
  53. ROAD_COLOR = (55, 55, 60)
  54. SHOULDER_COLOR = (90, 90, 95)
  55. LINE_COLOR = (230, 230, 60)
  56.  
  57. WHITE = (255, 255, 255)
  58. BLACK = (10, 10, 10)
  59. RED = (220, 40, 40)
  60. DARK_RED = (150, 20, 20)
  61. YELLOW = (250, 210, 30)
  62. BLUE = (40, 110, 220)
  63. GREEN = (60, 200, 90)
  64. GRAY = (150, 150, 150)
  65. ORANGE = (245, 140, 30)
  66.  
  67. HIGH_SCORE_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "car_game_highscore.json")
  68. def load_high_score():
  69. try:
  70. with open(HIGH_SCORE_FILE, "r") as f:
  71. data = json.load(f)
  72. return int(data.get("high_score", 0))
  73. except (FileNotFoundError, json.JSONDecodeError, ValueError):
  74. return 0
  75.  
  76.  
  77. def save_high_score(score):
  78. try:
  79. with open(HIGH_SCORE_FILE, "w") as f:
  80. json.dump({"high_score": score}, f)
  81. except OSError:
  82. pass
  83.  
  84.  
  85. class Particle:
  86. def __init__(self, x, y, color, vel, life, radius, gravity=0.0, fade=True):
  87. self.x = x
  88. self.y = y
  89. self.color = color
  90. self.vx, self.vy = vel
  91. self.life = life
  92. self.max_life = life
  93. self.radius = radius
  94. self.gravity = gravity
  95. self.fade = fade
  96.  
  97. def update(self):
  98. self.x += self.vx
  99. self.y += self.vy
  100. self.vy += self.gravity
  101. self.life -= 1
  102.  
  103. def alive(self):
  104. return self.life > 0
  105.  
  106. def draw(self, surface):
  107. if self.life <= 0:
  108. return
  109. t = self.life / self.max_life
  110. r = max(1, int(self.radius * t)) if self.fade else self.radius
  111. alpha_color = self.color
  112. s = pygame.Surface((r * 2, r * 2), pygame.SRCALPHA)
  113. pygame.draw.circle(s, (*alpha_color, int(255 * t) if self.fade else 255), (r, r), r)
  114. surface.blit(s, (int(self.x - r), int(self.y - r)))
  115.  
  116.  
  117. class ParticleSystem:
  118. def __init__(self):
  119. self.particles = []
  120.  
  121. def emit_exhaust(self, x, y):
  122. for _ in range(1):
  123. vel = (random.uniform(-0.3, 0.3), random.uniform(1.5, 3.0))
  124. self.particles.append(
  125. Particle(x, y, GRAY, vel, life=25, radius=6, fade=True)
  126. )
  127.  
  128. def emit_crash(self, x, y):
  129. for _ in range(40):
  130. angle = random.uniform(0, math.tau)
  131. speed = random.uniform(2, 8)
  132. vel = (math.cos(angle) * speed, math.sin(angle) * speed)
  133. color = random.choice([ORANGE, RED, YELLOW, GRAY])
  134. self.particles.append(
  135. Particle(x, y, color, vel, life=random.randint(20, 45),
  136. radius=random.randint(3, 7), gravity=0.15)
  137. )
  138.  
  139. def update(self):
  140. self.particles = [p for p in self.particles if p.alive()]
  141. for p in self.particles:
  142. p.update()
  143.  
  144. def draw(self, surface):
  145. for p in self.particles:
  146. p.draw(surface)
  147.  
  148.  
  149. def make_car_surface(width, height, body_color, window_color=(30, 30, 40)):
  150. """Draw a simple top-down car sprite onto a transparent surface."""
  151. surf = pygame.Surface((width, height), pygame.SRCALPHA)
  152. body_rect = pygame.Rect(0, 6, width, height - 12)
  153. pygame.draw.rect(surf, body_color, body_rect, border_radius=10)
  154. # windshield / rear window
  155. pygame.draw.rect(surf, window_color, (width * 0.18, height * 0.12, width * 0.64, height * 0.22), border_radius=4)
  156. pygame.draw.rect(surf, window_color, (width * 0.18, height * 0.66, width * 0.64, height * 0.22), border_radius=4)
  157. # headlights
  158. pygame.draw.circle(surf, (255, 250, 200), (int(width * 0.2), 8), 4)
  159. pygame.draw.circle(surf, (255, 250, 200), (int(width * 0.8), 8), 4)
  160. # taillights
  161. pygame.draw.circle(surf, (255, 60, 60), (int(width * 0.2), height - 8), 4)
  162. pygame.draw.circle(surf, (255, 60, 60), (int(width * 0.8), height - 8), 4)
  163. # side mirrors
  164. pygame.draw.rect(surf, body_color, (-3, height * 0.32, 6, 8))
  165. pygame.draw.rect(surf, body_color, (width - 3, height * 0.32, 6, 8))
  166. return surf
  167.  
  168.  
  169. class PlayerCar:
  170. WIDTH = 46
  171. HEIGHT = 84
  172.  
  173. def __init__(self):
  174. self.x = SCREEN_WIDTH / 2
  175. self.y = SCREEN_HEIGHT - 140
  176. self.vx = 0.0
  177. self.speed = 0.0
  178. self.max_speed = 14.0
  179. self.min_speed = -3.0
  180. self.acceleration = 0.18
  181. self.brake_power = 0.35
  182. self.friction = 0.06
  183. self.steer_speed = 0.32
  184. self.max_steer_v = 6.5
  185. self.sprite = make_car_surface(self.WIDTH, self.HEIGHT, BLUE)
  186. self.fuel = 100.0
  187. self.boosting = False
  188. self.alive = True
  189. self.invincible_timer = 0
  190.  
  191. @property
  192. def rect(self):
  193.  
  194. w, h = self.WIDTH - 10, self.HEIGHT - 14
  195. return pygame.Rect(self.x - w / 2, self.y - h / 2, w, h)
  196.  
  197. def handle_input(self, keys, dt_scale):
  198. # Steering
  199. if keys[pygame.K_LEFT] or keys[pygame.K_a]:
  200. self.vx -= self.steer_speed * dt_scale
  201. elif keys[pygame.K_RIGHT] or keys[pygame.K_d]:
  202. self.vx += self.steer_speed * dt_scale
  203. else:
  204.  
  205. self.vx *= 0.85
  206.  
  207. self.vx = max(-self.max_steer_v, min(self.max_steer_v, self.vx))
  208.  
  209. if keys[pygame.K_UP] or keys[pygame.K_w]:
  210. self.speed += self.acceleration * dt_scale
  211. elif keys[pygame.K_DOWN] or keys[pygame.K_s]:
  212. self.speed -= self.brake_power * dt_scale
  213. else:
  214. if self.speed > 0:
  215. self.speed -= self.friction * dt_scale
  216. elif self.speed < 0:
  217. self.speed += self.friction * dt_scale
  218.  
  219.  
  220. self.boosting = False
  221. if (keys[pygame.K_LSHIFT] or keys[pygame.K_RSHIFT]) and self.fuel > 0 and self.speed > 0:
  222. self.speed += self.acceleration * 1.6 * dt_scale
  223. self.fuel -= 0.9 * dt_scale
  224. self.boosting = True
  225. else:
  226. self.fuel = min(100.0, self.fuel + 0.12 * dt_scale)
  227.  
  228. top_speed = self.max_speed * (1.35 if self.boosting else 1.0)
  229. self.speed = max(self.min_speed, min(top_speed, self.speed))
  230.  
  231. def update(self, dt_scale):
  232. self.x += self.vx * dt_scale
  233.  
  234. margin = self.WIDTH / 2
  235. self.x = max(ROAD_LEFT - 20 + margin, min(ROAD_RIGHT + 20 - margin, self.x))
  236.  
  237. def draw(self, surface, particles):
  238.  
  239. if self.speed > 1:
  240. particles.emit_exhaust(self.x, self.y + self.HEIGHT / 2 - 4)
  241.  
  242. tilt = max(-12, min(12, -self.vx * 2.2))
  243. rotated = pygame.transform.rotate(self.sprite, tilt)
  244. rect = rotated.get_rect(center=(self.x, self.y))
  245. surface.blit(rotated, rect)
  246.  
  247.  
  248. if self.boosting:
  249. flame_h = random.randint(14, 26)
  250. flame_rect = pygame.Rect(0, 0, 14, flame_h)
  251. flame_rect.midtop = (self.x, self.y + self.HEIGHT / 2 - 6)
  252. pygame.draw.polygon(surface, ORANGE, [
  253. (flame_rect.centerx - 7, flame_rect.top),
  254. (flame_rect.centerx + 7, flame_rect.top),
  255. (flame_rect.centerx, flame_rect.bottom),
  256. ])
  257.  
  258.  
  259. class TrafficCar:
  260. WIDTH = 46
  261. HEIGHT = 84
  262. COLORS = [RED, GREEN, YELLOW, (150, 60, 200), (240, 240, 240), ORANGE]
  263.  
  264. def __init__(self, lane_x, y, speed):
  265. self.x = lane_x
  266. self.y = y
  267. self.speed = speed
  268. color = random.choice(self.COLORS)
  269. self.sprite = make_car_surface(self.WIDTH, self.HEIGHT, color)
  270. self.passed = False
  271.  
  272. @property
  273. def rect(self):
  274. w, h = self.WIDTH - 10, self.HEIGHT - 14
  275. return pygame.Rect(self.x - w / 2, self.y - h / 2, w, h)
  276.  
  277. def update(self, scroll_speed):
  278. self.y += scroll_speed - self.speed
  279.  
  280. def draw(self, surface):
  281. surface.blit(self.sprite, self.sprite.get_rect(center=(self.x, self.y)))
  282.  
  283. def off_screen(self):
  284. return self.y > SCREEN_HEIGHT + 120 or self.y < -120
  285.  
  286.  
  287. class Road:
  288. def __init__(self):
  289. self.dash_offset = 0
  290.  
  291. def update(self, scroll_speed):
  292. self.dash_offset = (self.dash_offset + scroll_speed) % 60
  293.  
  294. def lane_centers(self):
  295. return [ROAD_LEFT + LANE_WIDTH * (i + 0.5) for i in range(NUM_LANES)]
  296.  
  297. def draw(self, surface):
  298. surface.fill(GRASS_COLOR)
  299. # shoulders
  300. pygame.draw.rect(surface, SHOULDER_COLOR, (ROAD_LEFT - 20, 0, ROAD_WIDTH + 40, SCREEN_HEIGHT))
  301. # road
  302. pygame.draw.rect(surface, ROAD_COLOR, (ROAD_LEFT, 0, ROAD_WIDTH, SCREEN_HEIGHT))
  303. # edge lines (solid white)
  304. pygame.draw.rect(surface, WHITE, (ROAD_LEFT, 0, 5, SCREEN_HEIGHT))
  305. pygame.draw.rect(surface, WHITE, (ROAD_RIGHT - 5, 0, 5, SCREEN_HEIGHT))
  306. # lane dashes
  307. for i in range(1, NUM_LANES):
  308. x = ROAD_LEFT + LANE_WIDTH * i
  309. y = -60 + self.dash_offset
  310. while y < SCREEN_HEIGHT:
  311. pygame.draw.rect(surface, LINE_COLOR, (x - 3, y, 6, 34))
  312. y += 60
  313.  
  314. class Game:
  315. STATE_MENU = "menu"
  316. STATE_PLAYING = "playing"
  317. STATE_PAUSED = "paused"
  318. STATE_GAMEOVER = "gameover"
  319.  
  320. def __init__(self):
  321. pygame.init()
  322. pygame.display.set_caption("Super Detailed Car Game")
  323. self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
  324. self.clock = pygame.time.Clock()
  325.  
  326. self.font_big = pygame.font.SysFont("arial", 64, bold=True)
  327. self.font_med = pygame.font.SysFont("arial", 32, bold=True)
  328. self.font_small = pygame.font.SysFont("arial", 22)
  329.  
  330. self.high_score = load_high_score()
  331. self.state = self.STATE_MENU
  332. self.reset()
  333.  
  334. def reset(self):
  335. self.player = PlayerCar()
  336. self.road = Road()
  337. self.particles = ParticleSystem()
  338. self.traffic = []
  339. self.spawn_timer = 0
  340. self.spawn_interval = 70
  341. self.distance = 0.0
  342. self.score = 0
  343. self.difficulty_timer = 0
  344. self.base_traffic_speed = 3.0
  345. self.max_traffic_speed_variance = 2.0
  346. self.scroll_speed = 0.0
  347. self.crash_shake = 0
  348.  
  349.  
  350. def spawn_traffic(self):
  351. lanes = self.road.lane_centers()
  352.  
  353. candidate_lanes = list(range(NUM_LANES))
  354. random.shuffle(candidate_lanes)
  355. for lane_i in candidate_lanes:
  356. lane_x = lanes[lane_i]
  357. too_close = any(
  358. abs(t.x - lane_x) < 5 and t.y < 160
  359. for t in self.traffic
  360. )
  361. if not too_close:
  362. speed = self.base_traffic_speed + random.uniform(
  363. -self.max_traffic_speed_variance * 0.3, self.max_traffic_speed_variance
  364. )
  365. self.traffic.append(TrafficCar(lane_x, -120, speed))
  366. break
  367. def update(self):
  368. if self.state != self.STATE_PLAYING:
  369. self.particles.update()
  370. return
  371.  
  372. keys = pygame.key.get_pressed()
  373. self.player.handle_input(keys, dt_scale=1.0)
  374. self.player.update(dt_scale=1.0)
  375.  
  376. self.scroll_speed = max(0.0, self.player.speed)
  377. self.distance += self.scroll_speed
  378. self.road.update(self.scroll_speed)
  379.  
  380. # difficulty ramps up over time
  381. self.difficulty_timer += 1
  382. if self.difficulty_timer % 300 == 0:
  383. self.base_traffic_speed = min(9.0, self.base_traffic_speed + 0.4)
  384. self.spawn_interval = max(28, self.spawn_interval - 4)
  385.  
  386. # spawn traffic
  387. self.spawn_timer += 1
  388. if self.spawn_timer >= self.spawn_interval:
  389. self.spawn_timer = 0
  390. self.spawn_traffic()
  391.  
  392. # update traffic
  393. for t in self.traffic:
  394. t.update(self.scroll_speed)
  395.  
  396. # near-miss / passed scoring
  397. for t in self.traffic:
  398. if not t.passed and t.y > self.player.y + 60:
  399. t.passed = True
  400. self.score += 15
  401.  
  402. # collisions
  403. player_rect = self.player.rect
  404. for t in self.traffic:
  405. if player_rect.colliderect(t.rect):
  406. self.crash()
  407. break
  408.  
  409. self.traffic = [t for t in self.traffic if not t.off_screen()]
  410.  
  411. # score from distance
  412. self.score = self.score # (near-miss score already added)
  413. self.distance_score = int(self.distance / 8)
  414.  
  415. self.particles.update()
  416.  
  417. if self.crash_shake > 0:
  418. self.crash_shake -= 1
  419.  
  420. def crash(self):
  421. self.particles.emit_crash(self.player.x, self.player.y)
  422. self.crash_shake = 18
  423. self.state = self.STATE_GAMEOVER
  424. final_score = self.score + int(self.distance / 8)
  425. if final_score > self.high_score:
  426. self.high_score = final_score
  427. save_high_score(self.high_score)
  428. self.final_score = final_score
  429.  
  430. # ---------------- DRAW ----------------
  431.  
  432. def draw(self):
  433. offset_x, offset_y = 0, 0
  434. if self.crash_shake > 0:
  435. offset_x = random.randint(-8, 8)
  436. offset_y = random.randint(-8, 8)
  437.  
  438. canvas = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT))
  439. self.road.draw(canvas)
  440.  
  441. for t in sorted(self.traffic, key=lambda c: c.y):
  442. t.draw(canvas)
  443.  
  444. if self.state in (self.STATE_PLAYING, self.STATE_PAUSED):
  445. self.player.draw(canvas, self.particles)
  446. elif self.state == self.STATE_GAMEOVER:
  447. # still show wrecked player briefly
  448. self.player.draw(canvas, self.particles)
  449.  
  450. self.particles.draw(canvas)
  451.  
  452. self.screen.blit(canvas, (offset_x, offset_y))
  453.  
  454. self.draw_hud()
  455.  
  456. if self.state == self.STATE_MENU:
  457. self.draw_menu()
  458. elif self.state == self.STATE_PAUSED:
  459. self.draw_pause()
  460. elif self.state == self.STATE_GAMEOVER:
  461. self.draw_gameover()
  462.  
  463. pygame.display.flip()
  464.  
  465. def draw_text_center(self, text, font, color, y, outline=True):
  466. surf = font.render(text, True, color)
  467. rect = surf.get_rect(center=(SCREEN_WIDTH / 2, y))
  468. if outline:
  469. out = font.render(text, True, BLACK)
  470. for dx, dy in [(-2, 0), (2, 0), (0, -2), (0, 2)]:
  471. self.screen.blit(out, out.get_rect(center=(SCREEN_WIDTH / 2 + dx, y + dy)))
  472. self.screen.blit(surf, rect)
  473.  
  474. def draw_hud(self):
  475. if self.state not in (self.STATE_PLAYING, self.STATE_PAUSED):
  476. return
  477. current_score = self.score + int(self.distance / 8)
  478. hud_lines = [
  479. f"Score: {current_score}",
  480. f"High Score: {self.high_score}",
  481. f"Speed: {int(self.player.speed * 12)} km/h",
  482. ]
  483. for i, line in enumerate(hud_lines):
  484. surf = self.font_small.render(line, True, WHITE)
  485. self.screen.blit(surf, (14, 12 + i * 26))
  486.  
  487. # fuel bar
  488. bar_x, bar_y, bar_w, bar_h = SCREEN_WIDTH - 174, 14, 160, 20
  489. pygame.draw.rect(self.screen, (50, 50, 50), (bar_x, bar_y, bar_w, bar_h), border_radius=5)
  490. fill_w = int(bar_w * (self.player.fuel / 100))
  491. fuel_color = GREEN if self.player.fuel > 30 else RED
  492. pygame.draw.rect(self.screen, fuel_color, (bar_x, bar_y, fill_w, bar_h), border_radius=5)
  493. pygame.draw.rect(self.screen, WHITE, (bar_x, bar_y, bar_w, bar_h), 2, border_radius=5)
  494. label = self.font_small.render("NITRO", True, WHITE)
  495. self.screen.blit(label, (bar_x, bar_y + bar_h + 2))
  496.  
  497. def draw_menu(self):
  498. overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA)
  499. overlay.fill((0, 0, 0, 140))
  500. self.screen.blit(overlay, (0, 0))
  501. self.draw_text_center("SUPER CAR GAME", self.font_big, YELLOW, 220)
  502. self.draw_text_center("Press ENTER to Start", self.font_med, WHITE, 320)
  503. self.draw_text_center(f"High Score: {self.high_score}", self.font_small, WHITE, 370)
  504. controls = [
  505. "Arrows / WASD: Steer & Accelerate",
  506. "SHIFT: Nitro Boost | P: Pause | ESC: Quit",
  507. ]
  508. for i, line in enumerate(controls):
  509. self.draw_text_center(line, self.font_small, GRAY, 430 + i * 28)
  510.  
  511. def draw_pause(self):
  512. overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA)
  513. overlay.fill((0, 0, 0, 150))
  514. self.screen.blit(overlay, (0, 0))
  515. self.draw_text_center("PAUSED", self.font_big, WHITE, 300)
  516. self.draw_text_center("Press P to Resume", self.font_med, WHITE, 370)
  517.  
  518. def draw_gameover(self):
  519. overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA)
  520. overlay.fill((0, 0, 0, 170))
  521. self.screen.blit(overlay, (0, 0))
  522. self.draw_text_center("CRASHED!", self.font_big, RED, 260)
  523. self.draw_text_center(f"Score: {self.final_score}", self.font_med, WHITE, 330)
  524. self.draw_text_center(f"High Score: {self.high_score}", self.font_med, YELLOW, 370)
  525. self.draw_text_center("Press ENTER to Restart", self.font_small, WHITE, 430)
  526. def run(self):
  527. running = True
  528. while running:
  529. for event in pygame.event.get():
  530. if event.type == pygame.QUIT:
  531. running = False
  532. elif event.type == pygame.KEYDOWN:
  533. if event.key == pygame.K_ESCAPE:
  534. running = False
  535. elif event.key == pygame.K_RETURN:
  536. if self.state in (self.STATE_MENU, self.STATE_GAMEOVER):
  537. self.reset()
  538. self.state = self.STATE_PLAYING
  539. elif event.key == pygame.K_p:
  540. if self.state == self.STATE_PLAYING:
  541. self.state = self.STATE_PAUSED
  542. elif self.state == self.STATE_PAUSED:
  543. self.state = self.STATE_PLAYING
  544.  
  545. self.update()
  546. self.draw()
  547. self.clock.tick(FPS)
  548. pygame.quit()
  549. sys.exit()
  550. if __name__ == "__main__":
  551. game = Game()
  552.  
  553. game.run()
Advertisement
Add Comment
Please, Sign In to add comment