In this article, we will see how to create a spiral sprint game in Python using Pygame. In this game, we will have functionality like difficulty modes, obstacle crashing, speed increment when points are increased, scoreboard, Particle animation, color-changing orbits, coins, and game sounds.
Spiral Sprint Game in Python Using Pygame
Before going any further you will need some resources like sound, assets, and fonts to make the complete game. You can download this from the given link.
File Structure
This is how your repository structure should look in the end after walking through the entire article.
SpiralSprint_Repo_Structure
Step 1: Importing the necessary modules
Install necessary packages by running the following lines in the command prompt and import them to your main.py file:
pip install pygame
pip install time
pip install random
Python3
# Spiral Sprint Gameimport randomimport pygame |
Step 2: Import objects from objects.py to make this game
The main objects that we will be creating are Balls that will revolve in a circular manner, Coins, Obstacle tiles, Particle animation, a Message box, and Buttons. The coding part for the objects.py file is shown in the last part of the article.
Python3
from objects import Balls, Coins, Tiles, Particle, Message, Button |
Step 3: Initialize the Pygame module & Â set the display size values as well as set the caption
- Initialize all the Pygame modules with the help of pygame.init()
- Now set the width and height of the values
- Also adding logic for the screen of small size like if someone tries to run this program in the pydroid mobile app then the game window should not go out of bound
Python3
# initialize pygame and set the display size and alignmentpygame.init()SCREEN = WIDTH, HEIGHT = 288, 512CENTER = WIDTH // 2, HEIGHT // 2info = pygame.display.Info()width = info.current_wheight = info.current_hÂ
if width >= height:Â Â Â Â win = pygame.display.set_mode(SCREEN, pygame.NOFRAME)else:Â Â Â Â win = pygame.display.set_mode(Â Â Â Â Â Â Â Â SCREEN, pygame.NOFRAME | pygame.SCALED | pygame.FULLSCREEN)pygame.display.set_caption('Connected') |
Step 4: Setting  raw UI elements
- Set the default Frames per sec[FPS] of the game as 90. You can tweak it if necessaryÂ
- Now set the color values and create a list of colors. This list of colors will be used in a later part to animate different colors for the revolving ball
- Now set the sound effect for different game scenarios
- Declare the different fonts for different texts to look more curated for that screen
- Now set the captions for different texts
- Now declare button images and use them to make clickable buttons
pygame.image.load() is used for loading the image
Python3
# Set the defaut FPS of the game as 90clock = pygame.time.Clock()FPS = 90Â
# COLORSRED = (255, 0, 0)GREEN = (0, 177, 64)BLUE = (30, 144, 255)ORANGE = (252, 76, 2)YELLOW = (254, 221, 0)PURPLE = (155, 38, 182)AQUA = (0, 103, 127)WHITE = (255, 255, 255)BLACK = (0, 0, 0)GRAY = (25, 25, 25)Â
color_list = [PURPLE, GREEN, BLUE, ORANGE, YELLOW, RED]color_index = 0color = color_list[color_index]Â
# SOUNDSflip_fx = pygame.mixer.Sound('Sounds/flip.mp3')score_fx = pygame.mixer.Sound('Sounds/point.mp3')dead_fx = pygame.mixer.Sound('Sounds/dead.mp3')score_page_fx = pygame.mixer.Sound('Sounds/score_page.mp3')Â
# Now set the sound at transition point of the gamepygame.mixer.music.load('Sounds/bgm.mp3')pygame.mixer.music.play(loops=-1)pygame.mixer.music.set_volume(0.5)Â
# FONTStitle_font = "Fonts/Aladin-Regular.ttf"score_font = "Fonts/DroneflyRegular-K78LA.ttf"game_over_font = "Fonts/ghostclan.ttf"final_score_font = "Fonts/DalelandsUncialBold-82zA.ttf"new_high_font = "Fonts/BubblegumSans-Regular.ttf"Â
# Using different font for differrent texts to look more curated for that screenconnected = Message(WIDTH//2, 120, 55, "Spiral Sprint", title_font, WHITE, win)score_msg = Message(WIDTH//2, 100, 60, "0", score_font, (150, 150, 150), win)game_msg = Message(80, 150, 40, "GAME", game_over_font, BLACK, win)over_msg = Message(210, 150, 40, "OVER!", game_over_font, WHITE, win)final_score = Message(WIDTH//2, HEIGHT//2, 90, "0", final_score_font, RED, win)new_high_msg = Message(WIDTH//2, HEIGHT//2+60, 20,                       "New High", None, GREEN, win)Â
# Declaring Button imageshome_img = pygame.image.load('Assets/homeBtn.png')replay_img = pygame.image.load('Assets/replay.png')sound_off_img = pygame.image.load("Assets/soundOffBtn.png")sound_on_img = pygame.image.load("Assets/soundOnBtn.png")easy_img = pygame.image.load("Assets/easy.jpg")hard_img = pygame.image.load("Assets/hard.jpg")Â
# Buttonseasy_btn = Button(easy_img, (70, 24), WIDTH//4-10, HEIGHT-100)hard_btn = Button(hard_img, (70, 24), WIDTH//2 + 10, HEIGHT-100)home_btn = Button(home_img, (24, 24), WIDTH // 4 - 18, HEIGHT//2 + 120)replay_btn = Button(replay_img, (36, 36), WIDTH // 2 - 18, HEIGHT//2 + 115)sound_btn = Button(sound_on_img, (24, 24), WIDTH -Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â WIDTH // 4 - 18, HEIGHT//2 + 120) |
Step 5: Setting in-game UI elements for the spiral game path for buttonsÂ
- Define the radius of the circle in which the balls should revolve
- With the help of pygame.sprite.Group() we create groups so that the effects we implement get consistent in every part of that group
- Now define the starting position of the revolving balls in the circle of radius 70 i.e  one ball above the diameter that is +x-axis and the second ball below the diameter that is at -x-axis
- Define the time interval at which the obstacle tile should arrive so the user has a scope of dodging
- Declare some bool variables for deciding which screen will be active at which time
Python3
# GroupsRADIUS = 70Â # Defining circle radiusball_group = pygame.sprite.Group()coin_group = pygame.sprite.Group()tile_group = pygame.sprite.Group()particle_group = pygame.sprite.Group()Â
# One ball above the diameter# i.e first and second quadrantball = Balls((CENTER[0], CENTER[1]+RADIUS),             RADIUS, 90, win)ball_group.add(ball)# Second ball below the diameter # i.e third and fourth quadrantball = Balls((CENTER[0], CENTER[1]-RADIUS),             RADIUS, 270, win)ball_group.add(ball)Â
# TIME# Time interval at which the tiles should arive # so the user has a scope of dodgingstart_time = pygame.time.get_ticks()current_time = 0coin_delta = 850tile_delta = 2000Â
# BOOL VARIABLESclicked = Falsenew_coin = Truenum_clicks = 0score = 0Â
player_alive = Truescore = 0highscore = 0sound_on = Trueeasy_level = TrueÂ
home_page = Truegame_page = Falsescore_page = False |
Step 6: Initiate the game logic
- While the game is running(running == True)Â
- Fill the game window with a GRAY color
- Now loop all the current game events with the help of for loop
- If the current game event is quit type if yes then exit the game program and also turn the boolean running as False
- If the event detected is a type of click then make the bool clicked true and perform the operation in the game screen i.e at each click just reverse the direction in which the balls are revolving[Multiply by -1] and also after every 5 clicks change the color of balls and coins from color_list that we declared in the above section[Setting  raw UI elements]Â
Python3
running = True# While the game is runningwhile running:    # Fill the game window with GRAY color    win.fill(GRAY)Â
    for event in pygame.event.get():        if event.type == pygame.QUIT:            running = FalseÂ
        # If the event is quit then off the         # bool running and quit the window        if event.type == pygame.KEYDOWN:            if event.key == pygame.K_ESCAPE or \                    event.key == pygame.K_q:                running = FalseÂ
        # If the event detected is a type of click         # then on the bool clicked and perform that task        if event.type == pygame.MOUSEBUTTONDOWN and game_page:            if not clicked:                clicked = True                # Just reverse their rotation direction                 # when clicked[Multiply by -1]                for ball in ball_group:                    ball.dtheta *= -1                    flip_fx.play()                # change the color of ball ater every                 # 5 click to make it more alive                num_clicks += 1                if num_clicks % 5 == 0:                    color_index += 1                    if color_index > len(color_list) - 1:                        color_index = 0Â
                    color = color_list[color_index]Â
        if event.type == pygame.MOUSEBUTTONDOWN and game_page:            clicked = False |
Step 7: Game home page:
- If there are no events and the home_page boolean is True then that means to show the home page of the game.
- In home_page, show the game name and an animation clip of the game, and two buttons easy and hard for difficulty levels
- If the easy button is clicked then only one ball will revolve i.e with a starting point of 90 degrees and the game window will be initiated.Â
- If the hard button is clicked then two balls will revolve i.e with a starting point of 90 degrees and 270 degrees respectively and the game window will be initiated.
- Once the game is started change the necessary booleans i.e home_page = False, game_page = True, easy_level = True
Python3
# if home_page bool is true that means its # home page so show the game name and an # animation clip of game and two buttons easy and hard  if home_page:      connected.update()Â
      pygame.draw.circle(win, BLACK, CENTER, 80, 20)      ball_group.update(color)      # If easy button is clicked then only       # one ball will revolve start=90degree      if easy_btn.draw(win):          ball_group.empty()          ball = Balls((CENTER[0],                    CENTER[1]+RADIUS), RADIUS, 90, win)          ball_group.add(ball)          # Once the game is started turn           # off the unnecessary booleans          home_page = False          game_page = True          easy_level = True      # If hard button is clicked then two balls       # will revolve start=90degree and       # 270degree respectively      if hard_btn.draw(win):          ball_group.empty()          ball = Balls((CENTER[0],                    CENTER[1]+RADIUS), RADIUS, 90, win)          ball_group.add(ball)          ball = Balls((CENTER[0],                   CENTER[1]-RADIUS), RADIUS, 270, win)          ball_group.add(ball)          # Once the game is started turn off           # the unnecessary booleans          home_page = False          game_page = True          easy_level = False |
Step 8: Game score page
- If there are no events and the score_page boolean is True then that means the game is over and now displays a scoreboard with the home button, replay button, and sound button options for the user
- Also, update the high score if the score is greater than a high score
- If the home button is clicked then draw the home_page window(win) and reset the scoreboard and change the following booleans home_page = True, score_page = False, game_page = False, player_alive = True
- If the replay button is clicked then draw the game_page window(win) and reset the scoreboard and change the following booleans home_page = False, score_page = False, game_page = True
- As soon as the replay button is clicked the user will get two options of difficulty accordingly the spiral orbit and ball count will be triggered in-game
- If the button is pressed on the sound icon then it will toggle between zero sound and master volume sound
Python3
# Update the score_page if its true then that # means the game is over;# So display the scores, home button, replay # button, and sound button options for the userif score_page:Â Â Â Â Â Â Â Â game_msg.update()Â # GAMEÂ Â Â Â Â Â Â Â over_msg.update()Â # OVERÂ
        # Display score if boolean is on else 0        if score:            final_score.update(score, color)        else:            final_score.update("0", color)        # update the highscore if score is         # greater than highscore        if score and (score >= highscore):            new_high_msg.update(shadow=False)Â
        # If home button is clicked then draw the         # home_page window(win) and take care         # of those extra booleans        if home_btn.draw(win):            home_page = True            score_page = False            game_page = False            player_alive = True            score = 0            score_msg = Message(WIDTH//2, 100, 60, "0",                                score_font, (150, 150, 150), win)Â
        # If replay button is clicked then draw the game_page window(win) and take care of those extra booleans        if replay_btn.draw(win):            home_page = False            score_page = False            game_page = True            score = 0            score_msg = Message(WIDTH//2, 100, 60, "0",                          score_font, (150, 150, 150), win)            # In game take easy or hard mode (users choice)            if easy_level:                ball = Balls((CENTER[0],                           CENTER[1]+RADIUS), RADIUS, 90, win)                ball_group.add(ball)            else:                ball = Balls((CENTER[0],                         CENTER[1]+RADIUS), RADIUS, 90, win)                ball_group.add(ball)                ball = Balls((CENTER[0],                         CENTER[1]-RADIUS), RADIUS, 270, win)                ball_group.add(ball)Â
            player_alive = TrueÂ
        # Sound trigger points        if sound_btn.draw(win):            sound_on = not sound_on            # Update the sound button image            if sound_on:                sound_btn.update_image(sound_on_img)                pygame.mixer.music.play(loops=-1)            else:                sound_btn.update_image(sound_off_img)                pygame.mixer.music.stop() |
Step 9: Main game_page
- If there are no events and the game_page boolean is True then that means the user is viewing the main game screen. Thus in game_page draw a spiral orbit, obstacle tiles, balls revolving in orbit, coins, scoreboard, and particle spin-offs
- pygame.draw.circle helps in drawing a circle shape after drawing the orbit now update the following groups ball_group, coin_group, tile_group, and particle_group with color and textÂ
- If the player is alive then the balls, obstacle, and coins movement will initiate
- Now in the ball_group if the ball collides with a coin then increase the score and check whether highscore<= score if yes then update the high score and If the ball gets collided with a tile then player_alive becomes false and triggers dead sound
- Also, keep calculating the time frame of the tiles i.e to create coins after a certain interval of time.
- If current_time – start_time is greater or equal to tile_delta then create a new coin in the obstacle form
- Once the coins are created then mark the new_coin boolean as false
- If the player is dead then the game_page bool will become false and the score_page bool will become true leading to the score page. Apart from booleans, all the groups should be cleared i.e.,ball_group.empty(), tile_group.empty(), coin_group
Python3
# If its game_page then draw circles, tiles, balls, score board       # and particle spin offs   if game_page:        pygame.draw.circle(win, BLACK, CENTER, 80, 20)        ball_group.update(color)        coin_group.update(color)        tile_group.update()        score_msg.update(score)        particle_group.update()        # If player is alive then the balls obstacle         # and coins movement will initiate        if player_alive:            for ball in ball_group:                if pygame.sprite.spritecollide(ball,                                        coin_group, True):                    score_fx.play()                    score += 1                    # Score updation                    if highscore <= score:                        highscore = scoreÂ
                    x, y = ball.rect.center                    for i in range(10):                        particle = Particle(x, y, color, win)                        particle_group.add(particle)                # If ball gets collided with tile                 # then player_alive becomes false                # and trigger dead sound                if pygame.sprite.spritecollide(ball,                                          tile_group, True):                    x, y = ball.rect.center                    for i in range(30):                        particle = Particle(x, y, color, win)                        particle_group.add(particle)Â
                    player_alive = False                    dead_fx.play()            # time frame of game            current_time = pygame.time.get_ticks()            delta = current_time - start_time            # Create obstacle coins and once created             # turn off the boolean            if coin_delta < delta < coin_delta + 100 and new_coin:                y = random.randint(CENTER[1]-RADIUS,                                   CENTER[1]+RADIUS)                coin = Coins(y, win)                coin_group.add(coin)                new_coin = False            # if current_time - start_time is greater            # or equals to tile_delta            # then create new coin in the obstacle form            if current_time - start_time >= tile_delta:                y = random.choice([CENTER[1]-80,                                   CENTER[1], CENTER[1]+80])                type_ = random.randint(1, 3)                t = Tiles(y, type_, win)                tile_group.add(t)Â
                start_time = current_time                new_coin = True        # when player is dead        if not player_alive and len(particle_group) == 0:            score_page = True            game_page = FalseÂ
            score_page_fx.play()Â
            ball_group.empty()            tile_group.empty()            coin_group.empty()    # Game screen    pygame.draw.rect(win, BLUE, (0, 0, WIDTH, HEIGHT),                      5, border_radius=10)    # Screen FPS    clock.tick(FPS)     # updates display    pygame.display.update() |
Step 10: Quitting the program
After all, the operation just quit the program Â
Python3
# Exit game windowpygame.quit() |
Complete objects.py file
In the main.py file, we have used coins, balls, particles, obstacle tiles, and message boxes extensively. So let’s create them before running the main program otherwise it will cause an error.
We will be creating five classes named Balls, Coins, Tiles, Particles, Message, and Button.
Python3
# Let's create some class objectimport pygameimport randomimport mathÂ
SCREEN = WIDTH, HEIGHT = 288, 512CENTER = WIDTH // 2, HEIGHT // 2Â
pygame.font.init()pygame.mixer.init()Â
# A class ball which takes initial pos, size,# angle, window, and shapeÂ
Â
class Balls(pygame.sprite.Sprite):Â Â Â Â def __init__(self, pos, radius, angle, win):Â Â Â Â Â Â Â Â super(Balls, self).__init__()Â
        self.initial_pos = pos        self.radius = radius        self.initial_angle = angle        self.win = win        self.reset()Â
        self.rect = pygame.draw.circle(            self.win, (25, 25, 25),                       (self.x, self.y), 6)    # Update the the balls angle     # [basic math try in rough sheet]Â
    def update(self, color):        x = round(CENTER[0] + self.radius *                  math.cos(self.angle * math.pi / 180))        y = round(CENTER[1] + self.radius *                  math.sin(self.angle * math.pi / 180))Â
        self.angle += self.dthetaÂ
        self.step += 1        if self.step % 5 == 0:            self.pos_list.append((x, y))        if len(self.pos_list) > 5:            self.pos_list.pop(0)Â
        pygame.draw.circle(self.win, (255, 255, 255), (x, y), 7)        self.rect = pygame.draw.circle(self.win, color, (x, y), 6)Â
        for index, pos in enumerate(self.pos_list):            if index < 3:                radius = 1            else:                radius = 2            pygame.draw.circle(self.win, color, pos, radius)    # Reset the positionÂ
    def reset(self):        self.x, self.y = self.initial_pos        self.angle = self.initial_angle        self.dtheta = -2Â
        self.pos_list = []        self.step = 0# Coin takes x & y coord of screen, size, and differential angleÂ
Â
class Coins(pygame.sprite.Sprite):Â Â Â Â def __init__(self, y, win):Â Â Â Â Â Â Â Â super(Coins, self).__init__()Â
        self.y = y        self.win = win        self.size = 15Â
        self.x = WIDTH + 20        self.dx = -1        self.s = 1Â
        self.rect = pygame.draw.rect(            self.win, (255, 255, 255), (self.x, self.y, self.size, self.size))    # Update its movement after every 20pix and swap colorsÂ
    def update(self, color):        self.x += self.dx        if self.x < -20:            self.kill()Â
        pygame.draw.rect(self.win, (200, 200, 200),                         (self.x+self.s, self.y+self.s,                          self.size, self.size))        self.rect = pygame.draw.rect(            self.win, color, (self.x, self.y,                               self.size, self.size))        pygame.draw.circle(self.win, (255, 255, 255),                            self.rect.center, 2)# Tiles that needs to be blocked takes in x & y coords,# angle, type and window sizeÂ
Â
class Tiles(pygame.sprite.Sprite):Â Â Â Â def __init__(self, y, type_, win):Â Â Â Â Â Â Â Â super(Tiles, self).__init__()Â
        self.x = WIDTH+10        self.y = y        self.type = type_        self.win = winÂ
        self.angle = 0        self.dtheta = 0        self.dx = -1Â
        if self.type == 1:            width = 50            height = 20        elif self.type == 2:            width = 20            height = 50        elif self.type == 3:            width = 50            height = 20            self.dtheta = 2Â
        self.image = pygame.Surface((width, height), pygame.SRCALPHA)        pygame.draw.rect(self.image, (255, 255, 255),                     (0, 0, width, height), border_radius=8)        self.rect = self.image.get_rect(center=(self.x, self.y))    # Rotational tile featureÂ
    def rotate(self):        image = pygame.transform.rotozoom(self.image, self.angle, 1)        rect = image.get_rect(center=self.rect.center)Â
        return image, rect    # Update its movementÂ
    def update(self):        self.rect.x += self.dx        if self.rect.right < 0:            self.kill()Â
        self.angle += self.dtheta        image, self.rect = self.rotate()Â
        self.win.blit(image, self.rect)Â
# Small particle spray when the balls gets collided# with tiles takes in x & y coords, color and window sizeÂ
Â
class Particle(pygame.sprite.Sprite):    def __init__(self, x, y, color, win):        super(Particle, self).__init__()        self.x = x        self.y = y        self.color = color        self.win = win        self.size = random.randint(4, 7)        xr = (-3, 3)        yr = (-3, 3)        f = 2        self.life = 40        self.x_vel = random.randrange(xr[0], xr[1]) * f        self.y_vel = random.randrange(yr[0], yr[1]) * f        self.lifetime = 0    # Update its movement in all eight directionÂ
    def update(self):        self.size -= 0.1        self.lifetime += 1        if self.lifetime <= self.life:            self.x += self.x_vel            self.y += self.y_vel            s = int(self.size)            pygame.draw.rect(self.win, self.color, (self.x, self.y, s, s))        else:            self.kill()Â
# Display message class takes in x & y coords, size of text, text ,# font , color of text and window sizeÂ
Â
class Message:    def __init__(self, x, y, size, text, font, color, win):        self.win = win        self.color = color        self.x, self.y = x, y        if not font:            self.font = pygame.font.SysFont("Verdana", size)            anti_alias = True        else:            self.font = pygame.font.Font(font, size)            anti_alias = False        self.image = self.font.render(text, anti_alias, color)        self.rect = self.image.get_rect(center=(x, y))        if self.color == (200, 200, 200):            self.shadow_color = (255, 255, 255)        else:            self.shadow_color = (54, 69, 79)        self.shadow = self.font.render(text, anti_alias, self.shadow_color)        self.shadow_rect = self.image.get_rect(center=(x+2, y+2))Â
    # Update the text according to color and bools    def update(self, text=None, color=None, shadow=True):        if text:            if not color:                color = self.color            self.image = self.font.render(f"{text}", False, color)            self.rect = self.image.get_rect(center=(self.x, self.y))            self.shadow = self.font.render(f"{text}", False, self.shadow_color)            self.shadow_rect = self.image.get_rect(center=(self.x+2, self.y+2))        if shadow:            self.win.blit(self.shadow, self.shadow_rect)        self.win.blit(self.image, self.rect)Â
# Button takes in clickable image , its scale size and x,y coordsÂ
Â
class Button(pygame.sprite.Sprite):Â Â Â Â def __init__(self, img, scale, x, y):Â Â Â Â Â Â Â Â super(Button, self).__init__()Â
        self.scale = scale        self.image = pygame.transform.scale(img, self.scale)        self.rect = self.image.get_rect()        self.rect.x = x        self.rect.y = yÂ
        self.clicked = FalseÂ
    def update_image(self, img):        self.image = pygame.transform.scale(img, self.scale)Â
    def draw(self, win):        action = False        pos = pygame.mouse.get_pos()        if self.rect.collidepoint(pos):            if pygame.mouse.get_pressed()[0] and not self.clicked:                action = True                self.clicked = TrueÂ
            if not pygame.mouse.get_pressed()[0]:                self.clicked = FalseÂ
        win.blit(self.image, self.rect)        return action |
Complete main.py file
Now run the main.py file and the gaming window will pop out.
Python3
# Spiral Sprint Gameimport randomimport pygameÂ
# from objects.py filefrom objects import Balls, Coins, Tiles, Particle, Message, ButtonÂ
# initialize pygame and set the display size and alignmentpygame.init()SCREEN = WIDTH, HEIGHT = 288, 512CENTER = WIDTH // 2, HEIGHT // 2info = pygame.display.Info()width = info.current_wheight = info.current_hÂ
if width >= height:Â Â Â Â win = pygame.display.set_mode(SCREEN, pygame.NOFRAME)else:Â Â Â Â win = pygame.display.set_mode(Â Â Â Â Â Â Â Â SCREEN, pygame.NOFRAME | pygame.SCALED | pygame.FULLSCREEN)pygame.display.set_caption('Connected')Â
# Set the defaut FPS of the game as 90clock = pygame.time.Clock()FPS = 90Â
# COLORSRED = (255, 0, 0)GREEN = (0, 177, 64)BLUE = (30, 144, 255)ORANGE = (252, 76, 2)YELLOW = (254, 221, 0)PURPLE = (155, 38, 182)AQUA = (0, 103, 127)WHITE = (255, 255, 255)BLACK = (0, 0, 0)GRAY = (25, 25, 25)Â
color_list = [PURPLE, GREEN, BLUE, ORANGE, YELLOW, RED]color_index = 0color = color_list[color_index]Â
# SOUNDSflip_fx = pygame.mixer.Sound('Sounds/flip.mp3')score_fx = pygame.mixer.Sound('Sounds/point.mp3')dead_fx = pygame.mixer.Sound('Sounds/dead.mp3')score_page_fx = pygame.mixer.Sound('Sounds/score_page.mp3')Â
# Now set the sound at transition point of the gamepygame.mixer.music.load('Sounds/bgm.mp3')pygame.mixer.music.play(loops=-1)pygame.mixer.music.set_volume(0.5)Â
# FONTStitle_font = "Fonts/Aladin-Regular.ttf"score_font = "Fonts/DroneflyRegular-K78LA.ttf"game_over_font = "Fonts/ghostclan.ttf"final_score_font = "Fonts/DalelandsUncialBold-82zA.ttf"new_high_font = "Fonts/BubblegumSans-Regular.ttf"Â
# Using Different font for differrent texts to look more curated for that screenconnected = Message(WIDTH//2, 120, 55, "Spiral Sprint", title_font, WHITE, win)score_msg = Message(WIDTH//2, 100, 60, "0", score_font, (150, 150, 150), win)game_msg = Message(80, 150, 40, "GAME", game_over_font, BLACK, win)over_msg = Message(210, 150, 40, "OVER!", game_over_font, WHITE, win)final_score = Message(WIDTH//2, HEIGHT//2, 90, "0", final_score_font, RED, win)new_high_msg = Message(WIDTH//2, HEIGHT//2+60, 20,                       "New High", None, GREEN, win)Â
# Declaring Button imageshome_img = pygame.image.load('Assets/homeBtn.png')replay_img = pygame.image.load('Assets/replay.png')sound_off_img = pygame.image.load("Assets/soundOffBtn.png")sound_on_img = pygame.image.load("Assets/soundOnBtn.png")easy_img = pygame.image.load("Assets/easy.jpg")hard_img = pygame.image.load("Assets/hard.jpg")Â
# Buttonseasy_btn = Button(easy_img, (70, 24), WIDTH//4-10, HEIGHT-100)hard_btn = Button(hard_img, (70, 24), WIDTH//2 + 10, HEIGHT-100)home_btn = Button(home_img, (24, 24), WIDTH // 4 - 18, HEIGHT//2 + 120)replay_btn = Button(replay_img, (36, 36), WIDTH // 2 - 18, HEIGHT//2 + 115)sound_btn = Button(sound_on_img, (24, 24), WIDTH -Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â WIDTH // 4 - 18, HEIGHT//2 + 120)Â
# GroupsRADIUS = 70Â # Defining circle radiusball_group = pygame.sprite.Group()coin_group = pygame.sprite.Group()tile_group = pygame.sprite.Group()particle_group = pygame.sprite.Group()Â
# One ball above the diameter i.e first and second quadrantball = Balls((CENTER[0], CENTER[1]+RADIUS), RADIUS, 90, win)ball_group.add(ball)# Second ball below the diameter i.e third and fourth quadrantball = Balls((CENTER[0], CENTER[1]-RADIUS), RADIUS, 270, win)ball_group.add(ball)Â
# TIME# Time interval at which the tiles should arive so the # user has a scope of dodgingstart_time = pygame.time.get_ticks()current_time = 0coin_delta = 850tile_delta = 2000Â
# BOOL VARIABLESclicked = Falsenew_coin = Truenum_clicks = 0score = 0Â
player_alive = Truescore = 0highscore = 0sound_on = Trueeasy_level = TrueÂ
home_page = Truegame_page = Falsescore_page = FalseÂ
running = True# While the game is runningwhile running:    # Fill the game window with GRAY color    win.fill(GRAY)Â
    for event in pygame.event.get():        if event.type == pygame.QUIT:            running = FalseÂ
        # If the event is quit then off the bool         # running and quit the window        if event.type == pygame.KEYDOWN:            if event.key == pygame.K_ESCAPE or \                    event.key == pygame.K_q:                running = FalseÂ
        # If the event detected is a type of click then        # on the bool clicked        # and perform that task        if event.type == pygame.MOUSEBUTTONDOWN and game_page:            if not clicked:                clicked = True                # Just reverse their rotation direction when                # clicked[Multiply by -1]                for ball in ball_group:                    ball.dtheta *= -1                    flip_fx.play()                # change the color of ball ater every 5 click                 # to make it more alive                num_clicks += 1                if num_clicks % 5 == 0:                    color_index += 1                    if color_index > len(color_list) - 1:                        color_index = 0Â
                    color = color_list[color_index]Â
        if event.type == pygame.MOUSEBUTTONDOWN and game_page:            clicked = False    # if home_page bool is true that means its     # home page so show the game name    # and an animation clip of game and     # two buttons easy and hard    if home_page:        connected.update()Â
        pygame.draw.circle(win, BLACK, CENTER, 80, 20)        ball_group.update(color)        # If easy button is clicked then only one ball         # will revolve start=90degree        if easy_btn.draw(win):            ball_group.empty()            ball = Balls((CENTER[0], CENTER[1]+RADIUS),                         RADIUS, 90, win)            ball_group.add(ball)            # Once the game is started turn off             # the unnecessary booleans            home_page = False            game_page = True            easy_level = True        # If hard button is clicked then two balls         # will revolve start=90degree        # and 270degree respectively        if hard_btn.draw(win):            ball_group.empty()            ball = Balls((CENTER[0], CENTER[1]+RADIUS), RADIUS, 90, win)            ball_group.add(ball)            ball = Balls((CENTER[0], CENTER[1]-RADIUS), RADIUS, 270, win)            ball_group.add(ball)            # Once the game is started turn off the unnecessary booleans            home_page = False            game_page = True            easy_level = FalseÂ
    # Update the score_page if its true then that means the game is over;    # So display the scores, home button, replay button, and sound button    # options for the user    if score_page:        game_msg.update() # GAME        over_msg.update() # OVERÂ
        # Display score if boolean is on else 0        if score:            final_score.update(score, color)        else:            final_score.update("0", color)        # update the highscore if score is greater than highscore        if score and (score >= highscore):            new_high_msg.update(shadow=False)Â
        # If home button is clicked then draw the home_page window(win)        # and take care of those extra booleans        if home_btn.draw(win):            home_page = True            score_page = False            game_page = False            player_alive = True            score = 0            score_msg = Message(WIDTH//2, 100, 60, "0",                                score_font, (150, 150, 150), win)Â
        # If replay button is clicked then draw the game_page window(win)        # and take care of those extra booleans        if replay_btn.draw(win):            home_page = False            score_page = False            game_page = True            score = 0            score_msg = Message(WIDTH//2, 100, 60, "0",                                score_font, (150, 150, 150), win)            # In game take easy or hard mode (users choice)            if easy_level:                ball = Balls((CENTER[0], CENTER[1]+RADIUS), RADIUS, 90, win)                ball_group.add(ball)            else:                ball = Balls((CENTER[0], CENTER[1]+RADIUS), RADIUS, 90, win)                ball_group.add(ball)                ball = Balls((CENTER[0], CENTER[1]-RADIUS), RADIUS, 270, win)                ball_group.add(ball)Â
            player_alive = TrueÂ
        # Sound trigger points        if sound_btn.draw(win):            sound_on = not sound_on            # Update the sound button image            if sound_on:                sound_btn.update_image(sound_on_img)                pygame.mixer.music.play(loops=-1)            else:                sound_btn.update_image(sound_off_img)                pygame.mixer.music.stop()    # If its game_page then draw circles, tiles, balls, score board    # and particle spin offs    if game_page:        pygame.draw.circle(win, BLACK, CENTER, 80, 20)        ball_group.update(color)        coin_group.update(color)        tile_group.update()        score_msg.update(score)        particle_group.update()        # If player is alive then the balls obstacle and         # coins movement will initiate        if player_alive:            for ball in ball_group:                if pygame.sprite.spritecollide(ball, coin_group, True):                    score_fx.play()                    score += 1                    # Score updation                    if highscore <= score:                        highscore = scoreÂ
                    x, y = ball.rect.center                    for i in range(10):                        particle = Particle(x, y, color, win)                        particle_group.add(particle)                # If ball gets collided with tile then                 # player_alive becomes false                # and trigger dead sound                if pygame.sprite.spritecollide(ball, tile_group, True):                    x, y = ball.rect.center                    for i in range(30):                        particle = Particle(x, y, color, win)                        particle_group.add(particle)Â
                    player_alive = False                    dead_fx.play()            # time frame of game            current_time = pygame.time.get_ticks()            delta = current_time - start_time            # Create obstacle coins and once created turn off the boolean            if coin_delta < delta < coin_delta + 100 and new_coin:                y = random.randint(CENTER[1]-RADIUS, CENTER[1]+RADIUS)                coin = Coins(y, win)                coin_group.add(coin)                new_coin = False            # if current_time - start_time is greater or equals to tile_delta            # then create new coin in the obstacle form            if current_time - start_time >= tile_delta:                y = random.choice([CENTER[1]-80, CENTER[1], CENTER[1]+80])                type_ = random.randint(1, 3)                t = Tiles(y, type_, win)                tile_group.add(t)Â
                start_time = current_time                new_coin = True        # when player is dead        if not player_alive and len(particle_group) == 0:            score_page = True            game_page = FalseÂ
            score_page_fx.play()Â
            ball_group.empty()            tile_group.empty()            coin_group.empty()    # Game screen    pygame.draw.rect(win, BLUE, (0, 0, WIDTH, HEIGHT), 5, border_radius=10)    clock.tick(FPS) # Screen FPS    pygame.display.update() # updates display# Exit game windowpygame.quit() |
Output:
Use a mouse click to play.
