ball.py
import pygame as pg
from settings import ball_x_speed, ball_y_speed, ball_radius
class Ball:
def __init__(self, x, y, screen):
self.x = x
self.y = y
self.screen = screen
self.radius = ball_radius
self.color = pg.Color("grey")
self.x_speed = ball_x_speed
self.y_speed = ball_y_speed
def move(self):
pg.draw.circle(self.screen, self.color, [self.x, self.y], self.radius)
self.y -= self.y_speed
self.x -= self.x_speed
def bounce_x(self):
self.x_speed *= -1
def bounce_y(self):
self.y_speed *= -1
def check_for_contact_on_x(self):
if self.x - self.radius <= 0 or self.x + self.radius >= self.screen.get_width():
self.bounce_x()
def check_for_contact_on_y(self):
if self.y + self.radius <= 0:
self.bounce_y()
bricks.py
import random
import pygame as pg
class Bricks:
def __init__(self, screen, width, height):
self.screen = screen
self.width = width
self.height = height
self.random_colors = ['blue', 'yellow', 'red', 'green', 'orange']
self.bricks = []
self.brick_colors = []
self.set_values()
def set_values(self):
y_values = [int(y) for y in range(100, 200, 25)]
x_values = [int(x) for x in range(10, 550, 42)]
y_index = 0
self.loop(x_values, y_values, y_index)
def loop(self, x_values, y_values, y_index):
for n in x_values:
# Check if it is the last position in the x_values list.
if n == x_values[-1]:
# Check if all the positions in the y_values has been occupied
if y_index < len(y_values) - 1:
y_index += 1
# Run the method again if there are still vacant positions.
self.loop(x_values, y_values, y_index)
# Create new bricks
else:
x = n
y = y_values[y_index]
brick = pg.Rect(x, y, self.width, self.height)
self.bricks.append(brick)
self.brick_colors.append(random.choice(self.random_colors))
def show_bricks(self):
for loop in range(len(self.bricks)):
brick = self.bricks[loop]
color = self.brick_colors[loop]
pg.draw.rect(self.screen, color, brick)
main.py
import pygame as pg
from paddle import Paddle
from bricks import Bricks
from ball import Ball
from scores import ScoreBoard
from settings import *
pg.init()
screen = pg.display.set_mode((WIDTH, HEIGHT))
pg.display.set_caption("Breakout Game")
clock = pg.time.Clock()
# OBJECTS
pad = Paddle(paddle_x, paddle_y)
bricks = Bricks(screen, brick_width, brick_height)
ball = Ball(ball_x, ball_y, screen)
score = ScoreBoard(text_x, color, screen)
score.set_high_score()
sound_played = False
running = True
while running:
screen.fill(BG_COLOR)
score.show_scores()
pad.appear(screen)
bricks.show_bricks()
# Check for quit game
for event in pg.event.get():
if event.type == pg.QUIT:
# score.record_high_score()
running = False
# Check if there are more trials
if score.is_game_over():
if not sound_played:
pg.mixer.Sound.play(game_end)
sound_played = True
score.game_over()
# Check if all bricks are broken
elif len(bricks.bricks) <= 0:
if not sound_played:
pg.mixer.Sound.play(win_game)
sound_played = True
score.success()
else:
ball.move()
# Check if ball hits the x-axis above
ball.check_for_contact_on_x()
# Check if ball hits y-axis
ball.check_for_contact_on_y()
# Check if ball falls off
if ball.y + ball.radius >= 580:
pg.mixer.Sound.play(dropping_ball)
ball.y = pad.y - ball.radius
pg.time.delay(2000)
score.trials -= 1
ball.bounce_y()
# Check if ball hits paddle
if (pad.rect.y < ball.y + ball.radius < pad.rect.y + pad.height
and
pad.rect.x < ball.x + ball.radius < pad.rect.x + pad.width):
pg.mixer.Sound.play(pad_hit)
ball.bounce_y()
ball.y = pad.y - ball.radius
# Check if ball hits brick
for brick in bricks.bricks:
if brick.collidepoint(ball.x, ball.y - ball.radius) or brick.collidepoint(ball.x, ball.y + ball.radius):
pg.mixer.Sound.play(brick_breaking)
bricks.bricks.remove(brick)
ball.bounce_y()
score.score += 1
# Check for key presses
keys = pg.key.get_pressed()
if keys[pg.K_RIGHT]:
pad.move_right()
if keys[pg.K_LEFT]:
pad.move_left()
# Restart game
if keys[pg.K_0]:
if score.is_game_over():
score.score = 0
score.trials = 5
score.sound_played = False
bricks.bricks.clear()
bricks.set_values()
pg.display.flip()
clock.tick(60)
paddle.py
import pygame as pg
from settings import paddle_height, paddle_width
class Paddle:
def __init__(self, x, y):
self.x = x
self.y = y
self.width = paddle_width
self.height = paddle_height
self.rect = pg.Rect(self.x, self.y, self.width, self.height)
self.color = pg.Color("white")
def appear(self, screen):
pg.draw.rect(screen, self.color, self.rect)
def move_right(self):
if self.rect.x + self.width <= 550:
self.rect.x += 2
def move_left(self):
if self.rect.x >= 0:
self.rect.x -= 2
scores.py
import pygame as pg
class ScoreBoard:
def __init__(self, x, color, screen):
self.screen = screen
self.color = color
self.x = x
self.score = 0
self.high_score = 0
self.trials = 5
self.font = pg.font.SysFont("calibri", 20)
def show_scores(self):
score_text = self.font.render(f"Score: {self.score}", True, self.color)
high_score_text = self.font.render(f"High Score: {self.high_score}", True, self.color)
trials_text = self.font.render(f"Trials: X{self.trials}", True, self.color)
score_text_rect = score_text.get_rect(topleft=(self.x, 10))
high_score_text_rect = high_score_text.get_rect(topleft=(self.x, 26))
trials_text_rect = trials_text.get_rect(topleft=(self.x, 42))
self.screen.blit(score_text, (self.x, 10))
self.screen.blit(high_score_text, (self.x, 26))
self.screen.blit(trials_text, (self.x, 42))
def is_game_over(self):
if self.trials == 0:
return True
return False
def game_over(self):
game_over_color = 'red'
game_over_font = pg.font.SysFont("calibri", 30)
game_over_text = game_over_font.render(f"Game Over! Click '0' to restart.", True, game_over_color)
game_over_rect = game_over_text.get_rect(topright=(50, 300))
self.screen.blit(game_over_text, (50, 300))
self.record_high_score()
def success(self):
game_success_color = 'green'
game_success_font = pg.font.SysFont("calibri", 30)
game_success_text = game_success_font.render(f"You won! Click '0' to restart.", True, game_success_color)
game_success_rect = game_success_text.get_rect(topleft=(50, 300))
self.screen.blit(game_success_text, (50, 300))
self.record_high_score()
def set_high_score(self):
try:
with open("records.txt", mode="r") as file:
lines = file.readlines()
except FileNotFoundError:
with open("records.txt", mode="w") as data:
data.write("0")
score = 0
else:
score = lines[0]
self.high_score = int(score)
def record_high_score(self):
if self.score > self.high_score:
with open("records.txt", mode="w") as file:
file.write(f"{self.score}")
settings.py
import pygame as pg
# Initialize Sound
pg.mixer.init()
# Audio files
pad_hit = pg.mixer.Sound('audio/pad_hit.ogg')
brick_breaking = pg.mixer.Sound("audio/brick_breaking.ogg")
game_end = pg.mixer.Sound("audio/game_end_.ogg")
dropping_ball = pg.mixer.Sound("audio/dropping_ball.ogg")
win_game = pg.mixer.Sound("audio/win_game.ogg")
# Screen dimensions
WIDTH = 550
HEIGHT = 600
BG_COLOR = "purple"
# Text color
color = "white"
# Paddle settings
paddle_x = 200
paddle_y = 550
paddle_width = 100
paddle_height = 20
# Ball settings
ball_x = 250
ball_y = 540
ball_x_speed = 2
ball_y_speed = 2
ball_radius = 5
# Text settings
text_x = 300
# Bricks settings
brick_width = 40
brick_height = 20