Apple Catcher Game in Python - PyGame Project

apple catcher game in python using PyGame library - PySeek

Introduction

Recently, I build a computer game using my favorite programming language Python. I'm gonna share the knowledge I've gained through making of this game, in this tutorial.

I gave the name of this game - Apple Catcher Game in Python. I've used the PyGame library to manage, Sounds, Graphics, Animation of this game.

With the pygame library, handling different tasks is easy like drawing on the screen. For your convenience, I divided the project into different program files instead of creating in just one.

While making this game you'll learn how to manage a large project that spans in multiple files. So, tight yourself with your chair and continue reading until the end.

☛Visit AlsoCreate a Snake Game in Python using Turtle Module

How does the game work?

The game is very easy to play. There will be a basket at the bottom of the window. We need to move it using the left and right arrow keys. Apples drop randomly from the top, and we have to catch them in the basket. 

Players will have three chances to miss the apple. If it is more than that, the game will be over.

Table Of Content

  • 1. The Project Details
  • 2. Requirements
  • 3. Starting the Game Project
    • 3.1. The main program
    • 3.2. All the Settings
    • 3.3. The Basket
    • 3.4. The Apple
    • 3.5. The Game Statistics
    • 3.6. The Button
    • 3.7. Add some Sound Effects to Our Game
    • 3.8. The Scoring
  • 4. Download the Code
  • 5. Summary

1. The Project Details

The project file contains two folders and eight Python Program files. Here is the hierarchy of the project file.

  • Apple_Catcher
    • Images
      • apple.bmp
      • basket.bmp
      • background.png
    • Sounds
      • bg_sound.mp3
      • apple_dropped.mp3
      • apple_catched.mp3
      • game_over.mp3
    • main.py
    • settings.py
    • basket.py
    • apple.py
    • game_stats.py
    • button.py
    • sounds.py
    • scoreboard.py
A Smiley Apple

'Apple_Catcher' is the main project folder. 'Images' and 'Sounds' are two folders containing several images and sound effects used in the game. The rest are python files. You may already have understood by watching the names of the files for which they are intended.

In order for this game to run properly, the original folder must contain all the folders and program files. Otherwise, you will not be able to play it.

Before you start coding let's have a look at what should you have installed in your System.

2. Requirements

Use pip3 instead of pip for Linux.

☛Install pygame: pip install pygame

3. Starting the Game Project

Since the game is spanned into several program files or modules, You've to place all those into the main folder. Instead of doing so, you can also download the zip file of the project through the Download button given at the end. It's Your Choice.

Apple Catcher Game has been started, the apples are dropping from the above, and a basket is catching them.
Image - Game Window

3.1. The main program

This is the driver program. It controls the animation, sounds, graphics, and logic of this game. Also, others necessary modules have been imported here.

main.py


import pygame as pg
import sys
from apple import Apple
from settings import Settings
from basket import Basket
from game_stats import GameStats
from button import Button
from scoreboard import Scoreboard
from sounds import Music

class AppleCatcher:
def __init__(self):
pg.init()

self.settings = Settings()
self.screen = pg.display.set_mode((self.settings.screen_width, \
self.settings.screen_height), self.settings.flag)
pg.display.set_caption('Apple Catcher')

# Background Window Image
self.background = pg.image.load('Images/background.png')

self.music = Music()

self.stats = GameStats(self)
self.sb = Scoreboard(self)
self.basket = Basket(self)
self.apples = pg.sprite.Group()
# Make the Play button
self.play_button = Button(self, "Play")

# Getting the Screen's Rectangular
self.screen_rect = self.screen.get_rect()


def run_game(self):
while True:
self._check_events()
if self.stats.game_active:
self.basket.update()
self._drop_apples()
self.apples.update()
self._check_apples_bottom()
self._update_apples()
self._update_screen()


def check_for_level_up(self):
# The game level up when the scores reach multiple of 20.
if self.stats.score!=0 and self.stats.score%20 == 0:
self.settings.increase_speed()
# Increase Level
self.stats.level += 1
self.sb.prep_level()


def _update_apples(self):
'''If a apple crosses the window, it disappears'''
for apple in self.apples.copy():
if apple.rect.bottom >= self.screen_rect.bottom:
self.apples.remove(apple)
self._check_basket_apple_collisions()


def _check_basket_apple_collisions(self):
'''If the basket and a apple collide, add a point.'''
collisions = pg.sprite.spritecollide(self.basket, self.apples, True)
if collisions:
# If collision detected add a point
self.stats.score += self.settings.apple_points
self.check_for_level_up()
self.music.apple_catched.play()
self.sb.prep_score()


def _check_apples_bottom(self):
'''It checks if the apple crosses the screen bottom'''
screen_rect = self.screen.get_rect()
for apple in self.apples.sprites():
if apple.rect.bottom >= screen_rect.bottom:
self._apple_hit()
break


def _apple_hit(self):
'''It checks the remaining chances to miss the apple
from being catched and play the drop sound. If chances over, it
plays a 'game over' sound.'''
if self.stats.apples_left > 0:
self.stats.apples_left -= 1
self.music.apple_droped.play()
self.sb.prep_apples()
else:
self.music.game_over.play()
self.stats.game_active = False
pg.mouse.set_visible(True)
self.music.bg_music.stop()


def _drop_apples(self):
'''Drop apples from the top, randomly'''
if len(self.apples) == 0:
new_apple = Apple(self)
self.apples.add(new_apple)
if len(self.apples) == 1:
for apple in self.apples.sprites():
if apple.rect.bottom > 300:
new_apple = Apple(self)
self.apples.add(new_apple)
if len(self.apples) == 2:
for apple in self.apples.sprites():
if apple.rect.bottom > 600:
new_apple = Apple(self)
self.apples.add(new_apple)
if len(self.apples) == 3:
for apple in self.apples.sprites():
if apple.rect.bottom > 900:
new_apple = Apple(self)
self.apples.add(new_apple)


def _check_play_button(self, mouse_pos):
"""Start a new game when the player clicks Play."""
button_clicked = self.play_button.rect.collidepoint(mouse_pos)
if button_clicked and not self.stats.game_active:
self.settings.initialize_dynamic_settings()
# Reset the game statistics.
self.stats.reset_stats()
self.stats.game_active = True
# Play the Background Music
self.music.bg_music.play()

self.sb.prep_score()
self.sb.prep_apples()
self.sb.prep_level()
# Get rid of any remaining apples
self.apples.empty()
# Hide the mouse cursor
pg.mouse.set_visible(False)


def _check_events(self):
"""Respond to keypresses and mouse events."""
for event in pg.event.get():
if event.type == pg.QUIT:
sys.exit()
elif event.type == pg.MOUSEBUTTONDOWN:
mouse_pos = pg.mouse.get_pos()
self._check_play_button(mouse_pos)
elif event.type == pg.KEYDOWN:
self._check_keydown_events(event)
elif event.type == pg.KEYUP:
self._check_keyup_events(event)


def _check_keydown_events(self, event):
"""Respond to keypresses."""
if event.key == pg.K_RIGHT:
self.basket.moving_right = True
elif event.key == pg.K_LEFT:
self.basket.moving_left = True
elif event.key == pg.K_SPACE:
self._drop_apples()


def _check_keyup_events(self, event):
"""Respond to key releases."""
if event.key == pg.K_RIGHT:
self.basket.moving_right = False
elif event.key == pg.K_LEFT:
self.basket.moving_left = False


def _update_screen(self):
"""Update images on the screen, and flip to the new screen."""
self.screen.blit(self.background, (0,0))
self.basket.blitme()

for apple in self.apples.sprites():
apple.blitme()

# Draw the score information.
self.sb.show_score()
# Draw the play button if the game is inactive.
if not self.stats.game_active:
self.play_button.draw_button()

pg.display.flip()


if __name__ == '__main__':
ec = AppleCatcher()
ec.run_game()

3.2. All the Settings

Let's write a module called 'settings' that contains a class named 'Settings' to store all the values in one place. For example, the screen width, height, background color, basket speed, apple drop speed, etc are defined here.

Game Settings

settings.py


import pygame as pg

class Settings:
def __init__(self):
screen_info = pg.display.Info()
self.screen_width = screen_info.current_w
self.screen_height = screen_info.current_h
self.bg_color = (230, 230, 230)
self.flag = pg.RESIZABLE

# Initialize static settings
self.apples_allowed = 3
self.apple_limit = 3
self.game_over = False

# Scoring
self.apple_points = 2

# Levelup Scale
self.levelup_scale = 1.1

self.initialize_dynamic_settings()

def initialize_dynamic_settings(self):
self.basket_speed = 1
self.apple_drop_speed = 0.5

def increase_speed(self):
self.basket_speed *= self.levelup_scale
self.apple_drop_speed *= self.levelup_scale

3.3. The Basket

Let's add a basket to this game to catch the dropping apples.

A Basket

basket.py


import pygame

class Basket:
'''A class to manage the Basket'''
def __init__(self, ac_game):
'''Initialize the basket and set its starting position.'''
self.screen = ac_game.screen
self.settings = ac_game.settings
self.screen_rect = ac_game.screen.get_rect()

# Load the Basket image
self.image = pygame.image.load('Images/basket.bmp')
self.rect = self.image.get_rect()
self.rect.midbottom = self.screen_rect.midbottom

# Store the decimal value for the basket's horizontal position.
self.x = float(self.rect.x)

# Movement flag
self.moving_right = False
self.moving_left = False

def update(self):
"""Update the basket position based on the movement flag."""
# Update the basket's x value, not the rect.
if self.moving_right and self.rect.right < lt self.screen_rect.right:
self.x += self.settings.basket_speed
if self.moving_left and self.rect.left > 0:
self.x -= self.settings.basket_speed

# Update rect object from self.x
self.rect.x = self.x

def blitme(self):
"""Draw the basket at its current location"""
self.screen.blit(self.image, self.rect)

3.4. The Apple

We have added a basket successfully. But empty basket is useless; so add apples for it. 

Each apple's behavior is controlled by a class called 'Apple'. Let's declare a separate module for it.

apple.py


import pygame
import random
from pygame.sprite import Sprite

class Apple(Sprite):
'''A class to manage the Apples'''
def __init__(self, ac_game):
'''Initialize the apple and set its starting position.'''
super().__init__()
self.screen = ac_game.screen
self.settings = ac_game.settings
self.screen_rect = ac_game.screen.get_rect()

# Load the Apple Image
self.image = pygame.image.load('Images/apple.bmp')
self.rect = self.image.get_rect()

# Define the location from where the apple will enter
self.rect.x = random.randrange(20, self.screen_rect.right-30)
self.rect.y = 0

# Store the decimal value for the apple's vertical position.
self.y = float(self.rect.y)


def update(self):
self.y += self.settings.apple_drop_speed
self.rect.y = self.y


def blitme(self):
"""Draw the basket at its current location"""
self.screen.blit(self.image, self.rect)

The 'Apple' class inherits from the Sprite, which we imported from pygame.sprite module. Using sprites, you can group related elements in your game and act on all the grouped elements at once.

To create an apple instance, __init__() requires the current instance of 'AppleCatcher' class, and we called super() method to inherit property from Sprite.

3.5. The Game Statistics

You need to reset some statistics each time the player starts a new game. For example, the score, level, game active status, etc. All these variables are need to reset when a new game will start.

To avoid code complexity, declare one 'GameStats' instance for the entire time the game is running. Create a different python module for it with this name, "game_stats".

game_stats.py


class GameStats:
'''Track statistics for Apple Catcher.'''
def __init__(self, ac_game):
self.settings = ac_game.settings
self.game_active = False
self.reset_stats()

def reset_stats(self):
self.apples_left = self.settings.apple_limit
self.score = 0
self.level = 1

3.6. The Button

Now you need to add a play button that appears before the game starts and reappears when the game ends so that the player can play again.

Play Button

button.py


import pygame.font

class Button:
def __init__(self, ac_game, text):
self.screen = ac_game.screen
self.screen_rect = ac_game.screen.get_rect()

# Set the dimensions and properties of the button.
self.width, self.height = 200, 50
self.button_color = (0, 255, 0)

self.text_color = (255, 255, 255)
self.font = pygame.font.SysFont(None, 48)

# Build the button's rect object and center it
self.rect = pygame.Rect(0, 0, self.width, self.height)
self.rect.center = self.screen_rect.center

self._show_text(text)


def _show_text(self, text):
self.text_image = self.font.render(text, True, \
self.text_color, self.button_color)
self.text_image_rect = self.text_image.get_rect()
self.text_image_rect.center = self.rect.center


def draw_button(self):
# Draw blank button and then draw blank message.
self.screen.fill(self.button_color, self.rect)
self.screen.blit(self.text_image, self.text_image_rect)

3.7. Add some Sound Effects to Our Game

You're almost at the end of making this Apple catcher Game. All the things will be looked ideal if you add some sound effects to this game. For example, the background music, apple drop sound, apple catch sound, and the game over sound, etc. 

Create a different module for it and declare a class called 'Music' there.

Add Music

sounds.py


from pygame import mixer

class Music:
def __init__(self):
# Msuics: Used in the Game
self.bg_music = mixer.Sound('Sounds/bg_sound.mp3')
self.apple_droped = mixer.Sound('Sounds/apple_dropped.mp3')
self.apple_catched = mixer.Sound('Sounds/apple_catched.mp3')
self.game_over = mixer.Sound('Sounds/game_over.mp3')

3.8. The Scoring

Now implement a scoring system to track your game's score in real-time that will display the score, level, and the number of remaining apples.

scoreboard.py


import pygame.font
from pygame.sprite import Group

from apple import Apple

class Scoreboard:
def __init__(self, ac_game):
self.ac_game = ac_game
self.screen = ac_game.screen
self.screen_rect = self.screen.get_rect()
self.settings = ac_game.settings
self.stats = ac_game.stats

self.text_color = (30, 30, 30)
self.font = pygame.font.SysFont(None, 48)

self.prep_score()
self.prep_apples()
self.prep_level()

# It Shows the Current Game Level
def prep_level(self):
level_str = str(self.stats.level)
self.level_image = self.font.render(level_str, True,
self.text_color, self.settings.bg_color)
# Position the level below the score.
self.level_rect = self.level_image.get_rect()
self.level_rect.right = self.score_rect.right
self.level_rect.top = self.score_rect.bottom + 10

# It shows the remainning chances to drop the apple again.
def prep_apples(self):
"""Show how many apples are left"""
self.apples = Group()
for apple_number in range(self.stats.apples_left):
apple = Apple(self.ac_game)
apple.rect.x = 10 + apple_number * apple.rect.width
apple.rect.y = 10
self.apples.add(apple)

# It shows the total score at the top right corner of the screen.
def prep_score(self):
score_str = str(self.stats.score)
self.score_image = self.font.render(score_str, True,
self.text_color, self.settings.bg_color)
self.score_rect = self.score_image.get_rect()
self.score_rect.right = self.screen_rect.right - 20
self.score_rect.top = 20

def show_score(self):
"""Draw score to the screen."""
self.screen.blit(self.score_image, self.score_rect)
self.apples.draw(self.screen)
self.screen.blit(self.level_image, self.level_rect)

4. Download the Code

Download the zip file of this project from my GitHub page(https://github.com/subhankar-rakshit) through the Download button.

☛Visit AlsoTic Tac Toe Game in Python (with Artificial Intelligence)

5. Summary

In this tutorial, we build a 2d computer game using the pygame library. We gave a sweet name to this game, "Apple Catcher Game in Python".

The whole project is divided into several modules and each module handles different task of this game.

Do Play this Apple Catcher Game and let me know what you scored. I hope You will enjoy this. 

You can make this game harder by increasing the apple drop speed from the settings.py file. You can also cheat with this game by increasing the basket speed from there. 

Do experiment with this game personally and please share your opinion below.

Thanks for reading!💙 

PySeek

Subhankar Rakshit

Meet Subhankar Rakshit, a Computer Science postgraduate (M.Sc.) and the creator of PySeek. Subhankar is a programmer, specializes in Python language. With a several years of experience under his belt, he has developed a deep understanding of software development. He enjoys writing blogs on various topics related to Computer Science, Python Programming, and Software Development.

Post a Comment (0)
Previous Post Next Post