Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import pygame
- import math
- import random
- import sys
- # ============================================================
- # NO HESI - HIGHWAY TRAFFIC WEAVER
- # SINGLE FILE - PART 1/4
- # ============================================================
- pygame.init()
- pygame.font.init()
- WIDTH, HEIGHT = 1000, 800
- screen = pygame.display.set_mode((WIDTH, HEIGHT))
- pygame.display.set_caption("NO HESI - Highway Traffic Weaver")
- clock = pygame.time.Clock()
- # ============================================================
- # FONTS
- # ============================================================
- FONT_TITLE = pygame.font.SysFont("arial", 46, bold=True)
- FONT_BIG = pygame.font.SysFont("arial", 34, bold=True)
- FONT_MED = pygame.font.SysFont("arial", 22, bold=True)
- FONT_HUD = pygame.font.SysFont("consolas", 18, bold=True)
- FONT_SMALL = pygame.font.SysFont("consolas", 14)
- # ============================================================
- # COLORS
- # ============================================================
- COLOR_BG = (10, 13, 17)
- COLOR_ROAD = (38, 40, 45)
- COLOR_GRASS = (18, 45, 23)
- COLOR_LINE_YELLOW = (245, 210, 50)
- COLOR_LINE_WHITE = (220, 220, 225)
- COLOR_TEXT = (240, 240, 240)
- COLOR_GOLD = (255, 215, 0)
- COLOR_CYAN = (0, 230, 255)
- COLOR_RED = (255, 60, 60)
- COLOR_ORANGE = (255, 130, 30)
- COLOR_GREEN = (60, 255, 100)
- # ============================================================
- # HIGHWAY
- # ============================================================
- ROAD_LEFT = 170
- ROAD_RIGHT = 830
- ROAD_WIDTH = ROAD_RIGHT - ROAD_LEFT
- NUM_LANES = 5
- LANE_WIDTH = ROAD_WIDTH // NUM_LANES
- # ============================================================
- # PLAYER CARS
- # ============================================================
- CARS = {
- "1": {
- "name": "M4 Competition",
- "max_speed": 22.0,
- "accel": 0.34,
- "brake": 0.55,
- "handling": 6.8,
- "grip": 0.96,
- "color": (20, 150, 230),
- "desc": "Agile, fast and extremely responsive."
- },
- "2": {
- "name": "RS7 Sportback",
- "max_speed": 25.0,
- "accel": 0.38,
- "brake": 0.58,
- "handling": 5.7,
- "grip": 0.92,
- "color": (210, 30, 35),
- "desc": "Heavy highway missile with huge top speed."
- },
- "3": {
- "name": "GT-R Nismo",
- "max_speed": 23.5,
- "accel": 0.36,
- "brake": 0.62,
- "handling": 6.2,
- "grip": 0.98,
- "color": (225, 225, 230),
- "desc": "Balanced power, grip and acceleration."
- }
- }
- # ============================================================
- # PARTICLE SYSTEM
- # ============================================================
- class Particle:
- def __init__(self, x, y, color, size, velocity, life):
- self.x = x
- self.y = y
- self.color = color
- self.size = size
- self.vx, self.vy = velocity
- self.life = life
- self.max_life = life
- def update(self):
- self.x += self.vx
- self.y += self.vy
- self.vx *= 0.96
- self.vy *= 0.96
- self.size *= 0.97
- self.life -= 1
- def draw(self, surface):
- if self.life <= 0:
- return
- alpha = max(
- 0,
- min(
- 255,
- int(255 * (self.life / self.max_life))
- )
- )
- particle_size = max(
- 2,
- int(self.size * 2)
- )
- particle_surface = pygame.Surface(
- (particle_size, particle_size),
- pygame.SRCALPHA
- )
- pygame.draw.circle(
- particle_surface,
- (*self.color, alpha),
- (
- particle_size // 2,
- particle_size // 2
- ),
- max(1, int(self.size))
- )
- surface.blit(
- particle_surface,
- (
- int(self.x - particle_size / 2),
- int(self.y - particle_size / 2)
- )
- )
- particles = []
- def create_smoke(x, y, amount=2, dark=False):
- for _ in range(amount):
- if dark:
- color = (75, 75, 75)
- else:
- color = (165, 165, 165)
- particles.append(
- Particle(
- x + random.uniform(-7, 7),
- y + random.uniform(-5, 5),
- color,
- random.uniform(3, 7),
- (
- random.uniform(-0.8, 0.8),
- random.uniform(0.5, 2.0)
- ),
- random.randint(18, 35)
- )
- )
- # ============================================================
- # TRAFFIC CAR
- # ============================================================
- class TrafficCar:
- def __init__(self, lane, speed):
- self.lane = lane
- self.x = (
- ROAD_LEFT +
- lane * LANE_WIDTH +
- LANE_WIDTH // 2
- )
- self.y = -120
- self.width = random.randint(34, 42)
- self.height = random.randint(62, 76)
- self.speed = speed
- self.color = random.choice([
- (130, 135, 145),
- (190, 45, 45),
- (45, 150, 75),
- (205, 190, 45),
- (110, 70, 170),
- (210, 120, 35),
- (60, 100, 180),
- (190, 190, 195)
- ])
- self.near_missed = False
- self.angle = 0
- def update(self, player_speed):
- # Relative highway movement
- self.y += player_speed - self.speed
- # Tiny realistic movement
- self.x += math.sin(self.y * 0.02) * 0.05
- def get_rect(self):
- return pygame.Rect(
- int(self.x - self.width / 2),
- int(self.y - self.height / 2),
- self.width,
- self.height
- )
- def draw(self, surface):
- rect = self.get_rect()
- # Shadow
- shadow = pygame.Rect(
- rect.left - 3,
- rect.bottom - 4,
- rect.width + 6,
- 8
- )
- pygame.draw.ellipse(
- surface,
- (15, 15, 15),
- shadow
- )
- # Main body
- pygame.draw.rect(
- surface,
- self.color,
- rect,
- border_radius=9
- )
- # Dark lower bumper
- darker_color = tuple(
- max(0, c - 35)
- for c in self.color
- )
- pygame.draw.rect(
- surface,
- darker_color,
- (
- rect.left + 3,
- rect.bottom - 12,
- rect.width - 6,
- 10
- ),
- border_radius=4
- )
- # Windows
- window_rect = pygame.Rect(
- rect.left + 5,
- rect.top + 13,
- rect.width - 10,
- 27
- )
- pygame.draw.rect(
- surface,
- (18, 25, 35),
- window_rect,
- border_radius=5
- )
- # Window divider
- pygame.draw.line(
- surface,
- (70, 75, 85),
- (
- rect.centerx,
- window_rect.top
- ),
- (
- rect.centerx,
- window_rect.bottom
- ),
- 2
- )
- # Headlights
- pygame.draw.rect(
- surface,
- (255, 255, 210),
- (
- rect.left + 4,
- rect.top + 3,
- 9,
- 5
- ),
- border_radius=2
- )
- pygame.draw.rect(
- surface,
- (255, 255, 210),
- (
- rect.right - 13,
- rect.top + 3,
- 9,
- 5
- ),
- border_radius=2
- )
- # Tail lights
- pygame.draw.rect(
- surface,
- (255, 20, 20),
- (
- rect.left + 4,
- rect.bottom - 8,
- 9,
- 5
- )
- )
- pygame.draw.rect(
- surface,
- (255, 20, 20),
- (
- rect.right - 13,
- rect.bottom - 8,
- 9,
- 5
- )
- )
- # ============================================================
- # POLICE CAR
- # ============================================================
- class PoliceCar:
- def __init__(self):
- self.width = 40
- self.height = 76
- self.x = random.choice([
- ROAD_LEFT + LANE_WIDTH // 2,
- ROAD_RIGHT - LANE_WIDTH // 2
- ])
- self.y = HEIGHT + 180
- self.speed = 16.0
- self.target_speed = 18.0
- self.active = True
- self.siren_phase = 0
- def update(self, player):
- # Police accelerates
- if self.speed < self.target_speed:
- self.speed += 0.08
- # Move relative to player
- self.y += player.speed - self.speed
- # Chase player's horizontal position
- dx = player.x - self.x
- self.x += max(
- -3.5,
- min(3.5, dx * 0.025)
- )
- # Keep police on highway
- self.x = max(
- ROAD_LEFT + 25,
- min(ROAD_RIGHT - 25, self.x)
- )
- self.siren_phase += 0.25
- def get_rect(self):
- return pygame.Rect(
- int(self.x - self.width / 2),
- int(self.y - self.height / 2),
- self.width,
- self.height
- )
- def draw(self, surface):
- rect = self.get_rect()
- # Shadow
- pygame.draw.ellipse(
- surface,
- (10, 10, 10),
- (
- rect.left - 4,
- rect.bottom - 5,
- rect.width + 8,
- 10
- )
- )
- # White body
- pygame.draw.rect(
- surface,
- (235, 235, 240),
- rect,
- border_radius=8
- )
- # Black police section
- pygame.draw.rect(
- surface,
- (20, 20, 25),
- (
- rect.left + 2,
- rect.top + 30,
- rect.width - 4,
- 22
- )
- )
- # Windows
- pygame.draw.rect(
- surface,
- (15, 25, 35),
- (
- rect.left + 5,
- rect.top + 12,
- rect.width - 10,
- 22
- ),
- border_radius=4
- )
- # Siren
- red_on = math.sin(self.siren_phase) > 0
- if red_on:
- pygame.draw.rect(
- surface,
- (255, 30, 30),
- (
- rect.centerx - 12,
- rect.top + 3,
- 12,
- 6
- )
- )
- pygame.draw.rect(
- surface,
- (40, 80, 255),
- (
- rect.centerx,
- rect.top + 3,
- 12,
- 6
- )
- )
- else:
- pygame.draw.rect(
- surface,
- (40, 80, 255),
- (
- rect.centerx - 12,
- rect.top + 3,
- 12,
- 6
- )
- )
- pygame.draw.rect(
- surface,
- (255, 30, 30),
- (
- rect.centerx,
- rect.top + 3,
- 12,
- 6
- )
- )
- # Tail lights
- pygame.draw.rect(
- surface,
- (255, 30, 30),
- (
- rect.left + 4,
- rect.bottom - 8,
- 9,
- 5
- )
- )
- pygame.draw.rect(
- surface,
- (255, 30, 30),
- (
- rect.right - 13,
- rect.bottom - 8,
- 9,
- 5
- )
- )
- # ============================================================
- # PLAYER CAR
- # ============================================================
- class PlayerCar:
- def __init__(self, specs):
- self.x = WIDTH // 2
- self.y = HEIGHT - 160
- self.width = 42
- self.height = 78
- self.name = specs["name"]
- self.max_speed = specs["max_speed"]
- self.accel = specs["accel"]
- self.brake = specs["brake"]
- self.handling = specs["handling"]
- self.grip = specs["grip"]
- self.color = specs["color"]
- # Physics
- self.speed = 0.0
- self.vx = 0.0
- self.steering = 0.0
- self.angle = 0.0
- self.crashed = False
- self.braking = False
- self.drifting = False
- def update(self, keys, weather):
- if self.crashed:
- self.speed *= 0.96
- self.vx *= 0.95
- return
- # ====================================================
- # THROTTLE / BRAKE
- # ====================================================
- accelerating = (
- keys[pygame.K_w] or
- keys[pygame.K_UP]
- )
- braking = (
- keys[pygame.K_s] or
- keys[pygame.K_DOWN]
- )
- self.braking = braking
- if accelerating:
- self.speed += self.accel
- elif braking:
- self.speed -= self.brake
- else:
- # Natural friction
- self.speed -= 0.055
- # ====================================================
- # WEATHER EFFECTS
- # ====================================================
- if weather == "RAIN":
- self.speed = min(
- self.speed,
- self.max_speed * 0.92
- )
- elif weather == "FOG":
- self.speed = min(
- self.speed,
- self.max_speed * 0.96
- )
- self.speed = max(
- 0,
- min(
- self.speed,
- self.max_speed
- )
- )
- # ====================================================
- # STEERING
- # ====================================================
- steer = 0
- if keys[pygame.K_a] or keys[pygame.K_LEFT]:
- steer -= 1
- if keys[pygame.K_d] or keys[pygame.K_RIGHT]:
- steer += 1
- # Smooth steering
- self.steering += (
- steer - self.steering
- ) * 0.25
- # Steering gets stronger at speed
- speed_factor = (
- 0.25 +
- (self.speed / self.max_speed) * 0.9
- )
- grip_modifier = self.grip
- # Rain makes the car slide
- if weather == "RAIN":
- grip_modifier *= 0.70
- steering_force = (
- self.steering *
- self.handling *
- speed_factor *
- grip_modifier
- )
- self.vx += (
- steering_force - self.vx
- ) * 0.28
- self.x += self.vx
- # ====================================================
- # DRIFT PHYSICS
- # ====================================================
- self.drifting = (
- abs(self.vx) > 3.2
- and
- self.speed > 9
- )
- if self.drifting:
- self.vx *= 0.985
- # ====================================================
- # BODY LEAN
- # ====================================================
- self.angle = -self.vx * 2.4
- self.angle = max(
- -18,
- min(18, self.angle)
- )
- # ====================================================
- # ROAD BOUNDARIES
- # ====================================================
- if self.x < ROAD_LEFT + 28:
- self.x = ROAD_LEFT + 28
- self.vx *= -0.25
- if self.x > ROAD_RIGHT - 28:
- self.x = ROAD_RIGHT - 28
- self.vx *= -0.25
- def get_rect(self):
- return pygame.Rect(
- int(self.x - self.width / 2),
- int(self.y - self.height / 2),
- self.width,
- self.height
- )
- def draw(self, surface):
- # ====================================================
- # CAR SHADOW
- # ====================================================
- shadow = pygame.Surface(
- (
- self.width + 18,
- self.height + 12
- ),
- pygame.SRCALPHA
- )
- pygame.draw.ellipse(
- shadow,
- (0, 0, 0, 110),
- shadow.get_rect()
- )
- shadow = pygame.transform.rotate(
- shadow,
- self.angle
- )
- shadow_rect = shadow.get_rect(
- center=(
- int(self.x + 4),
- int(self.y + 7)
- )
- )
- surface.blit(
- shadow,
- shadow_rect
- )
- # ====================================================
- # CAR BODY
- # ====================================================
- car_surf = pygame.Surface(
- (
- self.width,
- self.height
- ),
- pygame.SRCALPHA
- )
- # Main body
- pygame.draw.rect(
- car_surf,
- self.color,
- (
- 1,
- 1,
- self.width - 2,
- self.height - 2
- ),
- border_radius=10
- )
- # Lower body
- darker = tuple(
- max(0, c - 40)
- for c in self.color
- )
- pygame.draw.rect(
- car_surf,
- darker,
- (
- 3,
- 48,
- self.width - 6,
- 25
- ),
- border_radius=7
- )
- # ====================================================
- # WINDSHIELD
- # ====================================================
- windshield = [
- (6, 12),
- (self.width - 6, 12),
- (self.width - 9, 34),
- (9, 34)
- ]
- pygame.draw.polygon(
- car_surf,
- (17, 27, 38),
- windshield
- )
- # Windshield reflection
- pygame.draw.line(
- car_surf,
- (70, 95, 115),
- (10, 15),
- (self.width - 10, 15),
- 2
- )
- # Center divider
- pygame.draw.line(
- car_surf,
- (65, 70, 80),
- (
- self.width // 2,
- 13
- ),
- (
- self.width // 2,
- 33
- ),
- 1
- )
- # ====================================================
- # HEADLIGHTS
- # ====================================================
- pygame.draw.rect(
- car_surf,
- (255, 255, 220),
- (
- 4,
- 3,
- 11,
- 6
- ),
- border_radius=2
- )
- pygame.draw.rect(
- car_surf,
- (255, 255, 220),
- (
- self.width - 15,
- 3,
- 11,
- 6
- ),
- border_radius=2
- )
- # ====================================================
- # TAIL LIGHTS
- # ====================================================
- pygame.draw.rect(
- car_surf,
- (255, 20, 20),
- (
- 4,
- self.height - 9,
- 11,
- 5
- )
- )
- pygame.draw.rect(
- car_surf,
- (255, 20, 20),
- (
- self.width - 15,
- self.height - 9,
- 11,
- 5
- )
- )
- # ====================================================
- # WHEELS
- # ====================================================
- wheel_color = (15, 15, 17)
- pygame.draw.rect(
- car_surf,
- wheel_color,
- (-3, 17, 6, 17),
- border_radius=3
- )
- pygame.draw.rect(
- car_surf,
- wheel_color,
- (
- self.width - 3,
- 17,
- 6,
- 17
- ),
- border_radius=3
- )
- pygame.draw.rect(
- car_surf,
- wheel_color,
- (
- -3,
- self.height - 36,
- 6,
- 17
- ),
- border_radius=3
- )
- pygame.draw.rect(
- car_surf,
- wheel_color,
- (
- self.width - 3,
- self.height - 36,
- 6,
- 17
- ),
- border_radius=3
- )
- # Rotate car
- rotated = pygame.transform.rotate(
- car_surf,
- self.angle
- )
- rect = rotated.get_rect(
- center=(
- int(self.x),
- int(self.y)
- )
- )
- surface.blit(
- rotated,
- rect.topleft
- )
- # ============================================================
- # WEATHER
- # ============================================================
- WEATHERS = [
- "CLEAR",
- "RAIN",
- "FOG",
- "NIGHT"
- ]
- def draw_weather(surface, weather):
- overlay = pygame.Surface(
- (WIDTH, HEIGHT),
- pygame.SRCALPHA
- )
- if weather == "RAIN":
- overlay.fill(
- (40, 70, 100, 35)
- )
- # Rain
- for _ in range(90):
- x = random.randint(
- 0,
- WIDTH
- )
- y = random.randint(
- 0,
- HEIGHT
- )
- pygame.draw.line(
- overlay,
- (170, 200, 230, 100),
- (
- x,
- y
- ),
- (
- x - 3,
- y + 14
- ),
- 1
- )
- elif weather == "FOG":
- overlay.fill(
- (170, 180, 185, 55)
- )
- elif weather == "NIGHT":
- overlay.fill(
- (5, 10, 30, 105)
- )
- surface.blit(
- overlay,
- (0, 0)
- )
- # ============================================================
- # ROAD
- # ============================================================
- def draw_road(surface, road_offset, weather):
- # Grass
- surface.fill(
- COLOR_GRASS
- )
- # Road
- pygame.draw.rect(
- surface,
- COLOR_ROAD,
- (
- ROAD_LEFT,
- 0,
- ROAD_WIDTH,
- HEIGHT
- )
- )
- # Road shadows
- pygame.draw.rect(
- surface,
- (22, 23, 27),
- (
- ROAD_LEFT + 8,
- 0,
- 8,
- HEIGHT
- )
- )
- pygame.draw.rect(
- surface,
- (22, 23, 27),
- (
- ROAD_RIGHT - 16,
- 0,
- 8,
- HEIGHT
- )
- )
- # ========================================================
- # LANE MARKINGS
- # ========================================================
- for i in range(1, NUM_LANES):
- lx = (
- ROAD_LEFT +
- i * LANE_WIDTH
- )
- for y in range(
- -100,
- HEIGHT + 100,
- 90
- ):
- pygame.draw.line(
- surface,
- COLOR_LINE_WHITE,
- (
- lx,
- y + int(road_offset)
- ),
- (
- lx,
- y + int(road_offset) + 42
- ),
- 3
- )
- # Yellow road edges
- pygame.draw.line(
- surface,
- COLOR_LINE_YELLOW,
- (
- ROAD_LEFT,
- 0
- ),
- (
- ROAD_LEFT,
- HEIGHT
- ),
- 5
- )
- pygame.draw.line(
- surface,
- COLOR_LINE_YELLOW,
- (
- ROAD_RIGHT,
- 0
- ),
- (
- ROAD_RIGHT,
- HEIGHT
- ),
- 5
- )
- # Wet road effect
- if weather == "RAIN":
- pygame.draw.rect(
- surface,
- (45, 48, 55),
- (
- ROAD_LEFT + 10,
- 0,
- ROAD_WIDTH - 20,
- HEIGHT
- ),
- 2
- )
- # ============================================================
- # VEHICLE SELECTION MENU
- # ============================================================
- def vehicle_menu():
- while True:
- screen.fill(
- COLOR_BG
- )
- # ====================================================
- # TITLE
- # ====================================================
- title = FONT_TITLE.render(
- "NO HESI",
- True,
- COLOR_CYAN
- )
- subtitle = FONT_MED.render(
- "HIGHWAY TRAFFIC WEAVER",
- True,
- COLOR_TEXT
- )
- screen.blit(
- title,
- (
- WIDTH // 2 -
- title.get_width() // 2,
- 45
- )
- )
- screen.blit(
- subtitle,
- (
- WIDTH // 2 -
- subtitle.get_width() // 2,
- 100
- )
- )
- # ====================================================
- # CARS
- # ====================================================
- y = 165
- for key, car in CARS.items():
- box = pygame.Rect(
- WIDTH // 2 - 330,
- y,
- 660,
- 120
- )
- pygame.draw.rect(
- screen,
- (29, 33, 41),
- box,
- border_radius=12
- )
- # Color strip
- pygame.draw.rect(
- screen,
- car["color"],
- (
- box.left + 15,
- box.top + 15,
- 10,
- box.height - 30
- ),
- border_radius=4
- )
- name = FONT_MED.render(
- f"[{key}] {car['name']}",
- True,
- COLOR_TEXT
- )
- desc = FONT_SMALL.render(
- car["desc"],
- True,
- (170, 175, 185)
- )
- stats = FONT_HUD.render(
- f"TOP SPEED "
- f"{int(car['max_speed'] * 18)} KM/H "
- f"HANDLING "
- f"{car['handling']:.1f}",
- True,
- COLOR_GOLD
- )
- screen.blit(
- name,
- (
- box.left + 40,
- box.top + 12
- )
- )
- screen.blit(
- desc,
- (
- box.left + 40,
- box.top + 48
- )
- )
- screen.blit(
- stats,
- (
- box.left + 40,
- box.top + 78
- )
- )
- y += 140
- # ====================================================
- # PROMPT
- # ====================================================
- prompt = FONT_MED.render(
- "Press 1, 2, or 3 to start",
- True,
- COLOR_GOLD
- )
- screen.blit(
- prompt,
- (
- WIDTH // 2 -
- prompt.get_width() // 2,
- HEIGHT - 55
- )
- )
- pygame.display.flip()
- # ====================================================
- # MENU EVENTS
- # ====================================================
- for event in pygame.event.get():
- if event.type == pygame.QUIT:
- pygame.quit()
- sys.exit()
- if event.type == pygame.KEYDOWN:
- if event.unicode in CARS:
- return event.unicode
- # ============================================================
- # MAIN GAME
- # ============================================================
- def game():
- global particles
- # Reset particles for a new run
- particles = []
- # ========================================================
- # SELECT CAR
- # ========================================================
- selected_car = vehicle_menu()
- player = PlayerCar(
- CARS[selected_car]
- )
- # ========================================================
- # GAME VARIABLES
- # ========================================================
- traffic = []
- police = None
- score = 0
- combo = 1
- close_calls = 0
- near_miss_timer = 0
- police_message_timer = 0
- spawn_timer = 0
- weather = "CLEAR"
- weather_index = 0
- weather_change_counter = 0
- road_offset = 0
- running = True
- # ========================================================
- # GAME LOOP
- # ========================================================
- while running:
- clock.tick(60)
- # ====================================================
- # EVENTS
- # ====================================================
- for event in pygame.event.get():
- if event.type == pygame.QUIT:
- return
- if event.type == pygame.KEYDOWN:
- if event.key == pygame.K_ESCAPE:
- return
- if event.key == pygame.K_r:
- return game()
- # ====================================================
- # KEYBOARD
- # ====================================================
- keys = pygame.key.get_pressed()
- # ====================================================
- # PLAYER PHYSICS
- # ====================================================
- player.update(
- keys,
- weather
- )
- # ====================================================
- # WEATHER
- # ====================================================
- weather_change_counter += 1
- # Every combo run eventually changes weather
- if (
- combo > 1
- and
- weather_change_counter > 600
- ):
- weather_change_counter = 0
- weather_index = (
- weather_index + 1
- ) % len(WEATHERS)
- weather = WEATHERS[
- weather_index
- ]
- # ====================================================
- # ROAD SCROLL
- # ====================================================
- road_offset = (
- road_offset +
- player.speed * 2.7
- ) % 90
- # ====================================================
- # TRAFFIC SPAWNING
- # ====================================================
- if not player.crashed:
- spawn_timer += 1
- spawn_delay = max(
- 18,
- 55 - int(player.speed * 1.5)
- )
- if spawn_timer >= spawn_delay:
- spawn_timer = 0
- lane = random.randint(
- 0,
- NUM_LANES - 1
- )
- # Don't stack cars
- lane_busy = any(
- car.lane == lane
- and
- car.y < 160
- for car in traffic
- )
- if not lane_busy:
- # Traffic gets faster as combo rises
- base_min = (
- 4.0 +
- combo * 0.15
- )
- base_max = (
- 8.0 +
- combo * 0.25
- )
- npc_speed = random.uniform(
- base_min,
- min(base_max, 13)
- )
- traffic.append(
- TrafficCar(
- lane,
- npc_speed
- )
- )
- # ====================================================
- # TRAFFIC UPDATE
- # ====================================================
- player_rect = player.get_rect()
- for car in traffic[:]:
- car.update(
- player.speed
- )
- npc_rect = car.get_rect()
- # =================================================
- # COLLISION
- # =================================================
- if not player.crashed:
- collision_rect = player_rect.inflate(
- -7,
- -10
- )
- npc_collision = npc_rect.inflate(
- -5,
- -8
- )
- if collision_rect.colliderect(
- npc_collision
- ):
- player.crashed = True
- combo = 1
- # Crash smoke/explosion
- for _ in range(35):
- particles.append(
- Particle(
- player.x +
- random.uniform(-15, 15),
- player.y +
- random.uniform(-25, 25),
- random.choice([
- (100, 100, 100),
- (180, 180, 180),
- (255, 130, 20)
- ]),
- random.uniform(3, 8),
- (
- random.uniform(-3, 3),
- random.uniform(-3, 3)
- ),
- random.randint(
- 20,
- 50
- )
- )
- )
- # =================================================
- # CLOSE CALL
- # =================================================
- if (
- not car.near_missed
- and
- not player.crashed
- and
- player.speed > 8
- ):
- dx = abs(
- player.x -
- car.x
- )
- dy = abs(
- player.y -
- car.y
- )
- # Tight close-call area
- if (
- dx < 52
- and
- dy < 68
- ):
- car.near_missed = True
- close_calls += 1
- combo += 1
- score += (
- 500 *
- combo
- )
- near_miss_timer = 55
- # Smoke
- create_smoke(
- player.x,
- player.y + 25,
- 5
- )
- # =================================================
- # 4 CLOSE CALLS = POLICE
- # =================================================
- if (
- close_calls >= 4
- and
- police is None
- ):
- police = PoliceCar()
- police_message_timer = 180
- # =================================================
- # REMOVE OFFSCREEN CARS
- # =================================================
- if (
- car.y > HEIGHT + 160
- or
- car.y < -350
- ):
- traffic.remove(car)
- # ========================================================
- # POLICE PURSUIT
- # ========================================================
- if (
- police is not None
- and
- not player.crashed
- ):
- police.target_speed = (
- player.speed + 5
- )
- police.update(
- player
- )
- police_rect = police.get_rect()
- # Police catches player
- if player_rect.colliderect(
- police_rect.inflate(
- -8,
- -10
- )
- ):
- player.crashed = True
- combo = 1
- for _ in range(25):
- create_smoke(
- player.x,
- player.y,
- 1,
- dark=True
- )
- # Don't let police disappear forever
- if police.y < -200:
- police.y = -200
- # ========================================================
- # SCORE
- # ========================================================
- if (
- not player.crashed
- and
- player.speed > 2
- ):
- score += int(
- player.speed *
- combo *
- 0.12
- )
- # ========================================================
- # TIRE SMOKE
- # ========================================================
- if not player.crashed:
- # Hard braking
- if (
- player.braking
- and
- player.speed > 8
- ):
- create_smoke(
- player.x - 13,
- player.y + 32,
- 1
- )
- create_smoke(
- player.x + 13,
- player.y + 32,
- 1
- )
- # Drifting
- elif player.drifting:
- create_smoke(
- player.x - 14,
- player.y + 32,
- 1
- )
- create_smoke(
- player.x + 14,
- player.y + 32,
- 1
- )
- # ========================================================
- # UPDATE PARTICLES
- # ========================================================
- for particle in particles[:]:
- particle.update()
- if particle.life <= 0:
- particles.remove(
- particle
- )
- # ========================================================
- # DRAW ROAD
- # ========================================================
- draw_road(
- screen,
- road_offset,
- weather
- )
- # ========================================================
- # DRAW TRAFFIC
- # ========================================================
- for car in traffic:
- car.draw(
- screen
- )
- # ========================================================
- # DRAW POLICE
- # ========================================================
- if police is not None:
- police.draw(
- screen
- )
- # ========================================================
- # DRAW PLAYER
- # ========================================================
- player.draw(
- screen
- )
- # ========================================================
- # DRAW PARTICLES
- # ========================================================
- for particle in particles:
- particle.draw(
- screen
- )
- # ========================================================
- # WEATHER
- # ========================================================
- draw_weather(
- screen,
- weather
- )
- # ========================================================
- # HUD
- # ========================================================
- speed_kmh = int(
- player.speed * 18
- )
- screen.blit(
- FONT_HUD.render(
- f"SPEED {speed_kmh:03d} KM/H",
- True,
- COLOR_TEXT
- ),
- (20, 20)
- )
- screen.blit(
- FONT_HUD.render(
- f"SCORE {score:,}",
- True,
- COLOR_GOLD
- ),
- (20, 48)
- )
- screen.blit(
- FONT_HUD.render(
- f"COMBO x{combo}",
- True,
- COLOR_CYAN
- if combo > 1
- else COLOR_TEXT
- ),
- (20, 76)
- )
- screen.blit(
- FONT_HUD.render(
- f"CLOSE CALLS {close_calls}/4",
- True,
- COLOR_ORANGE
- if close_calls >= 3
- else COLOR_TEXT
- ),
- (20, 104)
- )
- screen.blit(
- FONT_HUD.render(
- f"WEATHER {weather}",
- True,
- COLOR_TEXT
- ),
- (20, 132)
- )
- # ========================================================
- # POLICE WARNING
- # ========================================================
- if police_message_timer > 0:
- police_message_timer -= 1
- warning = FONT_BIG.render(
- "POLICE PURSUIT!",
- True,
- COLOR_RED
- )
- screen.blit(
- warning,
- (
- WIDTH // 2 -
- warning.get_width() // 2,
- 130
- )
- )
- warning2 = FONT_MED.render(
- "HIGH SPEED UNIT DEPLOYED",
- True,
- COLOR_TEXT
- )
- screen.blit(
- warning2,
- (
- WIDTH // 2 -
- warning2.get_width() // 2,
- 175
- )
- )
- # ========================================================
- # CLOSE CALL MESSAGE
- # ========================================================
- if near_miss_timer > 0:
- near_miss_timer -= 1
- text = FONT_BIG.render(
- "CLOSE CALL!",
- True,
- COLOR_GOLD
- )
- screen.blit(
- text,
- (
- WIDTH // 2 -
- text.get_width() // 2,
- 220
- )
- )
- # ========================================================
- # CRASH SCREEN
- # ========================================================
- if player.crashed:
- dark = pygame.Surface(
- (WIDTH, HEIGHT),
- pygame.SRCALPHA
- )
- dark.fill(
- (0, 0, 0, 120)
- )
- screen.blit(
- dark,
- (0, 0)
- )
- crash = FONT_TITLE.render(
- "CRASHED!",
- True,
- COLOR_RED
- )
- screen.blit(
- crash,
- (
- WIDTH // 2 -
- crash.get_width() // 2,
- HEIGHT // 2 - 70
- )
- )
- score_text = FONT_MED.render(
- f"FINAL SCORE: {score:,}",
- True,
- COLOR_GOLD
- )
- screen.blit(
- score_text,
- (
- WIDTH // 2 -
- score_text.get_width() // 2,
- HEIGHT // 2
- )
- )
- restart = FONT_MED.render(
- "Press R to restart",
- True,
- COLOR_TEXT
- )
- screen.blit(
- restart,
- (
- WIDTH // 2 -
- restart.get_width() // 2,
- HEIGHT // 2 + 45
- )
- )
- # ========================================================
- # DISPLAY
- # ========================================================
- pygame.display.flip()
- # ============================================================
- # PROGRAM START
- # ============================================================
- def main():
- try:
- game()
- except Exception as error:
- pygame.quit()
- print()
- print("=" * 60)
- print("GAME CRASH DETECTED")
- print("=" * 60)
- print()
- print(error)
- print()
- print("=" * 60)
- raise
- # ============================================================
- # START
- # ============================================================
- if __name__ == "__main__":
- main()
Advertisement
Add Comment
Please, Sign In to add comment