From 665e9dde9324671ce532c38cb69e50039ea2fae0 Mon Sep 17 00:00:00 2001 From: SuperY613 <180219147+SuperY613@users.noreply.github.com> Date: Tue, 23 Jun 2026 02:08:52 +0000 Subject: [PATCH] Pending changes exported from your codespace --- README.md | 333 ++++++++++++++++++++++++++++- __pycache__/README.cpython-312.pyc | Bin 0 -> 19907 bytes 2 files changed, 332 insertions(+), 1 deletion(-) create mode 100644 __pycache__/README.cpython-312.pyc diff --git a/README.md b/README.md index c9aff93..7657691 100644 --- a/README.md +++ b/README.md @@ -1 +1,332 @@ -# Racing-game \ No newline at end of file +""" +Top-down Racing Game (single file) +Requires: pygame +Install: pip install pygame +Run: python racing_game.py + +Controls: + - Up / W : accelerate + - Down / S : brake / reverse + - Left / A : steer left + - Right / D : steer right + - R : restart race + - ESC or window close : quit +""" +# Ensure pygame is installed: pip install pygame +import sys +import math +import random +import pygame +from pygame import Vector2 # type: ignore + +pygame.init() +WIDTH, HEIGHT = 1000, 700 +SCREEN = pygame.display.set_mode((WIDTH, HEIGHT)) +pygame.display.set_caption("Top-down Racing Demo") +CLOCK = pygame.time.Clock() +FONT = pygame.font.SysFont(None, 24) + +# Colors +GREEN = (61, 174, 64) +ROAD = (50, 50, 50) +LINE = (255, 255, 255) +START_LINE = (255, 0, 0) +SKY = (120, 200, 255) + +# Track parameters +TRACK_CENTER = Vector2(WIDTH // 2, HEIGHT // 2 - 20) +OUTER_RX, OUTER_RY = 380, 220 +INNER_RX, INNER_RY = 200, 90 + +# Game settings +NUM_OPPONENTS = 3 +LAPS_TO_FINISH = 3 + +def create_track_surface(): + surf = pygame.Surface((WIDTH, HEIGHT)) + surf.fill(GREEN) + # draw outer track (road) + pygame.draw.ellipse(surf, ROAD, ( + TRACK_CENTER.x - OUTER_RX, TRACK_CENTER.y - OUTER_RY, OUTER_RX * 2, OUTER_RY * 2 + )) + # cut out inner grass to make ring + pygame.draw.ellipse(surf, GREEN, ( + TRACK_CENTER.x - INNER_RX, TRACK_CENTER.y - INNER_RY, INNER_RX * 2, INNER_RY * 2 + )) + # draw finish/start line at top center of inner ellipse + line_w = 4 + # compute top point of inner ellipse + top_x = TRACK_CENTER.x + top_y = TRACK_CENTER.y - INNER_RY + pygame.draw.line(surf, START_LINE, (top_x - 20, top_y), (top_x + 20, top_y), line_w) + # small white dashes on outer boundary for visuals + for a in range(0, 360, 12): + ra = math.radians(a) + x = TRACK_CENTER.x + math.cos(ra) * (OUTER_RX + INNER_RX) / 2 + y = TRACK_CENTER.y + math.sin(ra) * (OUTER_RY + INNER_RY) / 2 + pygame.draw.circle(surf, (200, 200, 200), (int(x), int(y)), 2) + return surf + +TRACK_SURF = create_track_surface() +TRACK_PIXELS = pygame.PixelArray(TRACK_SURF) # for quick color checks (read-only usage) + +def is_on_road(pos): + x, y = int(pos.x), int(pos.y) + if 0 <= x < WIDTH and 0 <= y < HEIGHT: + return TRACK_SURF.get_at((x, y))[:3] == ROAD + return False + +def angle_to(target, current_pos): + v = target - current_pos + return math.degrees(math.atan2(-v.y, v.x)) % 360 + +class Car: + def __init__(self, color, pos, angle=0.0, max_speed=4.0): + self.color = color + self.pos = Vector2(pos) + self.angle = angle # degrees, 0 = right + self.speed = 0.0 + self.max_speed = max_speed + self.length = 28 + self.width = 14 + self.acceleration = 0.12 + self.brake_decel = 0.2 + self.friction = 0.03 + self.steer_speed = 3.5 # degrees per frame at full lock + self.laps = 0 + self.previous_cross = False + self.progress = 0.0 # angular progress on track for ranking + + def rect_points(self): + # return polygon points for rotated rectangle (for debugging/collision visuals) + rad = math.radians(self.angle) + cos, sin = math.cos(rad), math.sin(rad) + l, w = self.length / 2, self.width / 2 + corners = [ + Vector2(cos * l - sin * w, sin * l + cos * w), + Vector2(-cos * l - sin * w, -sin * l + cos * w), + Vector2(-cos * l + sin * w, -sin * l - cos * w), + Vector2(cos * l + sin * w, sin * l - cos * w), + ] + return [self.pos + p for p in corners] + + def update(self): + # movement integration + rad = math.radians(self.angle) + self.pos += Vector2(math.cos(rad), -math.sin(rad)) * self.speed + + # friction + if self.speed > 0: + self.speed = max(0.0, self.speed - self.friction) + elif self.speed < 0: + self.speed = min(0.0, self.speed + self.friction) + + # check road/grass slowdown + if not is_on_road(self.pos): + # on grass => heavy slowdown + self.speed *= 0.94 + # reduce steering + # (we don't change steer here; controllers apply steer with penalty) + # keep on screen + self.pos.x = max(0, min(WIDTH - 1, self.pos.x)) + self.pos.y = max(0, min(HEIGHT - 1, self.pos.y)) + + # compute angular progress around track center (for lap progress) + dx = self.pos.x - TRACK_CENTER.x + dy = self.pos.y - TRACK_CENTER.y + angle = math.degrees(math.atan2(-dy, dx)) % 360 + # convert to a progress metric (0...1) around the track + self.progress = angle / 360.0 + + # finish line crossing detection: compare above/below top y of inner ellipse + top_y = TRACK_CENTER.y - INNER_RY + # crossing occurs when y <= top_y +/- a small tolerance and x near center + x_near = abs(self.pos.x - TRACK_CENTER.x) < INNER_RX * 0.6 + crossing = (self.pos.y < top_y + 6) and x_near + if crossing and not self.previous_cross: + # when crossing heading roughly forward (y increasing after crossing) + self.laps += 1 + self.previous_cross = crossing + + def draw(self, surf): + # draw rotated rectangle + points = self.rect_points() + pg_points = [(p.x, p.y) for p in points] + pygame.draw.polygon(surf, self.color, pg_points) + # small nose to indicate forward + rad = math.radians(self.angle) + nose = self.pos + Vector2(math.cos(rad), -math.sin(rad)) * (self.length/2 + 4) + pygame.draw.circle(surf, (0,0,0), (int(nose.x), int(nose.y)), 3) + +class PlayerCar(Car): + def handle_input(self, keys): + # acceleration / braking + if keys[pygame.K_UP] or keys[pygame.K_w]: + self.speed += self.acceleration + if keys[pygame.K_DOWN] or keys[pygame.K_s]: + self.speed -= self.brake_decel + # steering scaled by speed + steer_amount = self.steer_speed * (max(0.2, abs(self.speed) / self.max_speed)) + if keys[pygame.K_LEFT] or keys[pygame.K_a]: + self.angle += steer_amount + if keys[pygame.K_RIGHT] or keys[pygame.K_d]: + self.angle -= steer_amount + # clamp + self.speed = max(-self.max_speed/2, min(self.max_speed, self.speed)) + +class AICar(Car): + def __init__(self, color, pos, waypoints, angle=0.0, max_speed=3.7): + super().__init__(color, pos, angle, max_speed) + self.waypoints = waypoints + self.current_wp = 0 + + def update_ai(self): + target = self.waypoints[self.current_wp] + vec_to = target - self.pos + dist = vec_to.length() + desired_angle = math.degrees(math.atan2(-vec_to.y, vec_to.x)) % 360 + # angle difference + diff = (desired_angle - self.angle + 180) % 360 - 180 + # steer toward desired angle + steer = max(-self.steer_speed, min(self.steer_speed, -diff)) + # steering effectiveness lowered on grass + if not is_on_road(self.pos): + steer *= 0.5 + self.angle += steer * 0.6 # AI steering smoothing + # throttle control + if abs(diff) < 30: + self.speed += self.acceleration * (1.2 if is_on_road(self.pos) else 0.3) + else: + # slow down for sharp turns + self.speed -= self.brake_decel * 0.8 + # reach waypoint + if dist < 30: + self.current_wp = (self.current_wp + 1) % len(self.waypoints) + # clamp speed + self.speed = max(-self.max_speed/3, min(self.max_speed, self.speed)) + +# create circular waypoints around TRACK_CENTER for AI +def generate_waypoints(n=24, radius_x=(OUTER_RX+INNER_RX)/2, radius_y=(OUTER_RY+INNER_RY)/2, jitter=10): + pts = [] + for i in range(n): + a = math.radians(i * (360.0 / n)) + r_x = radius_x + random.uniform(-jitter, jitter) + r_y = radius_y + random.uniform(-jitter, jitter) + x = TRACK_CENTER.x + math.cos(a) * r_x + y = TRACK_CENTER.y + math.sin(a) * r_y + pts.append(Vector2(x, y)) + return pts + +WAYPOINTS = generate_waypoints(32) + +def reset_race(): + # player start just above start line, facing right + player = PlayerCar((0, 120, 230), Vector2(TRACK_CENTER.x - 40, TRACK_CENTER.y - INNER_RY - 30), angle=0.0, max_speed=5.0) + opponents = [] + for i in range(NUM_OPPONENTS): + offset = (i + 1) * 40 + pos = Vector2(TRACK_CENTER.x + offset, TRACK_CENTER.y - INNER_RY - 30) + color = (200 - i*40, 50 + i*50, 50 + i*30) + ai = AICar(color, pos, WAYPOINTS, angle=0.0, max_speed=4.2 - i*0.4) + opponents.append(ai) + return player, opponents + +player, opponents = reset_race() + +def draw_hud(surf, player, opponents, finished=False): + lines = [ + f"Speed: {player.speed:.1f}", + f"Laps: {min(player.laps, LAPS_TO_FINISH)}/{LAPS_TO_FINISH}", + ] + for i, line in enumerate(lines): + txt = FONT.render(line, True, (0,0,0)) + surf.blit(txt, (10, 10 + i*22)) + # ranking by laps then progress + racers = [player] + opponents + def rank_key(c): + return (c.laps, c.progress) + racers_sorted = sorted(racers, key=rank_key, reverse=True) + for i, r in enumerate(racers_sorted): + label = "You" if r is player else f"CPU{i}" + stat = f"{i+1}. {label} L{r.laps} P{int(r.speed)}" + txt = FONT.render(stat, True, (0,0,0)) + surf.blit(txt, (WIDTH - 220, 10 + i*22)) + if finished: + msg = FONT.render("Race finished! Press R to restart.", True, (0,0,0)) + surf.blit(msg, (WIDTH//2 - 120, 20)) + +def draw_instructions(surf): + lines = [ + "Controls: Arrow keys or WASD to drive. R to restart.", + "Drive on the gray road. Red line = start/finish.", + f"Complete {LAPS_TO_FINISH} laps to finish." + ] + for i, t in enumerate(lines): + txt = FONT.render(t, True, (10,10,10)) + surf.blit(txt, (10, HEIGHT - 70 + i*20)) + +def mainloop(): + global player, opponents + running = True + finished = False + finish_timer = 0 + while running: + dt = CLOCK.tick(60) / 1000.0 + for event in pygame.event.get(): + if event.type == pygame.QUIT: + running = False + elif event.type == pygame.KEYDOWN: + if event.key == pygame.K_ESCAPE: + running = False + if event.key == pygame.K_r: + player, opponents = reset_race() + finished = False + finish_timer = 0 + + keys = pygame.key.get_pressed() + if not finished: + player.handle_input(keys) + player.update() + for ai in opponents: + ai.update_ai() + ai.update() + + # check finish condition + if not finished and player.laps >= LAPS_TO_FINISH: + finished = True + finish_timer = pygame.time.get_ticks() + + # draw scene + SCREEN.fill(SKY) + SCREEN.blit(TRACK_SURF, (0, 0)) + + # optional: draw waypoints for debug (comment out later) + # for wp in WAYPOINTS: + # pygame.draw.circle(SCREEN, (0,0,0), (int(wp.x), int(wp.y)), 3) + + # draw racers in order by their y for simple painter's ordering + all_cars = opponents + [player] + all_cars.sort(key=lambda c: c.pos.y) # draws from top to bottom + for car in all_cars: + car.draw(SCREEN) + + draw_hud(SCREEN, player, opponents, finished) + draw_instructions(SCREEN) + + # if finished show winner info + if finished: + winner = sorted([player] + opponents, key=lambda c: (c.laps, c.progress), reverse=True)[0] + if winner is player: + msg = "You won! Press R to race again." + else: + msg = "CPU won. Press R to try again." + big = pygame.font.SysFont(None, 40).render(msg, True, (255, 0, 0)) + SCREEN.blit(big, (WIDTH//2 - big.get_width()//2, HEIGHT//2 - 20)) + + pygame.display.flip() + + pygame.quit() + sys.exit() + +if __name__ == "__main__": + mainloop() \ No newline at end of file diff --git a/__pycache__/README.cpython-312.pyc b/__pycache__/README.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..af4bb3190992b2e04a31532046c7f59ca1e4a070 GIT binary patch literal 19907 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 Id1UGSKaNP3@Bjb+ literal 0 HcmV?d00001