diff --git a/Games/Car_Racing_Game/README.md b/Games/Car_Racing_Game/README.md new file mode 100644 index 0000000000..8843bf7fd4 --- /dev/null +++ b/Games/Car_Racing_Game/README.md @@ -0,0 +1,74 @@ +# **Car Racing Game** +--- + +
+ +## **Description 📃** + +Car Racing Game is an exhilarating 2D racing game where players control a red car and compete against a computer-controlled green car. The game features multiple levels with increasing difficulty, realistic collision detection, and smooth controls. + + +## **Functionalities 🎮** + +- **Player and Computer Cars**: Control the red car and race against the green computer car. +- **Levels and Progression**: Complete levels by reaching the finish line before the computer car. Each level offers more challenges and obstacles. +- **Collision Detection**: Realistic collision detection with track borders and other cars. +- **Speed Control**: Adjust the speed of your car using the arrow keys. +- **Direction Control**: Rotate your car left or right to navigate through the track. +- **Game Over and Reset**: The game ends if the player fails to beat the computer car. Reset the game to try again. + +
+ +## **How to Play? 🕹ī¸** + +1. **Start the Game**: Launch the game to begin. + +### Controls: + +- Use the **left** and **right arrow keys** to rotate the car. +- Use the **up arrow key** to accelerate forward. +- Use the **down arrow key** to slow down or reverse. + +2. **Navigate the Track**: Avoid collisions with track borders and other cars. +3. **Complete Levels**: Reach the finish line before the computer car to advance to the next level. +4. **Game Over**: If the computer car reaches the finish line first, it's game over. Reset the game to try again. + +
+ +## **Installation and Running the Game 🚀** +### Prerequisites + +- Python 3.x +- Pygame library + +### Steps + +1. **Clone the repository**: + ```sh + git clone https://github.com/shellyverma/game.git + ``` + +2. **Navigate to the game directory**: + ```sh + cd game + ``` + +3. **Install the dependencies** (assuming you have Python and pip installed): + ```sh + pip install pygame + ``` + +4. **Run the game**: + ```sh + python main.py + ``` + +
+ +## **Screenshots 📸** + + +![Game Screenshot](https://github.com/shellyverma/game/blob/ea66450ffb4afb9fb849ea685e39a131d5da8849/Screenshot%20.png?raw=true) + +--- + diff --git a/Games/Car_Racing_Game/__pycache__/utils.cpython-312.pyc b/Games/Car_Racing_Game/__pycache__/utils.cpython-312.pyc new file mode 100644 index 0000000000..c9a648cf14 Binary files /dev/null and b/Games/Car_Racing_Game/__pycache__/utils.cpython-312.pyc differ diff --git a/Games/Car_Racing_Game/git b/Games/Car_Racing_Game/git new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Games/Car_Racing_Game/imgs/finish.png b/Games/Car_Racing_Game/imgs/finish.png new file mode 100644 index 0000000000..9f78c56d0c Binary files /dev/null and b/Games/Car_Racing_Game/imgs/finish.png differ diff --git a/Games/Car_Racing_Game/imgs/grass.png b/Games/Car_Racing_Game/imgs/grass.png new file mode 100644 index 0000000000..dbacd680f0 Binary files /dev/null and b/Games/Car_Racing_Game/imgs/grass.png differ diff --git a/Games/Car_Racing_Game/imgs/green-car.png b/Games/Car_Racing_Game/imgs/green-car.png new file mode 100644 index 0000000000..053ec9949c Binary files /dev/null and b/Games/Car_Racing_Game/imgs/green-car.png differ diff --git a/Games/Car_Racing_Game/imgs/red-car.png b/Games/Car_Racing_Game/imgs/red-car.png new file mode 100644 index 0000000000..49441823ca Binary files /dev/null and b/Games/Car_Racing_Game/imgs/red-car.png differ diff --git a/Games/Car_Racing_Game/imgs/track-border.png b/Games/Car_Racing_Game/imgs/track-border.png new file mode 100644 index 0000000000..a5d9a46a57 Binary files /dev/null and b/Games/Car_Racing_Game/imgs/track-border.png differ diff --git a/Games/Car_Racing_Game/imgs/track.png b/Games/Car_Racing_Game/imgs/track.png new file mode 100644 index 0000000000..bd6954dace Binary files /dev/null and b/Games/Car_Racing_Game/imgs/track.png differ diff --git a/Games/Car_Racing_Game/main.py b/Games/Car_Racing_Game/main.py new file mode 100644 index 0000000000..756c470b6b --- /dev/null +++ b/Games/Car_Racing_Game/main.py @@ -0,0 +1,328 @@ +import pygame +import time +import math +from utils import scale_image, blit_rotate_center, blit_text_center +import os + +# Initialize Pygame font module +pygame.font.init() + +# Set the base directory to the GameZone/Games/Car_Racing_Game directory +base_dir = os.path.join(os.getcwd(), "Games", "Car_Racing_Game") +imgs_dir = os.path.join(base_dir, "imgs") + +# Debug prints to ensure directories are correct +print("Base directory:", base_dir) +print("Images directory:", imgs_dir) +if os.path.exists(imgs_dir): + print("Files in imgs directory:", os.listdir(imgs_dir)) +else: + print("imgs directory not found") + +# Attempt to load the images with error handling +try: + GRASS = scale_image(pygame.image.load(os.path.join(imgs_dir, "grass.png")), 2.5) + print("grass.png loaded successfully") +except FileNotFoundError as e: + print("Error loading grass.png:", e) + +try: + TRACK = scale_image(pygame.image.load(os.path.join(imgs_dir, "track.png")), 0.9) + print("track.png loaded successfully") +except FileNotFoundError as e: + print("Error loading track.png:", e) + +try: + TRACK_BORDER = scale_image(pygame.image.load(os.path.join(imgs_dir, "track-border.png")), 0.9) + TRACK_BORDER_MASK = pygame.mask.from_surface(TRACK_BORDER) + print("track-border.png loaded successfully") +except FileNotFoundError as e: + print("Error loading track-border.png:", e) + +try: + FINISH = pygame.image.load(os.path.join(imgs_dir, "finish.png")) + FINISH_MASK = pygame.mask.from_surface(FINISH) + FINISH_POSITION = (130, 250) + print("finish.png loaded successfully") +except FileNotFoundError as e: + print("Error loading finish.png:", e) + +try: + RED_CAR = scale_image(pygame.image.load(os.path.join(imgs_dir, "red-car.png")), 0.55) + print("red-car.png loaded successfully") +except FileNotFoundError as e: + print("Error loading red-car.png:", e) + +try: + GREEN_CAR = scale_image(pygame.image.load(os.path.join(imgs_dir, "green-car.png")), 0.55) + print("green-car.png loaded successfully") +except FileNotFoundError as e: + print("Error loading green-car.png:", e) + +# Ensure TRACK is loaded before setting up the game window +if 'TRACK' in locals(): + # Set up the game window dimensions + WIDTH, HEIGHT = TRACK.get_width(), TRACK.get_height() + WIN = pygame.display.set_mode((WIDTH, HEIGHT)) + pygame.display.set_caption("Racing Game!") + + # Set up the main font for text display + MAIN_FONT = pygame.font.SysFont("comicsans", 44) + + # Game settings + FPS = 60 + PATH = [(175, 119), (110, 70), (56, 133), (70, 481), (318, 731), (404, 680), (418, 521), (507, 475), (600, 551), (613, 715), (736, 713), + (734, 399), (611, 357), (409, 343), (433, 257), (697, 258), (738, 123), (581, 71), (303, 78), (275, 377), (176, 388), (178, 260)] + + # Class to manage game information such as levels and time + class GameInfo: + LEVELS = 10 + + def __init__(self, level=1): + self.level = level + self.started = False + self.level_start_time = 0 + + def next_level(self): + self.level += 1 + self.started = False + + def reset(self): + self.level = 1 + self.started = False + self.level_start_time = 0 + + def game_finished(self): + return self.level > self.LEVELS + + def start_level(self): + self.started = True + self.level_start_time = time.time() + + def get_level_time(self): + if not self.started: + return 0 + return round(time.time() - self.level_start_time) + + # Abstract car class with common functionalities for player and computer cars + class AbstractCar: + def __init__(self, max_vel, rotation_vel): + self.img = self.IMG + self.max_vel = max_vel + self.vel = 0 + self.rotation_vel = rotation_vel + self.angle = 0 + self.x, self.y = self.START_POS + self.acceleration = 0.1 + + def rotate(self, left=False, right=False): + if left: + self.angle += self.rotation_vel + elif right: + self.angle -= self.rotation_vel + + def draw(self, win): + blit_rotate_center(win, self.img, (self.x, self.y), self.angle) + + def move_forward(self): + self.vel = min(self.vel + self.acceleration, self.max_vel) + self.move() + + def move_backward(self): + self.vel = max(self.vel - self.acceleration, -self.max_vel/2) + self.move() + + def move(self): + radians = math.radians(self.angle) + vertical = math.cos(radians) * self.vel + horizontal = math.sin(radians) * self.vel + + self.y -= vertical + self.x -= horizontal + + def collide(self, mask, x=0, y=0): + car_mask = pygame.mask.from_surface(self.img) + offset = (int(self.x - x), int(self.y - y)) + poi = mask.overlap(car_mask, offset) + return poi + + def reset(self): + self.x, self.y = self.START_POS + self.angle = 0 + self.vel = 0 + + # Player car class with specific functionalities + class PlayerCar(AbstractCar): + IMG = RED_CAR + START_POS = (180, 200) + + def reduce_speed(self): + self.vel = max(self.vel - self.acceleration / 2, 0) + self.move() + + def bounce(self): + self.vel = -self.vel + self.move() + + # Computer car class with AI functionalities + class ComputerCar(AbstractCar): + IMG = GREEN_CAR + START_POS = (150, 200) + + def __init__(self, max_vel, rotation_vel, path=[]): + super().__init__(max_vel, rotation_vel) + self.path = path + self.current_point = 0 + self.vel = max_vel + + def draw_points(self, win): + for point in self.path: + pygame.draw.circle(win, (255, 0, 0), point, 5) + + def draw(self, win): + super().draw(win) + # self.draw_points(win) + + def calculate_angle(self): + target_x, target_y = self.path[self.current_point] + x_diff = target_x - self.x + y_diff = target_y - self.y + + if y_diff == 0: + desired_radian_angle = math.pi / 2 + else: + desired_radian_angle = math.atan(x_diff / y_diff) + + if target_y > self.y: + desired_radian_angle += math.pi + + difference_in_angle = self.angle - math.degrees(desired_radian_angle) + if difference_in_angle >= 180: + difference_in_angle -= 360 + + if difference_in_angle > 0: + self.angle -= min(self.rotation_vel, abs(difference_in_angle)) + else: + self.angle += min(self.rotation_vel, abs(difference_in_angle)) + + def update_path_point(self): + target = self.path[self.current_point] + rect = pygame.Rect( + self.x, self.y, self.img.get_width(), self.img.get_height()) + if rect.collidepoint(*target): + self.current_point += 1 + + def move(self): + if self.current_point >= len(self.path): + return + + self.calculate_angle() + self.update_path_point() + super().move() + + def next_level(self, level): + self.reset() + self.vel = self.max_vel + (level - 1) * 0.2 + self.current_point = 0 + + # Function to draw the game elements on the screen + def draw(win, images, player_car, computer_car, game_info): + for img, pos in images: + win.blit(img, pos) + + level_text = MAIN_FONT.render( + f"Level {game_info.level}", 1, (255, 255, 255)) + win.blit(level_text, (10, HEIGHT - level_text.get_height() - 70)) + + time_text = MAIN_FONT.render( + f"Time: {game_info.get_level_time()}s", 1, (255, 255, 255)) + win.blit(time_text, (10, HEIGHT - time_text.get_height() - 40)) + + vel_text = MAIN_FONT.render( + f"Vel: {round(player_car.vel, 1)}px/s", 1, (255, 255, 255)) + win.blit(vel_text, (10, HEIGHT - vel_text.get_height() - 10)) + + player_car.draw(win) + computer_car.draw(win) + pygame.display.update() + + # Function to handle player car movement + def move_player(player_car): + keys = pygame.key.get_pressed() + moved = False + + if keys[pygame.K_LEFT]: + player_car.rotate(left=True) + if keys[pygame.K_RIGHT]: + player_car.rotate(right=True) + if keys[pygame.K_UP]: + moved = True + player_car.move_forward() + if keys[pygame.K_DOWN]: + moved = True + player_car.move_backward() + + if not moved: + player_car.reduce_speed() + + # Main game loop + run = True + clock = pygame.time.Clock() + images = [(GRASS, (0, 0)), (TRACK, (0, 0)), + (FINISH, FINISH_POSITION), (TRACK_BORDER, (0, 0))] + player_car = PlayerCar(4, 4) + computer_car = ComputerCar(2, 4, PATH) + game_info = GameInfo() + + while run: + clock.tick(FPS) + + draw(WIN, images, player_car, computer_car, game_info) + + # Wait for the player to start the level + while not game_info.started: + blit_text_center( + WIN, MAIN_FONT, f"Press any key to start level {game_info.level}!") + pygame.display.update() + for event in pygame.event.get(): + if event.type == pygame.QUIT: + run = False + break + if event.type == pygame.KEYDOWN: + game_info.start_level() + + for event in pygame.event.get(): + if event.type == pygame.QUIT: + run = False + break + + move_player(player_car) + computer_car.move() + + # Check for collisions with the track border + if player_car.collide(TRACK_BORDER_MASK) != None: + player_car.bounce() + + # Check for collisions with the finish line + finish_poi_collide = player_car.collide( + FINISH_MASK, *FINISH_POSITION) + if finish_poi_collide != None: + if finish_poi_collide[1] == 0: + player_car.bounce() + else: + game_info.next_level() + player_car.reset() + computer_car.next_level(game_info.level) + + # Check if the game is finished + if game_info.game_finished(): + blit_text_center(WIN, MAIN_FONT, "You won the game!") + pygame.display.update() + pygame.time.wait(5000) + game_info.reset() + player_car.reset() + computer_car.reset() + + pygame.quit() +else: + print("TRACK not loaded. Exiting.") diff --git a/Games/Car_Racing_Game/utils.py b/Games/Car_Racing_Game/utils.py new file mode 100644 index 0000000000..e3aa50d2f2 --- /dev/null +++ b/Games/Car_Racing_Game/utils.py @@ -0,0 +1,50 @@ +import pygame + +def scale_image(img, factor): + """ + Scale an image by a given factor. + + Parameters: + img (pygame.Surface): The image to be scaled. + factor (float): The scaling factor. + + Returns: + pygame.Surface: The scaled image. + """ + size = round(img.get_width() * factor), round(img.get_height() * factor) + return pygame.transform.scale(img, size) + +def blit_rotate_center(win, image, top_left, angle): + """ + Draw an image rotated around its center. + + Parameters: + win (pygame.Surface): The surface to draw the image on. + image (pygame.Surface): The image to be rotated and drawn. + top_left (tuple): The top-left coordinates of the image. + angle (float): The angle to rotate the image. + """ + # Rotate the image by the specified angle + rotated_image = pygame.transform.rotate(image, angle) + # Get the new rectangle of the rotated image, centered on the original image's center + new_rect = rotated_image.get_rect(center=image.get_rect(topleft=top_left).center) + # Draw the rotated image on the window + win.blit(rotated_image, new_rect.topleft) + +def blit_text_center(win, font, text): + """ + Draw text centered on the window. + + Parameters: + win (pygame.Surface): The surface to draw the text on. + font (pygame.font.Font): The font used to render the text. + text (str): The text to be rendered and drawn. + """ + # Render the text with the specified font + render = font.render(text, 1, (200, 200, 200)) + # Calculate the position to center the text on the window + position = (win.get_width() / 2 - render.get_width() / 2, + win.get_height() / 2 - render.get_height() / 2) + # Draw the text on the window + win.blit(render, position) + diff --git a/README.md b/README.md index 901a5700d5..0008290f12 100644 --- a/README.md +++ b/README.md @@ -805,15 +805,13 @@ This repository also provides one such platforms where contributers come over an | [Helicopter_Game](https://github.com/kinjgit/GameZone/tree/main/Games/Helicopter_Game) | | [Bouncing Ball Game](https://github.com/kunjgit/GameZone/tree/main/Games/Bouncing_Ball_Game) | |[Harmony_Mixer](https://github.com/kunjgit/GameZone/tree/main/Games/Harmony_Mixer)| +|[Car_Racing_Game](https://github.com/kunjgit/GameZone/tree/main/Games/Car_Racing_Game)| |[KeySymphony](https://github.com/kunjgit/GameZone/tree/main/Games/KeySymphony)| |[Math_Race_Game](https://github.com/kunjgit/GameZone/tree/main/Games/Math_Race_Game)| | [Bunny is Lost](https://github.com/kunjgit/GameZone/tree/main/Games/Bunny_is_Lost)| |[Steam_Punk](https://github.com/kunjgit/GameZone/tree/main/Games/Steam_Punk)| |[Tower Defence Game](https://github.com/Will2Jacks/GameZoneForked/tree/Task/Games/Tower_Defence_Game)| - |[Dot_Dash](https://github.com/kunjgit/GameZone/tree/main/Games/Dot_Dash)| - - |[Ghost Busting Game](https://github.com/kunjgit/GameZone/tree/main/Games/Ghost_busting_game)| |[Wheel_of_fortune](https://github.com/Will2Jacks/GameZoneForked/tree/Task/Games/Wheel_of_fortune)| |[Dot_Box_Game](https://github.com/kunjgit/GameZone/tree/main/Games/Dot_Box_Game)| diff --git a/assets/images/Car_Racing_Game.png b/assets/images/Car_Racing_Game.png new file mode 100644 index 0000000000..fba0a97e03 Binary files /dev/null and b/assets/images/Car_Racing_Game.png differ