Question:
I just made a car racing game on PyCharm using pygame and decided i wanted to run it here on replit. The code runs fine on PyCharm but when i run the code however, the program raises an error saying pygame.error: Unsupported image format
. I can’t view my image files as they all seem to say Failed to load media file
Repl link:
https://replit.com/@jonathanessombe/Car-Racing-game
import pygame
import time
import math
# import the module from our Race Car game directory
from utils import scale_image, blit_rotation_center, blit_text_center
pygame.font.init()
# poi = point of intersection
# Initializing images and scale the images using scale_image()
grass = scale_image(pygame.image.load('grass.jpg'), 2.5)
track = scale_image(pygame.image.load('track.png'), 0.85)
# Initialize the calling mask
track_border = scale_image(pygame.image.load('track-border.png'), 0.85)
track_border_mask = pygame.mask.from_surface(track_border)
finish = pygame.image.load('finish.png')
finish_mask = pygame.mask.from_surface(finish)
finish_position = (130, 250)
red_car = scale_image(pygame.image.load('red-car.png'), 0.55)
green_car = scale_image(pygame.image.load('green-car.png'), 0.55)
# width and height from the track image we initialized
width, height = track.get_width(), track.get_height()
# Initialize and interactive window
window = pygame.display.set_mode((width, height))
# Title of the window created
pygame.display.set_caption('Racing Game!')
main_font = pygame.font.SysFont('comicsans', 30)
# frames per seconds
fps = 60
# Computer cars path on the window
computers_path = [(166, 104), (105, 67), (51, 129), (61, 455), (316, 691), (382, 636),
(396, 484), (483, 452), (568, 520), (581, 673), (693, 663), (693, 367),
(607, 336), (388, 321), (408, 238), (658, 241), (698, 102), (560, 71),
(288, 71), (260, 356), (170, 367), (178, 260)]
class GameInfo:
# maximum levels in the game
levels = 10
def __init__(self, level=1):
# current game level
self.level = level
# State of the game(not started)
self.started = False
# initialize games timer
self.level_start_time = 0
def next_level(self):
"""This method is used to advance to the next level of the game.
It increments each level by 1. It sets the current state of the game
as not started to indicate the next level of the game will begin soon """
# increase level by 1
self.level += 1
self.started = False
def reset_level(self):
"""This method resets the level of the game back to level 1.
It sets the games state as not started
as well as resets the games timer."""
self.level = 1
self.started = False
self.level_start_time = 0
def game_finished(self):
"""This method checks if the game is completed.
This occurs when the game exceeds level 10.
If the game level is not completed,
the function will return false. Else it will be true"""
return self.level > self.levels
def start_level(self):
"""This method starts the current level of the game
as well as start a timer used to calculate
how long each level took to complete. """
# Start the game
self.started = True
# Start the games timer
self.level_start_time = time.time()
def get_level_time(self):
"""This method calculates the time difference between
when the game started to when it ended.If the timer has not started,
the function will return a time of 0."""
if not self.started:
return 0
return round(time.time() - self.level_start_time)
class AbstractCar:
""" This parent class contains attributes that will be used by both cars."""
# initialize class variable red car
car_image = red_car
# position class variable
start_position = (0, 0)
def __init__(self, max_velocity, delta_angle):
# image of the car
self.img = self.car_image
self.max_velocity = max_velocity
# initial velocity
self.velocity = 0
# change in angle of the player car when changing directions
self.delta_angle = delta_angle
# initial angle
self.angle = 0
# initial x and y coordinates of the car
self.x, self.y = self.start_position
# increase velocity by this value
self.acceleration = 0.1
def rotate(self, left=False, right=False):
"""Change the angle of the car depending on if it moves left or right from its initial position.
Angle will either increase or decrease depending on if the car moves left or right"""
if left:
self.angle += self.delta_angle
if right:
self.angle -= self.delta_angle
def draw_car(self, win):
"""Call the blit_rotation_center function from the utils module """
blit_rotation_center(win, self.img, (self.x, self.y), self.angle)
def move_forward(self):
"""Allows Player car to accelerate when the 'w' key is pressed.
The car will increase its velocity everytime the 'w' key is pressed until it reaches it's maximum velocity"""
# Maximum velocity after car has accelerated at rest
self.velocity = min(self.velocity + self.acceleration, self.max_velocity)
self.move()
def move_backwards(self):
"""Allows Player car to accelerate backwards when the 's' key is pressed.
The car will increase its velocity everytime the 's' key is pressed until it reaches it's maximum velocity"""
# Maximum velocity after car has accelerated at rest
self.velocity = max(self.velocity - self.acceleration, -self.max_velocity/2)
self.move()
def move(self):
"""This function is responsible for making player and/or computer car rotate in the proper direction.
It also Ensures the car moves in the correct direction based on its angle and its position in the window.
"""
# initial angle in radians
rads = math.radians(self.angle)
# change in velocity in the vertical direction
vertical = math.cos(rads) * self.velocity
# change in velocity in the horizontal direction
horizontal = math.sin(rads) * self.velocity
# Changes coordinates of the car which ensures the car is moving in the correct direction
self.y -= vertical
self.x -= horizontal
def collide(self, mask, x=0, y=0):
"""This function is used to check if the player or computer car comes in contact with specified surface.
The function returns None if no collision occurred or returns a tuple containing the offset"""
# initialize car mask
car_mask = pygame.mask.from_surface(self.img)
# Change in x and y between calling mask and mask being called
offset = (int(self.x - x), int(self.y - y))
# check if both masks are overlapping each other
point_of_intersection = mask.overlap(car_mask, offset)
# return tuple containing the position(∆x and ∆y) of the collision or None if no collision
return point_of_intersection
def reset_cars(self):
"""This method resets the position of both cars after colliding with the finish line."""
self.x, self.y = self.start_position
self.angle = 0
self.velocity = 0
class PlayerCar(AbstractCar):
"""Player car class inheriting attributes from Abstract car class."""
# initialize class attribute for the player car
car_image = red_car
# starting position of player car
start_position = (180, 200)
def reduce_speed(self):
"""This function slows the car down when the 'w' key is not being pressed """
self.velocity = max(self.velocity - self.acceleration / 2, 0)
# allows car to turn and move during deceleration
self.move()
def bounce(self):
"""This is functions is triggered when the player car comes into contact with the track_border_mask.
The player car will bounce back in the opposite direction with the same speed"""
# change the direction of the player car velocity
self.velocity = -self.velocity
self.move()
class ComputerCar(AbstractCar):
car_image = green_car
start_position = (150, 200)
def __init__(self, max_velocity, delta_angle, path=[]):
super().__init__(max_velocity, delta_angle) # inherent all attributes defined in AbstractCar class
self.path = path # list containing the coordinates the computer car will take
self.current_point = 0 # The index of the targets contained in the path variable
self.velocity = max_velocity
def draw_points(self, win):
red = (255, 0, 0)
for point in self.path:
pygame.draw.circle(win, red, point, 5)
def comp_draw(self, win):
super().draw_car(win)
# self.draw_points(win)
def calculate_angle(self):
"""This function ensures the car is moving to the intended target(assigned coordinate) on the screen.
It does ths by calculating the change in angle between the Computer car and the target.
This points the car in the proper direction thus allowing it to rotate properly when moving on the road """
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.delta_angle, abs(difference_in_angle))
else:
self.angle += min(self.delta_angle, abs(difference_in_angle))
def update_path_point(self):
"""This function allows the Computer car to move to the next target in its path on the window"""
# Check if the car collides with the target
target = self.path[self.current_point]
# create a rectangle object for the car
rect = pygame.Rect(self.x, self.y, self.img.get_width(), self.img.get_height())
# Check if the rectangle around the car collides with a target
if rect.collidepoint(*target):
# Allow the computer car to move to the next target/ coordinate in the path variable
self.current_point += 1
def comp_move(self):
if self.current_point >= len(self.path):
return
self.calculate_angle()
self.update_path_point()
super().move()
def comp_next_level(self, level):
"""This method increases the speed of the computer car after the completion of each level.
It also resets the position of the computer car after each level."""
delta_velocity_of_car = 0.2
self.reset_cars()
self.velocity = self.max_velocity + (level - 1) * delta_velocity_of_car
self.current_point = 0
def draw(win, images, user_car, comp_car, games_information):
"""This function draws images and updates them on the window for all images created main.py"""
for img, pos in images:
win.blit(img, pos)
# initialize the games level
level_text = main_font.render(
f'Level {games_information.level}', 1, (255, 255, 255))
# draw the games level on the window
win.blit(level_text, (10, height - level_text.get_height() - 70))
# initialize the timer
time_text = main_font.render(
f'Time: {games_information.get_level_time()}s', 1, (255, 255, 255))
# draw the timer on the window
win.blit(time_text, (10, height - time_text.get_height() - 40))
# initialize the velocity
velocity_text = main_font.render(f'Vel: {user_car.velocity:.1f}px/s', 1, (255, 255, 255))
# draw the timer on the window
win.blit(velocity_text, (10, height - velocity_text.get_height() - 10))
# draw the cars into the window
user_car.draw_car(win)
comp_car.comp_draw(win)
# show all images you draw on the screen
pygame.display.update()
def move_player(users_car):
"""Contains all the keys accessible to the player car"""
# List containing state off all keys where all elements are True or False
keys = pygame.key.get_pressed()
# State of the car. It is either idle or moving
moved = False
# Check if 'a' key is pressed
if keys[pygame.K_a]:
# rotate the car left
users_car.rotate(left=True)
# Check if 'd' key is pressed
if keys[pygame.K_d]:
# rotate the car right
users_car.rotate(right=True)
# check if 'w' key is pressed
if keys[pygame.K_w]:
# car is moving
moved = True
# move car forward
users_car.move_forward()
# check if 's' key is pressed
if keys[pygame.K_s]:
# car is moving
moved = True
# move car backwards
users_car.move_backwards()
# The car is not moving
if not moved:
users_car.reduce_speed()
def handle_collision(user_car, comp_car, game_info):
"""This function is responsible for handling all the collisions by both the player and the computer car.
This includes collision for the player car between the finish line,the track border and
for the computer car the collision between the finish line and its targets"""
# check if player car is touching track_border_mask
if user_car.collide(track_border_mask) is not None:
user_car.bounce()
comp_finish_poi_collide = comp_car.collide(
finish_mask, *finish_position)
# Check is the computer car collides with the finish line
if comp_finish_poi_collide is not None:
# draw the 'You lost' text on the screen
blit_text_center(window, main_font, 'You lost!')
pygame.display.update()
# Slow the window down
pygame.time.wait(5000)
# Reset the game
game_info.reset_level()
# Reset the position of the cars if true
user_car.reset_cars()
comp_car.reset_cars()
comp_car.comp_move()
user_finish_poi_collide = user_car.collide(finish_mask, *finish_position)
# Check is the player collides with the finish line
if user_finish_poi_collide is not None:
# Check if player car collides with finish line when y coordinate is 0
if user_finish_poi_collide[1] == 0:
user_car.bounce()
else:
# increase the level of the computer car
game_info.next_level()
# reset the position of the cars
user_car.reset_cars()
comp_car.comp_next_level(game_info.level)
# keep the program running unless it is closed
run = True
# initialize clock object
clock = pygame.time.Clock()
# images and their position in the window(order matters)
images_list = [(grass, (0, 0)), (track, (0, 0)),
(finish, finish_position), (track_border, (0, 0))]
# initialize player and computer car object
player_car = PlayerCar(4, 4)
computer_car = ComputerCar(2, 4, computers_path)
# initialize GameInfo() object
game_info = GameInfo()
# keep window running unless closed
while run:
# Regulate from rate to 60 frames per seconds for all users
clock.tick(fps)
# draw images on screen
draw(window, images_list, player_car, computer_car, game_info)
# show game text when the level has not started
while not game_info.started:
# Draw new level game text on screen
blit_text_center(window, main_font, f'Press any key to start level {game_info.level}!')
pygame.display.update()
# check to see if the ser either closes the window or presses a key
for event in pygame.event.get():
# close the window if the user exits the window
if event.type == pygame.QUIT:
pygame.quit()
# if user presses any key down, start the level
if event.type == pygame.KEYDOWN:
game_info.start_level()
# Draw the computer and its path coordinates on the window
computer_car.comp_draw(window)
# close window if the user exits the window
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# if event.type == pygame.MOUSEBUTTONDOWN:
# mouse_pos = pygame.mouse.get_pos()
# computer_car.path.append(mouse_pos)
# Move the player and computer car
move_player(player_car)
computer_car.comp_move()
handle_collision(player_car, computer_car, game_info)
# if player car beats computer car
if game_info.game_finished():
blit_text_center(window, main_font, 'You win')
pygame.time.wait(5000)
game_info.reset_level()
player_car.reset_cars()
computer_car.reset_cars()
# print(computer_car.path)
pygame.quit()