123Aadidev

Untitled

Aug 8th, 2026
32
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 46.63 KB | None | 0 0
  1. import pygame
  2. import math
  3. import random
  4. import sys
  5.  
  6. # ============================================================
  7. # NO HESI - HIGHWAY TRAFFIC WEAVER
  8. # SINGLE FILE - PART 1/4
  9. # ============================================================
  10.  
  11. pygame.init()
  12. pygame.font.init()
  13.  
  14. WIDTH, HEIGHT = 1000, 800
  15.  
  16. screen = pygame.display.set_mode((WIDTH, HEIGHT))
  17. pygame.display.set_caption("NO HESI - Highway Traffic Weaver")
  18.  
  19. clock = pygame.time.Clock()
  20.  
  21. # ============================================================
  22. # FONTS
  23. # ============================================================
  24.  
  25. FONT_TITLE = pygame.font.SysFont("arial", 46, bold=True)
  26. FONT_BIG = pygame.font.SysFont("arial", 34, bold=True)
  27. FONT_MED = pygame.font.SysFont("arial", 22, bold=True)
  28. FONT_HUD = pygame.font.SysFont("consolas", 18, bold=True)
  29. FONT_SMALL = pygame.font.SysFont("consolas", 14)
  30.  
  31. # ============================================================
  32. # COLORS
  33. # ============================================================
  34.  
  35. COLOR_BG = (10, 13, 17)
  36. COLOR_ROAD = (38, 40, 45)
  37. COLOR_GRASS = (18, 45, 23)
  38.  
  39. COLOR_LINE_YELLOW = (245, 210, 50)
  40. COLOR_LINE_WHITE = (220, 220, 225)
  41.  
  42. COLOR_TEXT = (240, 240, 240)
  43. COLOR_GOLD = (255, 215, 0)
  44. COLOR_CYAN = (0, 230, 255)
  45. COLOR_RED = (255, 60, 60)
  46. COLOR_ORANGE = (255, 130, 30)
  47. COLOR_GREEN = (60, 255, 100)
  48.  
  49. # ============================================================
  50. # HIGHWAY
  51. # ============================================================
  52.  
  53. ROAD_LEFT = 170
  54. ROAD_RIGHT = 830
  55.  
  56. ROAD_WIDTH = ROAD_RIGHT - ROAD_LEFT
  57.  
  58. NUM_LANES = 5
  59. LANE_WIDTH = ROAD_WIDTH // NUM_LANES
  60.  
  61. # ============================================================
  62. # PLAYER CARS
  63. # ============================================================
  64.  
  65. CARS = {
  66. "1": {
  67. "name": "M4 Competition",
  68. "max_speed": 22.0,
  69. "accel": 0.34,
  70. "brake": 0.55,
  71. "handling": 6.8,
  72. "grip": 0.96,
  73. "color": (20, 150, 230),
  74. "desc": "Agile, fast and extremely responsive."
  75. },
  76.  
  77. "2": {
  78. "name": "RS7 Sportback",
  79. "max_speed": 25.0,
  80. "accel": 0.38,
  81. "brake": 0.58,
  82. "handling": 5.7,
  83. "grip": 0.92,
  84. "color": (210, 30, 35),
  85. "desc": "Heavy highway missile with huge top speed."
  86. },
  87.  
  88. "3": {
  89. "name": "GT-R Nismo",
  90. "max_speed": 23.5,
  91. "accel": 0.36,
  92. "brake": 0.62,
  93. "handling": 6.2,
  94. "grip": 0.98,
  95. "color": (225, 225, 230),
  96. "desc": "Balanced power, grip and acceleration."
  97. }
  98. }
  99.  
  100. # ============================================================
  101. # PARTICLE SYSTEM
  102. # ============================================================
  103.  
  104. class Particle:
  105.  
  106. def __init__(self, x, y, color, size, velocity, life):
  107. self.x = x
  108. self.y = y
  109.  
  110. self.color = color
  111. self.size = size
  112.  
  113. self.vx, self.vy = velocity
  114.  
  115. self.life = life
  116. self.max_life = life
  117.  
  118. def update(self):
  119.  
  120. self.x += self.vx
  121. self.y += self.vy
  122.  
  123. self.vx *= 0.96
  124. self.vy *= 0.96
  125.  
  126. self.size *= 0.97
  127.  
  128. self.life -= 1
  129.  
  130. def draw(self, surface):
  131.  
  132. if self.life <= 0:
  133. return
  134.  
  135. alpha = max(
  136. 0,
  137. min(
  138. 255,
  139. int(255 * (self.life / self.max_life))
  140. )
  141. )
  142.  
  143. particle_size = max(
  144. 2,
  145. int(self.size * 2)
  146. )
  147.  
  148. particle_surface = pygame.Surface(
  149. (particle_size, particle_size),
  150. pygame.SRCALPHA
  151. )
  152.  
  153. pygame.draw.circle(
  154. particle_surface,
  155. (*self.color, alpha),
  156. (
  157. particle_size // 2,
  158. particle_size // 2
  159. ),
  160. max(1, int(self.size))
  161. )
  162.  
  163. surface.blit(
  164. particle_surface,
  165. (
  166. int(self.x - particle_size / 2),
  167. int(self.y - particle_size / 2)
  168. )
  169. )
  170.  
  171.  
  172. particles = []
  173.  
  174.  
  175. def create_smoke(x, y, amount=2, dark=False):
  176.  
  177. for _ in range(amount):
  178.  
  179. if dark:
  180. color = (75, 75, 75)
  181. else:
  182. color = (165, 165, 165)
  183.  
  184. particles.append(
  185. Particle(
  186. x + random.uniform(-7, 7),
  187. y + random.uniform(-5, 5),
  188. color,
  189. random.uniform(3, 7),
  190. (
  191. random.uniform(-0.8, 0.8),
  192. random.uniform(0.5, 2.0)
  193. ),
  194. random.randint(18, 35)
  195. )
  196. )
  197.  
  198.  
  199. # ============================================================
  200. # TRAFFIC CAR
  201. # ============================================================
  202.  
  203. class TrafficCar:
  204.  
  205. def __init__(self, lane, speed):
  206.  
  207. self.lane = lane
  208.  
  209. self.x = (
  210. ROAD_LEFT +
  211. lane * LANE_WIDTH +
  212. LANE_WIDTH // 2
  213. )
  214.  
  215. self.y = -120
  216.  
  217. self.width = random.randint(34, 42)
  218. self.height = random.randint(62, 76)
  219.  
  220. self.speed = speed
  221.  
  222. self.color = random.choice([
  223. (130, 135, 145),
  224. (190, 45, 45),
  225. (45, 150, 75),
  226. (205, 190, 45),
  227. (110, 70, 170),
  228. (210, 120, 35),
  229. (60, 100, 180),
  230. (190, 190, 195)
  231. ])
  232.  
  233. self.near_missed = False
  234. self.angle = 0
  235.  
  236. def update(self, player_speed):
  237.  
  238. # Relative highway movement
  239. self.y += player_speed - self.speed
  240.  
  241. # Tiny realistic movement
  242. self.x += math.sin(self.y * 0.02) * 0.05
  243.  
  244. def get_rect(self):
  245.  
  246. return pygame.Rect(
  247. int(self.x - self.width / 2),
  248. int(self.y - self.height / 2),
  249. self.width,
  250. self.height
  251. )
  252.  
  253. def draw(self, surface):
  254.  
  255. rect = self.get_rect()
  256.  
  257. # Shadow
  258. shadow = pygame.Rect(
  259. rect.left - 3,
  260. rect.bottom - 4,
  261. rect.width + 6,
  262. 8
  263. )
  264.  
  265. pygame.draw.ellipse(
  266. surface,
  267. (15, 15, 15),
  268. shadow
  269. )
  270.  
  271. # Main body
  272. pygame.draw.rect(
  273. surface,
  274. self.color,
  275. rect,
  276. border_radius=9
  277. )
  278.  
  279. # Dark lower bumper
  280. darker_color = tuple(
  281. max(0, c - 35)
  282. for c in self.color
  283. )
  284.  
  285. pygame.draw.rect(
  286. surface,
  287. darker_color,
  288. (
  289. rect.left + 3,
  290. rect.bottom - 12,
  291. rect.width - 6,
  292. 10
  293. ),
  294. border_radius=4
  295. )
  296.  
  297. # Windows
  298. window_rect = pygame.Rect(
  299. rect.left + 5,
  300. rect.top + 13,
  301. rect.width - 10,
  302. 27
  303. )
  304.  
  305. pygame.draw.rect(
  306. surface,
  307. (18, 25, 35),
  308. window_rect,
  309. border_radius=5
  310. )
  311.  
  312. # Window divider
  313. pygame.draw.line(
  314. surface,
  315. (70, 75, 85),
  316. (
  317. rect.centerx,
  318. window_rect.top
  319. ),
  320. (
  321. rect.centerx,
  322. window_rect.bottom
  323. ),
  324. 2
  325. )
  326.  
  327. # Headlights
  328. pygame.draw.rect(
  329. surface,
  330. (255, 255, 210),
  331. (
  332. rect.left + 4,
  333. rect.top + 3,
  334. 9,
  335. 5
  336. ),
  337. border_radius=2
  338. )
  339.  
  340. pygame.draw.rect(
  341. surface,
  342. (255, 255, 210),
  343. (
  344. rect.right - 13,
  345. rect.top + 3,
  346. 9,
  347. 5
  348. ),
  349. border_radius=2
  350. )
  351.  
  352. # Tail lights
  353. pygame.draw.rect(
  354. surface,
  355. (255, 20, 20),
  356. (
  357. rect.left + 4,
  358. rect.bottom - 8,
  359. 9,
  360. 5
  361. )
  362. )
  363.  
  364. pygame.draw.rect(
  365. surface,
  366. (255, 20, 20),
  367. (
  368. rect.right - 13,
  369. rect.bottom - 8,
  370. 9,
  371. 5
  372. )
  373. )
  374. # ============================================================
  375. # POLICE CAR
  376. # ============================================================
  377.  
  378. class PoliceCar:
  379.  
  380. def __init__(self):
  381.  
  382. self.width = 40
  383. self.height = 76
  384.  
  385. self.x = random.choice([
  386. ROAD_LEFT + LANE_WIDTH // 2,
  387. ROAD_RIGHT - LANE_WIDTH // 2
  388. ])
  389.  
  390. self.y = HEIGHT + 180
  391.  
  392. self.speed = 16.0
  393. self.target_speed = 18.0
  394.  
  395. self.active = True
  396. self.siren_phase = 0
  397.  
  398. def update(self, player):
  399.  
  400. # Police accelerates
  401. if self.speed < self.target_speed:
  402. self.speed += 0.08
  403.  
  404. # Move relative to player
  405. self.y += player.speed - self.speed
  406.  
  407. # Chase player's horizontal position
  408. dx = player.x - self.x
  409.  
  410. self.x += max(
  411. -3.5,
  412. min(3.5, dx * 0.025)
  413. )
  414.  
  415. # Keep police on highway
  416. self.x = max(
  417. ROAD_LEFT + 25,
  418. min(ROAD_RIGHT - 25, self.x)
  419. )
  420.  
  421. self.siren_phase += 0.25
  422.  
  423. def get_rect(self):
  424.  
  425. return pygame.Rect(
  426. int(self.x - self.width / 2),
  427. int(self.y - self.height / 2),
  428. self.width,
  429. self.height
  430. )
  431.  
  432. def draw(self, surface):
  433.  
  434. rect = self.get_rect()
  435.  
  436. # Shadow
  437. pygame.draw.ellipse(
  438. surface,
  439. (10, 10, 10),
  440. (
  441. rect.left - 4,
  442. rect.bottom - 5,
  443. rect.width + 8,
  444. 10
  445. )
  446. )
  447.  
  448. # White body
  449. pygame.draw.rect(
  450. surface,
  451. (235, 235, 240),
  452. rect,
  453. border_radius=8
  454. )
  455.  
  456. # Black police section
  457. pygame.draw.rect(
  458. surface,
  459. (20, 20, 25),
  460. (
  461. rect.left + 2,
  462. rect.top + 30,
  463. rect.width - 4,
  464. 22
  465. )
  466. )
  467.  
  468. # Windows
  469. pygame.draw.rect(
  470. surface,
  471. (15, 25, 35),
  472. (
  473. rect.left + 5,
  474. rect.top + 12,
  475. rect.width - 10,
  476. 22
  477. ),
  478. border_radius=4
  479. )
  480.  
  481. # Siren
  482. red_on = math.sin(self.siren_phase) > 0
  483.  
  484. if red_on:
  485.  
  486. pygame.draw.rect(
  487. surface,
  488. (255, 30, 30),
  489. (
  490. rect.centerx - 12,
  491. rect.top + 3,
  492. 12,
  493. 6
  494. )
  495. )
  496.  
  497. pygame.draw.rect(
  498. surface,
  499. (40, 80, 255),
  500. (
  501. rect.centerx,
  502. rect.top + 3,
  503. 12,
  504. 6
  505. )
  506. )
  507.  
  508. else:
  509.  
  510. pygame.draw.rect(
  511. surface,
  512. (40, 80, 255),
  513. (
  514. rect.centerx - 12,
  515. rect.top + 3,
  516. 12,
  517. 6
  518. )
  519. )
  520.  
  521. pygame.draw.rect(
  522. surface,
  523. (255, 30, 30),
  524. (
  525. rect.centerx,
  526. rect.top + 3,
  527. 12,
  528. 6
  529. )
  530. )
  531.  
  532. # Tail lights
  533. pygame.draw.rect(
  534. surface,
  535. (255, 30, 30),
  536. (
  537. rect.left + 4,
  538. rect.bottom - 8,
  539. 9,
  540. 5
  541. )
  542. )
  543.  
  544. pygame.draw.rect(
  545. surface,
  546. (255, 30, 30),
  547. (
  548. rect.right - 13,
  549. rect.bottom - 8,
  550. 9,
  551. 5
  552. )
  553. )
  554.  
  555.  
  556. # ============================================================
  557. # PLAYER CAR
  558. # ============================================================
  559.  
  560. class PlayerCar:
  561.  
  562. def __init__(self, specs):
  563.  
  564. self.x = WIDTH // 2
  565. self.y = HEIGHT - 160
  566.  
  567. self.width = 42
  568. self.height = 78
  569.  
  570. self.name = specs["name"]
  571.  
  572. self.max_speed = specs["max_speed"]
  573. self.accel = specs["accel"]
  574. self.brake = specs["brake"]
  575. self.handling = specs["handling"]
  576. self.grip = specs["grip"]
  577.  
  578. self.color = specs["color"]
  579.  
  580. # Physics
  581. self.speed = 0.0
  582. self.vx = 0.0
  583.  
  584. self.steering = 0.0
  585. self.angle = 0.0
  586.  
  587. self.crashed = False
  588.  
  589. self.braking = False
  590. self.drifting = False
  591.  
  592. def update(self, keys, weather):
  593.  
  594. if self.crashed:
  595.  
  596. self.speed *= 0.96
  597. self.vx *= 0.95
  598.  
  599. return
  600.  
  601. # ====================================================
  602. # THROTTLE / BRAKE
  603. # ====================================================
  604.  
  605. accelerating = (
  606. keys[pygame.K_w] or
  607. keys[pygame.K_UP]
  608. )
  609.  
  610. braking = (
  611. keys[pygame.K_s] or
  612. keys[pygame.K_DOWN]
  613. )
  614.  
  615. self.braking = braking
  616.  
  617. if accelerating:
  618.  
  619. self.speed += self.accel
  620.  
  621. elif braking:
  622.  
  623. self.speed -= self.brake
  624.  
  625. else:
  626.  
  627. # Natural friction
  628. self.speed -= 0.055
  629.  
  630. # ====================================================
  631. # WEATHER EFFECTS
  632. # ====================================================
  633.  
  634. if weather == "RAIN":
  635.  
  636. self.speed = min(
  637. self.speed,
  638. self.max_speed * 0.92
  639. )
  640.  
  641. elif weather == "FOG":
  642.  
  643. self.speed = min(
  644. self.speed,
  645. self.max_speed * 0.96
  646. )
  647.  
  648. self.speed = max(
  649. 0,
  650. min(
  651. self.speed,
  652. self.max_speed
  653. )
  654. )
  655.  
  656. # ====================================================
  657. # STEERING
  658. # ====================================================
  659.  
  660. steer = 0
  661.  
  662. if keys[pygame.K_a] or keys[pygame.K_LEFT]:
  663. steer -= 1
  664.  
  665. if keys[pygame.K_d] or keys[pygame.K_RIGHT]:
  666. steer += 1
  667.  
  668. # Smooth steering
  669. self.steering += (
  670. steer - self.steering
  671. ) * 0.25
  672.  
  673. # Steering gets stronger at speed
  674. speed_factor = (
  675. 0.25 +
  676. (self.speed / self.max_speed) * 0.9
  677. )
  678.  
  679. grip_modifier = self.grip
  680.  
  681. # Rain makes the car slide
  682. if weather == "RAIN":
  683. grip_modifier *= 0.70
  684.  
  685. steering_force = (
  686. self.steering *
  687. self.handling *
  688. speed_factor *
  689. grip_modifier
  690. )
  691.  
  692. self.vx += (
  693. steering_force - self.vx
  694. ) * 0.28
  695.  
  696. self.x += self.vx
  697.  
  698. # ====================================================
  699. # DRIFT PHYSICS
  700. # ====================================================
  701.  
  702. self.drifting = (
  703. abs(self.vx) > 3.2
  704. and
  705. self.speed > 9
  706. )
  707.  
  708. if self.drifting:
  709. self.vx *= 0.985
  710.  
  711. # ====================================================
  712. # BODY LEAN
  713. # ====================================================
  714.  
  715. self.angle = -self.vx * 2.4
  716.  
  717. self.angle = max(
  718. -18,
  719. min(18, self.angle)
  720. )
  721.  
  722. # ====================================================
  723. # ROAD BOUNDARIES
  724. # ====================================================
  725.  
  726. if self.x < ROAD_LEFT + 28:
  727.  
  728. self.x = ROAD_LEFT + 28
  729.  
  730. self.vx *= -0.25
  731.  
  732. if self.x > ROAD_RIGHT - 28:
  733.  
  734. self.x = ROAD_RIGHT - 28
  735.  
  736. self.vx *= -0.25
  737.  
  738. def get_rect(self):
  739.  
  740. return pygame.Rect(
  741. int(self.x - self.width / 2),
  742. int(self.y - self.height / 2),
  743. self.width,
  744. self.height
  745. )
  746.  
  747. def draw(self, surface):
  748.  
  749. # ====================================================
  750. # CAR SHADOW
  751. # ====================================================
  752.  
  753. shadow = pygame.Surface(
  754. (
  755. self.width + 18,
  756. self.height + 12
  757. ),
  758. pygame.SRCALPHA
  759. )
  760.  
  761. pygame.draw.ellipse(
  762. shadow,
  763. (0, 0, 0, 110),
  764. shadow.get_rect()
  765. )
  766.  
  767. shadow = pygame.transform.rotate(
  768. shadow,
  769. self.angle
  770. )
  771.  
  772. shadow_rect = shadow.get_rect(
  773. center=(
  774. int(self.x + 4),
  775. int(self.y + 7)
  776. )
  777. )
  778.  
  779. surface.blit(
  780. shadow,
  781. shadow_rect
  782. )
  783.  
  784. # ====================================================
  785. # CAR BODY
  786. # ====================================================
  787.  
  788. car_surf = pygame.Surface(
  789. (
  790. self.width,
  791. self.height
  792. ),
  793. pygame.SRCALPHA
  794. )
  795.  
  796. # Main body
  797. pygame.draw.rect(
  798. car_surf,
  799. self.color,
  800. (
  801. 1,
  802. 1,
  803. self.width - 2,
  804. self.height - 2
  805. ),
  806. border_radius=10
  807. )
  808.  
  809. # Lower body
  810. darker = tuple(
  811. max(0, c - 40)
  812. for c in self.color
  813. )
  814.  
  815. pygame.draw.rect(
  816. car_surf,
  817. darker,
  818. (
  819. 3,
  820. 48,
  821. self.width - 6,
  822. 25
  823. ),
  824. border_radius=7
  825. )
  826.  
  827. # ====================================================
  828. # WINDSHIELD
  829. # ====================================================
  830.  
  831. windshield = [
  832. (6, 12),
  833. (self.width - 6, 12),
  834. (self.width - 9, 34),
  835. (9, 34)
  836. ]
  837.  
  838. pygame.draw.polygon(
  839. car_surf,
  840. (17, 27, 38),
  841. windshield
  842. )
  843.  
  844. # Windshield reflection
  845. pygame.draw.line(
  846. car_surf,
  847. (70, 95, 115),
  848. (10, 15),
  849. (self.width - 10, 15),
  850. 2
  851. )
  852.  
  853. # Center divider
  854. pygame.draw.line(
  855. car_surf,
  856. (65, 70, 80),
  857. (
  858. self.width // 2,
  859. 13
  860. ),
  861. (
  862. self.width // 2,
  863. 33
  864. ),
  865. 1
  866. )
  867.  
  868. # ====================================================
  869. # HEADLIGHTS
  870. # ====================================================
  871.  
  872. pygame.draw.rect(
  873. car_surf,
  874. (255, 255, 220),
  875. (
  876. 4,
  877. 3,
  878. 11,
  879. 6
  880. ),
  881. border_radius=2
  882. )
  883.  
  884. pygame.draw.rect(
  885. car_surf,
  886. (255, 255, 220),
  887. (
  888. self.width - 15,
  889. 3,
  890. 11,
  891. 6
  892. ),
  893. border_radius=2
  894. )
  895.  
  896. # ====================================================
  897. # TAIL LIGHTS
  898. # ====================================================
  899.  
  900. pygame.draw.rect(
  901. car_surf,
  902. (255, 20, 20),
  903. (
  904. 4,
  905. self.height - 9,
  906. 11,
  907. 5
  908. )
  909. )
  910.  
  911. pygame.draw.rect(
  912. car_surf,
  913. (255, 20, 20),
  914. (
  915. self.width - 15,
  916. self.height - 9,
  917. 11,
  918. 5
  919. )
  920. )
  921.  
  922. # ====================================================
  923. # WHEELS
  924. # ====================================================
  925.  
  926. wheel_color = (15, 15, 17)
  927.  
  928. pygame.draw.rect(
  929. car_surf,
  930. wheel_color,
  931. (-3, 17, 6, 17),
  932. border_radius=3
  933. )
  934.  
  935. pygame.draw.rect(
  936. car_surf,
  937. wheel_color,
  938. (
  939. self.width - 3,
  940. 17,
  941. 6,
  942. 17
  943. ),
  944. border_radius=3
  945. )
  946.  
  947. pygame.draw.rect(
  948. car_surf,
  949. wheel_color,
  950. (
  951. -3,
  952. self.height - 36,
  953. 6,
  954. 17
  955. ),
  956. border_radius=3
  957. )
  958.  
  959. pygame.draw.rect(
  960. car_surf,
  961. wheel_color,
  962. (
  963. self.width - 3,
  964. self.height - 36,
  965. 6,
  966. 17
  967. ),
  968. border_radius=3
  969. )
  970.  
  971. # Rotate car
  972. rotated = pygame.transform.rotate(
  973. car_surf,
  974. self.angle
  975. )
  976.  
  977. rect = rotated.get_rect(
  978. center=(
  979. int(self.x),
  980. int(self.y)
  981. )
  982. )
  983.  
  984. surface.blit(
  985. rotated,
  986. rect.topleft
  987. )
  988. # ============================================================
  989. # WEATHER
  990. # ============================================================
  991.  
  992. WEATHERS = [
  993. "CLEAR",
  994. "RAIN",
  995. "FOG",
  996. "NIGHT"
  997. ]
  998.  
  999.  
  1000. def draw_weather(surface, weather):
  1001.  
  1002. overlay = pygame.Surface(
  1003. (WIDTH, HEIGHT),
  1004. pygame.SRCALPHA
  1005. )
  1006.  
  1007. if weather == "RAIN":
  1008.  
  1009. overlay.fill(
  1010. (40, 70, 100, 35)
  1011. )
  1012.  
  1013. # Rain
  1014. for _ in range(90):
  1015.  
  1016. x = random.randint(
  1017. 0,
  1018. WIDTH
  1019. )
  1020.  
  1021. y = random.randint(
  1022. 0,
  1023. HEIGHT
  1024. )
  1025.  
  1026. pygame.draw.line(
  1027. overlay,
  1028. (170, 200, 230, 100),
  1029. (
  1030. x,
  1031. y
  1032. ),
  1033. (
  1034. x - 3,
  1035. y + 14
  1036. ),
  1037. 1
  1038. )
  1039.  
  1040. elif weather == "FOG":
  1041.  
  1042. overlay.fill(
  1043. (170, 180, 185, 55)
  1044. )
  1045.  
  1046. elif weather == "NIGHT":
  1047.  
  1048. overlay.fill(
  1049. (5, 10, 30, 105)
  1050. )
  1051.  
  1052. surface.blit(
  1053. overlay,
  1054. (0, 0)
  1055. )
  1056.  
  1057.  
  1058. # ============================================================
  1059. # ROAD
  1060. # ============================================================
  1061.  
  1062. def draw_road(surface, road_offset, weather):
  1063.  
  1064. # Grass
  1065. surface.fill(
  1066. COLOR_GRASS
  1067. )
  1068.  
  1069. # Road
  1070. pygame.draw.rect(
  1071. surface,
  1072. COLOR_ROAD,
  1073. (
  1074. ROAD_LEFT,
  1075. 0,
  1076. ROAD_WIDTH,
  1077. HEIGHT
  1078. )
  1079. )
  1080.  
  1081. # Road shadows
  1082. pygame.draw.rect(
  1083. surface,
  1084. (22, 23, 27),
  1085. (
  1086. ROAD_LEFT + 8,
  1087. 0,
  1088. 8,
  1089. HEIGHT
  1090. )
  1091. )
  1092.  
  1093. pygame.draw.rect(
  1094. surface,
  1095. (22, 23, 27),
  1096. (
  1097. ROAD_RIGHT - 16,
  1098. 0,
  1099. 8,
  1100. HEIGHT
  1101. )
  1102. )
  1103.  
  1104. # ========================================================
  1105. # LANE MARKINGS
  1106. # ========================================================
  1107.  
  1108. for i in range(1, NUM_LANES):
  1109.  
  1110. lx = (
  1111. ROAD_LEFT +
  1112. i * LANE_WIDTH
  1113. )
  1114.  
  1115. for y in range(
  1116. -100,
  1117. HEIGHT + 100,
  1118. 90
  1119. ):
  1120.  
  1121. pygame.draw.line(
  1122. surface,
  1123. COLOR_LINE_WHITE,
  1124. (
  1125. lx,
  1126. y + int(road_offset)
  1127. ),
  1128. (
  1129. lx,
  1130. y + int(road_offset) + 42
  1131. ),
  1132. 3
  1133. )
  1134.  
  1135. # Yellow road edges
  1136. pygame.draw.line(
  1137. surface,
  1138. COLOR_LINE_YELLOW,
  1139. (
  1140. ROAD_LEFT,
  1141. 0
  1142. ),
  1143. (
  1144. ROAD_LEFT,
  1145. HEIGHT
  1146. ),
  1147. 5
  1148. )
  1149.  
  1150. pygame.draw.line(
  1151. surface,
  1152. COLOR_LINE_YELLOW,
  1153. (
  1154. ROAD_RIGHT,
  1155. 0
  1156. ),
  1157. (
  1158. ROAD_RIGHT,
  1159. HEIGHT
  1160. ),
  1161. 5
  1162. )
  1163.  
  1164. # Wet road effect
  1165. if weather == "RAIN":
  1166.  
  1167. pygame.draw.rect(
  1168. surface,
  1169. (45, 48, 55),
  1170. (
  1171. ROAD_LEFT + 10,
  1172. 0,
  1173. ROAD_WIDTH - 20,
  1174. HEIGHT
  1175. ),
  1176. 2
  1177. )
  1178.  
  1179.  
  1180. # ============================================================
  1181. # VEHICLE SELECTION MENU
  1182. # ============================================================
  1183.  
  1184. def vehicle_menu():
  1185.  
  1186. while True:
  1187.  
  1188. screen.fill(
  1189. COLOR_BG
  1190. )
  1191.  
  1192. # ====================================================
  1193. # TITLE
  1194. # ====================================================
  1195.  
  1196. title = FONT_TITLE.render(
  1197. "NO HESI",
  1198. True,
  1199. COLOR_CYAN
  1200. )
  1201.  
  1202. subtitle = FONT_MED.render(
  1203. "HIGHWAY TRAFFIC WEAVER",
  1204. True,
  1205. COLOR_TEXT
  1206. )
  1207.  
  1208. screen.blit(
  1209. title,
  1210. (
  1211. WIDTH // 2 -
  1212. title.get_width() // 2,
  1213. 45
  1214. )
  1215. )
  1216.  
  1217. screen.blit(
  1218. subtitle,
  1219. (
  1220. WIDTH // 2 -
  1221. subtitle.get_width() // 2,
  1222. 100
  1223. )
  1224. )
  1225.  
  1226. # ====================================================
  1227. # CARS
  1228. # ====================================================
  1229.  
  1230. y = 165
  1231.  
  1232. for key, car in CARS.items():
  1233.  
  1234. box = pygame.Rect(
  1235. WIDTH // 2 - 330,
  1236. y,
  1237. 660,
  1238. 120
  1239. )
  1240.  
  1241. pygame.draw.rect(
  1242. screen,
  1243. (29, 33, 41),
  1244. box,
  1245. border_radius=12
  1246. )
  1247.  
  1248. # Color strip
  1249. pygame.draw.rect(
  1250. screen,
  1251. car["color"],
  1252. (
  1253. box.left + 15,
  1254. box.top + 15,
  1255. 10,
  1256. box.height - 30
  1257. ),
  1258. border_radius=4
  1259. )
  1260.  
  1261. name = FONT_MED.render(
  1262. f"[{key}] {car['name']}",
  1263. True,
  1264. COLOR_TEXT
  1265. )
  1266.  
  1267. desc = FONT_SMALL.render(
  1268. car["desc"],
  1269. True,
  1270. (170, 175, 185)
  1271. )
  1272.  
  1273. stats = FONT_HUD.render(
  1274. f"TOP SPEED "
  1275. f"{int(car['max_speed'] * 18)} KM/H "
  1276. f"HANDLING "
  1277. f"{car['handling']:.1f}",
  1278. True,
  1279. COLOR_GOLD
  1280. )
  1281.  
  1282. screen.blit(
  1283. name,
  1284. (
  1285. box.left + 40,
  1286. box.top + 12
  1287. )
  1288. )
  1289.  
  1290. screen.blit(
  1291. desc,
  1292. (
  1293. box.left + 40,
  1294. box.top + 48
  1295. )
  1296. )
  1297.  
  1298. screen.blit(
  1299. stats,
  1300. (
  1301. box.left + 40,
  1302. box.top + 78
  1303. )
  1304. )
  1305.  
  1306. y += 140
  1307.  
  1308. # ====================================================
  1309. # PROMPT
  1310. # ====================================================
  1311.  
  1312. prompt = FONT_MED.render(
  1313. "Press 1, 2, or 3 to start",
  1314. True,
  1315. COLOR_GOLD
  1316. )
  1317.  
  1318. screen.blit(
  1319. prompt,
  1320. (
  1321. WIDTH // 2 -
  1322. prompt.get_width() // 2,
  1323. HEIGHT - 55
  1324. )
  1325. )
  1326.  
  1327. pygame.display.flip()
  1328.  
  1329. # ====================================================
  1330. # MENU EVENTS
  1331. # ====================================================
  1332.  
  1333. for event in pygame.event.get():
  1334.  
  1335. if event.type == pygame.QUIT:
  1336.  
  1337. pygame.quit()
  1338. sys.exit()
  1339.  
  1340. if event.type == pygame.KEYDOWN:
  1341.  
  1342. if event.unicode in CARS:
  1343.  
  1344. return event.unicode
  1345. # ============================================================
  1346. # MAIN GAME
  1347. # ============================================================
  1348.  
  1349. def game():
  1350.  
  1351. global particles
  1352.  
  1353. # Reset particles for a new run
  1354. particles = []
  1355.  
  1356. # ========================================================
  1357. # SELECT CAR
  1358. # ========================================================
  1359.  
  1360. selected_car = vehicle_menu()
  1361.  
  1362. player = PlayerCar(
  1363. CARS[selected_car]
  1364. )
  1365.  
  1366. # ========================================================
  1367. # GAME VARIABLES
  1368. # ========================================================
  1369.  
  1370. traffic = []
  1371.  
  1372. police = None
  1373.  
  1374. score = 0
  1375. combo = 1
  1376.  
  1377. close_calls = 0
  1378.  
  1379. near_miss_timer = 0
  1380. police_message_timer = 0
  1381.  
  1382. spawn_timer = 0
  1383.  
  1384. weather = "CLEAR"
  1385. weather_index = 0
  1386. weather_change_counter = 0
  1387.  
  1388. road_offset = 0
  1389.  
  1390. running = True
  1391.  
  1392. # ========================================================
  1393. # GAME LOOP
  1394. # ========================================================
  1395.  
  1396. while running:
  1397.  
  1398. clock.tick(60)
  1399.  
  1400. # ====================================================
  1401. # EVENTS
  1402. # ====================================================
  1403.  
  1404. for event in pygame.event.get():
  1405.  
  1406. if event.type == pygame.QUIT:
  1407.  
  1408. return
  1409.  
  1410. if event.type == pygame.KEYDOWN:
  1411.  
  1412. if event.key == pygame.K_ESCAPE:
  1413.  
  1414. return
  1415.  
  1416. if event.key == pygame.K_r:
  1417.  
  1418. return game()
  1419.  
  1420. # ====================================================
  1421. # KEYBOARD
  1422. # ====================================================
  1423.  
  1424. keys = pygame.key.get_pressed()
  1425.  
  1426. # ====================================================
  1427. # PLAYER PHYSICS
  1428. # ====================================================
  1429.  
  1430. player.update(
  1431. keys,
  1432. weather
  1433. )
  1434.  
  1435. # ====================================================
  1436. # WEATHER
  1437. # ====================================================
  1438.  
  1439. weather_change_counter += 1
  1440.  
  1441. # Every combo run eventually changes weather
  1442. if (
  1443. combo > 1
  1444. and
  1445. weather_change_counter > 600
  1446. ):
  1447.  
  1448. weather_change_counter = 0
  1449.  
  1450. weather_index = (
  1451. weather_index + 1
  1452. ) % len(WEATHERS)
  1453.  
  1454. weather = WEATHERS[
  1455. weather_index
  1456. ]
  1457.  
  1458. # ====================================================
  1459. # ROAD SCROLL
  1460. # ====================================================
  1461.  
  1462. road_offset = (
  1463. road_offset +
  1464. player.speed * 2.7
  1465. ) % 90
  1466.  
  1467. # ====================================================
  1468. # TRAFFIC SPAWNING
  1469. # ====================================================
  1470.  
  1471. if not player.crashed:
  1472.  
  1473. spawn_timer += 1
  1474.  
  1475. spawn_delay = max(
  1476. 18,
  1477. 55 - int(player.speed * 1.5)
  1478. )
  1479.  
  1480. if spawn_timer >= spawn_delay:
  1481.  
  1482. spawn_timer = 0
  1483.  
  1484. lane = random.randint(
  1485. 0,
  1486. NUM_LANES - 1
  1487. )
  1488.  
  1489. # Don't stack cars
  1490. lane_busy = any(
  1491. car.lane == lane
  1492. and
  1493. car.y < 160
  1494. for car in traffic
  1495. )
  1496.  
  1497. if not lane_busy:
  1498.  
  1499. # Traffic gets faster as combo rises
  1500. base_min = (
  1501. 4.0 +
  1502. combo * 0.15
  1503. )
  1504.  
  1505. base_max = (
  1506. 8.0 +
  1507. combo * 0.25
  1508. )
  1509.  
  1510. npc_speed = random.uniform(
  1511. base_min,
  1512. min(base_max, 13)
  1513. )
  1514.  
  1515. traffic.append(
  1516. TrafficCar(
  1517. lane,
  1518. npc_speed
  1519. )
  1520. )
  1521.  
  1522. # ====================================================
  1523. # TRAFFIC UPDATE
  1524. # ====================================================
  1525.  
  1526. player_rect = player.get_rect()
  1527.  
  1528. for car in traffic[:]:
  1529.  
  1530. car.update(
  1531. player.speed
  1532. )
  1533.  
  1534. npc_rect = car.get_rect()
  1535.  
  1536. # =================================================
  1537. # COLLISION
  1538. # =================================================
  1539.  
  1540. if not player.crashed:
  1541.  
  1542. collision_rect = player_rect.inflate(
  1543. -7,
  1544. -10
  1545. )
  1546.  
  1547. npc_collision = npc_rect.inflate(
  1548. -5,
  1549. -8
  1550. )
  1551.  
  1552. if collision_rect.colliderect(
  1553. npc_collision
  1554. ):
  1555.  
  1556. player.crashed = True
  1557.  
  1558. combo = 1
  1559.  
  1560. # Crash smoke/explosion
  1561. for _ in range(35):
  1562.  
  1563. particles.append(
  1564. Particle(
  1565. player.x +
  1566. random.uniform(-15, 15),
  1567.  
  1568. player.y +
  1569. random.uniform(-25, 25),
  1570.  
  1571. random.choice([
  1572. (100, 100, 100),
  1573. (180, 180, 180),
  1574. (255, 130, 20)
  1575. ]),
  1576.  
  1577. random.uniform(3, 8),
  1578.  
  1579. (
  1580. random.uniform(-3, 3),
  1581. random.uniform(-3, 3)
  1582. ),
  1583.  
  1584. random.randint(
  1585. 20,
  1586. 50
  1587. )
  1588. )
  1589. )
  1590.  
  1591. # =================================================
  1592. # CLOSE CALL
  1593. # =================================================
  1594.  
  1595. if (
  1596. not car.near_missed
  1597. and
  1598. not player.crashed
  1599. and
  1600. player.speed > 8
  1601. ):
  1602.  
  1603. dx = abs(
  1604. player.x -
  1605. car.x
  1606. )
  1607.  
  1608. dy = abs(
  1609. player.y -
  1610. car.y
  1611. )
  1612.  
  1613. # Tight close-call area
  1614. if (
  1615. dx < 52
  1616. and
  1617. dy < 68
  1618. ):
  1619.  
  1620. car.near_missed = True
  1621.  
  1622. close_calls += 1
  1623.  
  1624. combo += 1
  1625.  
  1626. score += (
  1627. 500 *
  1628. combo
  1629. )
  1630.  
  1631. near_miss_timer = 55
  1632.  
  1633. # Smoke
  1634. create_smoke(
  1635. player.x,
  1636. player.y + 25,
  1637. 5
  1638. )
  1639.  
  1640. # =================================================
  1641. # 4 CLOSE CALLS = POLICE
  1642. # =================================================
  1643.  
  1644. if (
  1645. close_calls >= 4
  1646. and
  1647. police is None
  1648. ):
  1649.  
  1650. police = PoliceCar()
  1651.  
  1652. police_message_timer = 180
  1653.  
  1654. # =================================================
  1655. # REMOVE OFFSCREEN CARS
  1656. # =================================================
  1657.  
  1658. if (
  1659. car.y > HEIGHT + 160
  1660. or
  1661. car.y < -350
  1662. ):
  1663.  
  1664. traffic.remove(car)
  1665.  
  1666. # ========================================================
  1667. # POLICE PURSUIT
  1668. # ========================================================
  1669.  
  1670. if (
  1671. police is not None
  1672. and
  1673. not player.crashed
  1674. ):
  1675.  
  1676. police.target_speed = (
  1677. player.speed + 5
  1678. )
  1679.  
  1680. police.update(
  1681. player
  1682. )
  1683.  
  1684. police_rect = police.get_rect()
  1685.  
  1686. # Police catches player
  1687. if player_rect.colliderect(
  1688. police_rect.inflate(
  1689. -8,
  1690. -10
  1691. )
  1692. ):
  1693.  
  1694. player.crashed = True
  1695.  
  1696. combo = 1
  1697.  
  1698. for _ in range(25):
  1699.  
  1700. create_smoke(
  1701. player.x,
  1702. player.y,
  1703. 1,
  1704. dark=True
  1705. )
  1706.  
  1707. # Don't let police disappear forever
  1708. if police.y < -200:
  1709.  
  1710. police.y = -200
  1711.  
  1712. # ========================================================
  1713. # SCORE
  1714. # ========================================================
  1715.  
  1716. if (
  1717. not player.crashed
  1718. and
  1719. player.speed > 2
  1720. ):
  1721.  
  1722. score += int(
  1723. player.speed *
  1724. combo *
  1725. 0.12
  1726. )
  1727.  
  1728. # ========================================================
  1729. # TIRE SMOKE
  1730. # ========================================================
  1731.  
  1732. if not player.crashed:
  1733.  
  1734. # Hard braking
  1735. if (
  1736. player.braking
  1737. and
  1738. player.speed > 8
  1739. ):
  1740.  
  1741. create_smoke(
  1742. player.x - 13,
  1743. player.y + 32,
  1744. 1
  1745. )
  1746.  
  1747. create_smoke(
  1748. player.x + 13,
  1749. player.y + 32,
  1750. 1
  1751. )
  1752.  
  1753. # Drifting
  1754. elif player.drifting:
  1755.  
  1756. create_smoke(
  1757. player.x - 14,
  1758. player.y + 32,
  1759. 1
  1760. )
  1761.  
  1762. create_smoke(
  1763. player.x + 14,
  1764. player.y + 32,
  1765. 1
  1766. )
  1767.  
  1768. # ========================================================
  1769. # UPDATE PARTICLES
  1770. # ========================================================
  1771.  
  1772. for particle in particles[:]:
  1773.  
  1774. particle.update()
  1775.  
  1776. if particle.life <= 0:
  1777.  
  1778. particles.remove(
  1779. particle
  1780. )
  1781.  
  1782. # ========================================================
  1783. # DRAW ROAD
  1784. # ========================================================
  1785.  
  1786. draw_road(
  1787. screen,
  1788. road_offset,
  1789. weather
  1790. )
  1791.  
  1792. # ========================================================
  1793. # DRAW TRAFFIC
  1794. # ========================================================
  1795.  
  1796. for car in traffic:
  1797.  
  1798. car.draw(
  1799. screen
  1800. )
  1801.  
  1802. # ========================================================
  1803. # DRAW POLICE
  1804. # ========================================================
  1805.  
  1806. if police is not None:
  1807.  
  1808. police.draw(
  1809. screen
  1810. )
  1811.  
  1812. # ========================================================
  1813. # DRAW PLAYER
  1814. # ========================================================
  1815.  
  1816. player.draw(
  1817. screen
  1818. )
  1819.  
  1820. # ========================================================
  1821. # DRAW PARTICLES
  1822. # ========================================================
  1823.  
  1824. for particle in particles:
  1825.  
  1826. particle.draw(
  1827. screen
  1828. )
  1829.  
  1830. # ========================================================
  1831. # WEATHER
  1832. # ========================================================
  1833.  
  1834. draw_weather(
  1835. screen,
  1836. weather
  1837. )
  1838.  
  1839. # ========================================================
  1840. # HUD
  1841. # ========================================================
  1842.  
  1843. speed_kmh = int(
  1844. player.speed * 18
  1845. )
  1846.  
  1847. screen.blit(
  1848. FONT_HUD.render(
  1849. f"SPEED {speed_kmh:03d} KM/H",
  1850. True,
  1851. COLOR_TEXT
  1852. ),
  1853. (20, 20)
  1854. )
  1855.  
  1856. screen.blit(
  1857. FONT_HUD.render(
  1858. f"SCORE {score:,}",
  1859. True,
  1860. COLOR_GOLD
  1861. ),
  1862. (20, 48)
  1863. )
  1864.  
  1865. screen.blit(
  1866. FONT_HUD.render(
  1867. f"COMBO x{combo}",
  1868. True,
  1869. COLOR_CYAN
  1870. if combo > 1
  1871. else COLOR_TEXT
  1872. ),
  1873. (20, 76)
  1874. )
  1875.  
  1876. screen.blit(
  1877. FONT_HUD.render(
  1878. f"CLOSE CALLS {close_calls}/4",
  1879. True,
  1880. COLOR_ORANGE
  1881. if close_calls >= 3
  1882. else COLOR_TEXT
  1883. ),
  1884. (20, 104)
  1885. )
  1886.  
  1887. screen.blit(
  1888. FONT_HUD.render(
  1889. f"WEATHER {weather}",
  1890. True,
  1891. COLOR_TEXT
  1892. ),
  1893. (20, 132)
  1894. )
  1895.  
  1896. # ========================================================
  1897. # POLICE WARNING
  1898. # ========================================================
  1899.  
  1900. if police_message_timer > 0:
  1901.  
  1902. police_message_timer -= 1
  1903.  
  1904. warning = FONT_BIG.render(
  1905. "POLICE PURSUIT!",
  1906. True,
  1907. COLOR_RED
  1908. )
  1909.  
  1910. screen.blit(
  1911. warning,
  1912. (
  1913. WIDTH // 2 -
  1914. warning.get_width() // 2,
  1915. 130
  1916. )
  1917. )
  1918.  
  1919. warning2 = FONT_MED.render(
  1920. "HIGH SPEED UNIT DEPLOYED",
  1921. True,
  1922. COLOR_TEXT
  1923. )
  1924.  
  1925. screen.blit(
  1926. warning2,
  1927. (
  1928. WIDTH // 2 -
  1929. warning2.get_width() // 2,
  1930. 175
  1931. )
  1932. )
  1933.  
  1934. # ========================================================
  1935. # CLOSE CALL MESSAGE
  1936. # ========================================================
  1937.  
  1938. if near_miss_timer > 0:
  1939.  
  1940. near_miss_timer -= 1
  1941.  
  1942. text = FONT_BIG.render(
  1943. "CLOSE CALL!",
  1944. True,
  1945. COLOR_GOLD
  1946. )
  1947.  
  1948. screen.blit(
  1949. text,
  1950. (
  1951. WIDTH // 2 -
  1952. text.get_width() // 2,
  1953. 220
  1954. )
  1955. )
  1956.  
  1957. # ========================================================
  1958. # CRASH SCREEN
  1959. # ========================================================
  1960.  
  1961. if player.crashed:
  1962.  
  1963. dark = pygame.Surface(
  1964. (WIDTH, HEIGHT),
  1965. pygame.SRCALPHA
  1966. )
  1967.  
  1968. dark.fill(
  1969. (0, 0, 0, 120)
  1970. )
  1971.  
  1972. screen.blit(
  1973. dark,
  1974. (0, 0)
  1975. )
  1976.  
  1977. crash = FONT_TITLE.render(
  1978. "CRASHED!",
  1979. True,
  1980. COLOR_RED
  1981. )
  1982.  
  1983. screen.blit(
  1984. crash,
  1985. (
  1986. WIDTH // 2 -
  1987. crash.get_width() // 2,
  1988. HEIGHT // 2 - 70
  1989. )
  1990. )
  1991.  
  1992. score_text = FONT_MED.render(
  1993. f"FINAL SCORE: {score:,}",
  1994. True,
  1995. COLOR_GOLD
  1996. )
  1997.  
  1998. screen.blit(
  1999. score_text,
  2000. (
  2001. WIDTH // 2 -
  2002. score_text.get_width() // 2,
  2003. HEIGHT // 2
  2004. )
  2005. )
  2006.  
  2007. restart = FONT_MED.render(
  2008. "Press R to restart",
  2009. True,
  2010. COLOR_TEXT
  2011. )
  2012.  
  2013. screen.blit(
  2014. restart,
  2015. (
  2016. WIDTH // 2 -
  2017. restart.get_width() // 2,
  2018. HEIGHT // 2 + 45
  2019. )
  2020. )
  2021.  
  2022. # ========================================================
  2023. # DISPLAY
  2024. # ========================================================
  2025.  
  2026. pygame.display.flip()
  2027.  
  2028.  
  2029. # ============================================================
  2030. # PROGRAM START
  2031. # ============================================================
  2032.  
  2033. def main():
  2034.  
  2035. try:
  2036.  
  2037. game()
  2038.  
  2039. except Exception as error:
  2040.  
  2041. pygame.quit()
  2042.  
  2043. print()
  2044. print("=" * 60)
  2045. print("GAME CRASH DETECTED")
  2046. print("=" * 60)
  2047. print()
  2048. print(error)
  2049. print()
  2050. print("=" * 60)
  2051.  
  2052. raise
  2053.  
  2054.  
  2055. # ============================================================
  2056. # START
  2057. # ============================================================
  2058.  
  2059. if __name__ == "__main__":
  2060. main()
Advertisement
Add Comment
Please, Sign In to add comment