From 44b4849e684ec1f722af8efe9fde08fc6aad5d8e Mon Sep 17 00:00:00 2001 From: jriyyya Date: Sat, 1 Jul 2023 15:16:39 +0000 Subject: [PATCH 01/17] Removed unused variables - There were lots of unused variables in game.py which were decalred in almost every method of BallAndBrick class without being used --- game.py | 83 +-------------------------------------------------------- 1 file changed, 1 insertion(+), 82 deletions(-) diff --git a/game.py b/game.py index 60f8603..50147ef 100644 --- a/game.py +++ b/game.py @@ -105,15 +105,10 @@ def restart_game(): pygame.mixer.music.load("assets/jazz.ogg") pygame.mixer.music.play(-1) screen = pygame.display.get_surface() - brick_w = round((screen.get_width()) / 10.7) - brick_h = round((screen.get_height()) / 32) scroller_w = round((screen.get_width()) / 10.7) scroller_h = round((screen.get_height()) / 40) b_diameter = round((scroller_w) / 3.75) - x_max_scrol = screen.get_width() - scroller_w y_scrol = (screen.get_height() - 10) - scroller_h - 70 - x_max_ball = (screen.get_width() - sx(10)) - b_diameter - y_max_ball = (screen.get_height() - 10) - b_diameter self.lives = 3 self.score = 0 @@ -141,13 +136,6 @@ def brick_make(): screen = pygame.display.get_surface() brick_w = round((screen.get_width()) / 10.7) brick_h = round((screen.get_height()) / 32) - scroller_w = round((screen.get_width()) / 10.7) - scroller_h = round((screen.get_height()) / 40) - b_diameter = round((scroller_w) / 3.75) - x_max_scrol = screen.get_width() - scroller_w - y_scrol = (screen.get_height() - 10) - scroller_h - 70 - x_max_ball = (screen.get_width() - sx(10)) - b_diameter - y_max_ball = (screen.get_height() - 10) - b_diameter brick_start_pos_y = 70 self.bricks_arr = [] @@ -164,15 +152,7 @@ def brick_make(): def draw_bricks(): screen = pygame.display.get_surface() - brick_w = round((screen.get_width()) / 10.7) - brick_h = round((screen.get_height()) / 32) scroller_w = round((screen.get_width()) / 10.7) - scroller_h = round((screen.get_height()) / 40) - b_diameter = round((scroller_w) / 3.75) - x_max_scrol = screen.get_width() - scroller_w - y_scrol = (screen.get_height() - 10) - scroller_h - 70 - x_max_ball = (screen.get_width() - sx(10)) - b_diameter - y_max_ball = (screen.get_height() - 10) - b_diameter if self.shake > pygame.time.get_ticks(): rand = (random() - 0.5) * 6, (random() - 0.5) * 6 @@ -188,15 +168,8 @@ def draw_bricks(): def check_input(): screen = pygame.display.get_surface() - brick_w = round((screen.get_width()) / 10.7) - brick_h = round((screen.get_height()) / 32) scroller_w = round((screen.get_width()) / 10.7) - scroller_h = round((screen.get_height()) / 40) - b_diameter = round((scroller_w) / 3.75) x_max_scrol = screen.get_width() - scroller_w - y_scrol = (screen.get_height() - 10) - scroller_h - 70 - x_max_ball = (screen.get_width() - sx(10)) - b_diameter - y_max_ball = (screen.get_height() - 10) - b_diameter while Gtk.events_pending(): Gtk.main_iteration() keys = pygame.key.get_pressed() @@ -231,13 +204,9 @@ def check_input(): def move_ball(): screen = pygame.display.get_surface() - brick_w = round((screen.get_width()) / 10.7) - brick_h = round((screen.get_height()) / 32) scroller_w = round((screen.get_width()) / 10.7) scroller_h = round((screen.get_height()) / 40) b_diameter = round((scroller_w) / 3.75) - x_max_scrol = screen.get_width() - scroller_w - y_scrol = (screen.get_height() - 10) - scroller_h - 70 x_max_ball = (screen.get_width() - sx(10)) - b_diameter y_max_ball = (screen.get_height() - 10) - b_diameter @@ -260,15 +229,10 @@ def move_ball(): def handle_collisions(): screen = pygame.display.get_surface() - brick_w = round((screen.get_width()) / 10.7) - brick_h = round((screen.get_height()) / 32) scroller_w = round((screen.get_width()) / 10.7) scroller_h = round((screen.get_height()) / 40) b_diameter = round((scroller_w) / 3.75) - x_max_scrol = screen.get_width() - scroller_w y_scrol = (screen.get_height() - 10) - scroller_h - 70 - x_max_ball = (screen.get_width() - sx(10)) - b_diameter - y_max_ball = (screen.get_height() - 10) - b_diameter for brick in self.bricks_arr: if self.ball.colliderect(brick): @@ -302,15 +266,7 @@ def handle_collisions(): def score_lives(): screen = pygame.display.get_surface() - brick_w = round((screen.get_width()) / 10.7) - brick_h = round((screen.get_height()) / 32) - scroller_w = round((screen.get_width()) / 10.7) - scroller_h = round((screen.get_height()) / 40) - b_diameter = round((scroller_w) / 3.75) - x_max_scrol = screen.get_width() - scroller_w - y_scrol = (screen.get_height() - 10) - scroller_h - 70 - x_max_ball = (screen.get_width() - sx(10)) - b_diameter - y_max_ball = (screen.get_height() - 10) - b_diameter + medfont = pygame.font.Font("fonts/comicsansms.ttf", int(sx(30))) font_surface = medfont.render( "Score: " + str(self.score), True, self.brick_col @@ -330,17 +286,6 @@ def score_lives(): ) def text_size(text, color, size): - screen = pygame.display.get_surface() - brick_w = round((screen.get_width()) / 10.7) - brick_h = round((screen.get_height()) / 32) - scroller_w = round((screen.get_width()) / 10.7) - scroller_h = round((screen.get_height()) / 40) - b_diameter = round((scroller_w) / 3.75) - x_max_scrol = screen.get_width() - scroller_w - y_scrol = (screen.get_height() - 10) - scroller_h - 70 - x_max_ball = (screen.get_width() - sx(10)) - b_diameter - y_max_ball = (screen.get_height() - 10) - b_diameter - smallfont = pygame.font.Font("fonts/comicsansms.ttf", int(sx(30))) medfont = pygame.font.Font("fonts/comicsansms.ttf", int(sx(40))) largefont = pygame.font.Font("fonts/comicsansms.ttf", int(sx(70))) @@ -356,15 +301,6 @@ def text_size(text, color, size): def message_to_screen(msg, color, y_displace=100, size="small"): screen = pygame.display.get_surface() scale = screen.get_height() / 900 - brick_w = round((screen.get_width()) / 10.7) - brick_h = round((screen.get_height()) / 32) - scroller_w = round((screen.get_width()) / 10.7) - scroller_h = round((screen.get_height()) / 40) - b_diameter = round((scroller_w) / 3.75) - x_max_scrol = screen.get_width() - scroller_w - y_scrol = (screen.get_height() - 10) - scroller_h - 70 - x_max_ball = (screen.get_width() - sx(10)) - b_diameter - y_max_ball = (screen.get_height() - 10) - b_diameter textSur, textRect = text_size(msg, color, size) textRect.center = ((screen.get_width()) / 2), ( @@ -412,15 +348,6 @@ def paused(): def settings(): screen = pygame.display.get_surface() - brick_w = round((screen.get_width()) / 10.7) - brick_h = round((screen.get_height()) / 32) - scroller_w = round((screen.get_width()) / 10.7) - scroller_h = round((screen.get_height()) / 40) - b_diameter = round((scroller_w) / 3.75) - x_max_scrol = screen.get_width() - scroller_w - y_scrol = (screen.get_height() - 10) - scroller_h - 70 - x_max_ball = (screen.get_width() - sx(10)) - b_diameter - y_max_ball = (screen.get_height() - 10) - b_diameter screen.fill(self.yellow) message_to_screen("Settings", self.black, -400, size="large") message_to_screen("Press N to start a new game", self.black, -300, size="medium") @@ -468,17 +395,9 @@ def settings(): break def gameLoop(): - screen = pygame.display.get_surface() - brick_w = round((screen.get_width()) / 10.7) - brick_h = round((screen.get_height()) / 32) scroller_w = round((screen.get_width()) / 10.7) - scroller_h = round((screen.get_height()) / 40) b_diameter = round((scroller_w) / 3.75) - x_max_scrol = screen.get_width() - scroller_w - y_scrol = (screen.get_height() - 10) - scroller_h - 70 - x_max_ball = (screen.get_width() - sx(10)) - b_diameter - y_max_ball = (screen.get_height() - 10) - b_diameter pygame.display.update() restart_game() From 9cc833226d15de3cbab90f664cbbee2fade1f423 Mon Sep 17 00:00:00 2001 From: jriyyya Date: Sun, 2 Jul 2023 09:48:04 +0000 Subject: [PATCH 02/17] Made a seperate ball class - The class handles movement, drawing and collisions - Having a seperate class for the ball will allow for having multiple balls at once if needed --- ball.py | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 ball.py diff --git a/ball.py b/ball.py new file mode 100644 index 0000000..5eb485e --- /dev/null +++ b/ball.py @@ -0,0 +1,80 @@ +import pygame +from random import random + + +class Ball: + + def __init__(self, position, radius): + self.gameDisplay = pygame.display.get_surface() + + self.radius = radius + self.position = pygame.Vector2(position[0], position[1]) + self.velocity = pygame.Vector2(7, -7) + + self.color = (0, 0, 0) + + def set_velocity(self, velocity): + self.velocity = velocity + + def update(self): + self.position[0] += self.velocity[0] + self.position[1] += self.velocity[1] + + bounce_padding = 10 + + x_min = 0 + bounce_padding + x_max = self.gameDisplay.get_width() - self.radius * 2 - bounce_padding + y_min = 0 + bounce_padding + y_max = self.gameDisplay.get_height() - self.radius * 2 - bounce_padding + + if self.position[0] <= x_min: + self.position[0] = x_min + self.velocity[0] *= -1 + + if self.position[0] >= x_max: + self.position[0] = x_max + self.velocity[0] *= -1 + + if self.position[1] <= y_min: + self.position[1] = y_min + self.velocity[1] *= -1 + + if self.position[1] >= y_max: + self.position[1] = y_max + self.velocity[1] *= -1 + + self.draw() + + def handle_collisions(self, paddle): + ball_rect = pygame.Rect( + self.position[0], + self.position[1], + self.radius * 2, + self.radius * 2, + ) + + if ball_rect.colliderect(paddle): + self.position[1] = paddle.y - self.radius * 2 + self.velocity[1] *= -1 + self.velocity.rotate_ip(random() * 10 - 5) + + def draw(self): + pygame.draw.circle( + self.gameDisplay, + self.color, + ( + int(self.position[0] + self.radius), + int(self.position[1] + self.radius), + ), + int(self.radius), + ) + + def check_collision(self, other_x, other_y, other_width, other_height): + self_rect = pygame.Rect(self.x, self.y, + self.rect.width, + self.rect.height) + other_rect = pygame.Rect(other_x, other_y, + other_width, + other_height) + if self_rect.colliderect(other_rect): + return True From b5f9b4b8b656d465b90de11ac93195a81c365761 Mon Sep 17 00:00:00 2001 From: jriyyya Date: Sun, 2 Jul 2023 10:12:45 +0000 Subject: [PATCH 03/17] Added Bat class in bat.py - made a new class called Bat which encapsulates the scroller functionality. It acts as a bat - It can be moved, it handles drawing and clamps its position inside the screen --- bat.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 bat.py diff --git a/bat.py b/bat.py new file mode 100644 index 0000000..929acb4 --- /dev/null +++ b/bat.py @@ -0,0 +1,32 @@ +import pygame + +class Bat: + + def __init__(self, position, dimensions): + self.gameDisplay = pygame.display.get_surface() + + self.rect = pygame.Rect( + position[0], position[1], dimensions[0], dimensions[1] + ) + + self.position = pygame.Vector2(position[0], position[1]) + self.speed = 12 + + self.color = (0, 0, 0) + + def move(self, direction): + self.rect.x += self.speed * direction # 1-> Right; -1 -> Left + + def update(self): + x_min = 0 + x_max = self.gameDisplay.get_width() - self.rect.width + + if self.rect.x < x_min: + self.rect.x = x_min + if self.rect.x > x_max: + self.rect.x = x_max + + self.draw() + + def draw(self): + pygame.draw.rect(self.gameDisplay, self.color, self.rect) From b1e848f2e28c615cfca1e1dd0ae065428630df77 Mon Sep 17 00:00:00 2001 From: jriyyya Date: Sun, 2 Jul 2023 10:26:43 +0000 Subject: [PATCH 04/17] Added Brick class - as of now only encapsulates static brick functionality, has no collision checks and acts as a rectangle with draw method --- brick.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 brick.py diff --git a/brick.py b/brick.py new file mode 100644 index 0000000..aaa8937 --- /dev/null +++ b/brick.py @@ -0,0 +1,21 @@ +import pygame + +class Brick: + + def __init__(self, position, dimensions): + self.gameDisplay = pygame.display.get_surface() + + self.rect = pygame.Rect( + position[0], position[1], dimensions[0], dimensions[1] + ) + + self.position = pygame.Vector2(position[0], position[1]) + self.speed = 12 + + self.color = (0, 0, 0) + + def update(self): + self.draw() + + def draw(self): + pygame.draw.rect(self.gameDisplay, self.color, self.rect) From 26b6bdb470f3a55aa0be64927b2182ed0138a9ef Mon Sep 17 00:00:00 2001 From: jriyyya Date: Wed, 5 Jul 2023 11:31:43 +0000 Subject: [PATCH 05/17] Add methods to ball.py - added is_lost, set_position - also changed bounce_against --- ball.py | 58 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/ball.py b/ball.py index 5eb485e..15fcf43 100644 --- a/ball.py +++ b/ball.py @@ -14,7 +14,10 @@ def __init__(self, position, radius): self.color = (0, 0, 0) def set_velocity(self, velocity): - self.velocity = velocity + self.velocity = pygame.Vector2(velocity[0], velocity[1]) + + def set_position(self, position): + self.position = pygame.Vector2(position[0], position[1]) def update(self): self.position[0] += self.velocity[0] @@ -25,7 +28,7 @@ def update(self): x_min = 0 + bounce_padding x_max = self.gameDisplay.get_width() - self.radius * 2 - bounce_padding y_min = 0 + bounce_padding - y_max = self.gameDisplay.get_height() - self.radius * 2 - bounce_padding + y_max = self.gameDisplay.get_height() + self.radius * 4 if self.position[0] <= x_min: self.position[0] = x_min @@ -45,18 +48,27 @@ def update(self): self.draw() - def handle_collisions(self, paddle): - ball_rect = pygame.Rect( - self.position[0], - self.position[1], - self.radius * 2, - self.radius * 2, - ) - - if ball_rect.colliderect(paddle): - self.position[1] = paddle.y - self.radius * 2 - self.velocity[1] *= -1 - self.velocity.rotate_ip(random() * 10 - 5) + def is_lost(self): + return self.position.y > self.gameDisplay.get_height() + + def bounce_against(self, rect): + d = self.radius * 2 + overlap_x = max(0, min(rect.right, self.position.x + self.velocity.x) - max(rect.left, self.position.x)) + overlap_y = max(0, min(rect.bottom, self.position.y + self.velocity.y) - max(rect.top, self.position.y)) + + if overlap_x < overlap_y: + if self.velocity.x > 0: + self.position.x = rect.left - d + else: + self.position.x = rect.right + self.velocity.x *= -1 + else: + if self.velocity.y > 0: + self.position.y = rect.top - d + else: + self.position.y = rect.bottom + self.velocity.y *= -1 + self.velocity.rotate_ip(random() * 10 - 5) def draw(self): pygame.draw.circle( @@ -69,12 +81,12 @@ def draw(self): int(self.radius), ) - def check_collision(self, other_x, other_y, other_width, other_height): - self_rect = pygame.Rect(self.x, self.y, - self.rect.width, - self.rect.height) - other_rect = pygame.Rect(other_x, other_y, - other_width, - other_height) - if self_rect.colliderect(other_rect): - return True + def check_collision(self, rect): + ball_rect = pygame.Rect( + self.position[0], + self.position[1], + self.radius * 2, + self.radius * 2, + ) + + return ball_rect.colliderect(rect) From afc73d70240cd763f0b9a2cb72871a381cf381a6 Mon Sep 17 00:00:00 2001 From: jriyyya Date: Wed, 5 Jul 2023 11:33:36 +0000 Subject: [PATCH 06/17] removed speed and position from Brick --- brick.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/brick.py b/brick.py index aaa8937..ddd515d 100644 --- a/brick.py +++ b/brick.py @@ -8,14 +8,16 @@ def __init__(self, position, dimensions): self.rect = pygame.Rect( position[0], position[1], dimensions[0], dimensions[1] ) - - self.position = pygame.Vector2(position[0], position[1]) - self.speed = 12 - + self.color = (0, 0, 0) def update(self): self.draw() - def draw(self): + def draw(self, offset = (0, 0)): + x, y = self.rect.x, self.rect.y + self.rect.x += offset [0] + self.rect.y += offset [1] pygame.draw.rect(self.gameDisplay, self.color, self.rect) + self.rect.x = x + self.rect.y = y \ No newline at end of file From 57434a013b6327f293112278da7d13dbf1c1472a Mon Sep 17 00:00:00 2001 From: jriyyya Date: Wed, 5 Jul 2023 11:38:29 +0000 Subject: [PATCH 07/17] Modified game.py to use the newly created classes - gameLoop has been modified - states are now defined in an enum - balls are now stored in an array this will be helpful if there are multiple balls at the same time in future for eg: with powerups - collision checking and State management logic has changed slightly: --- game.py | 193 +++++++++++++++++++++----------------------------------- 1 file changed, 72 insertions(+), 121 deletions(-) diff --git a/game.py b/game.py index 50147ef..bb283ba 100644 --- a/game.py +++ b/game.py @@ -19,13 +19,17 @@ from random import random -import sys import pygame import gi +from ball import Ball +from bat import Bat +from brick import Brick +from enum import Enum gi.require_version("Gtk", "3.0") from gi.repository import Gtk +State = Enum('State', ['STILL', 'PLAY', 'WON', 'LOST']) class BallAndBrick: def __init__(self): @@ -39,10 +43,6 @@ def __init__(self): self.back_col = (255, 255, 255) self.brick_col = (0, 0, 0) self.scroll_col = (0, 0, 0) - self.ball_still = 0 - self.ball_play = 1 - self.ball_won = 2 - self.ball_game_over = 3 self.clock = pygame.time.Clock() self.pause = False self.shake = 0 @@ -107,25 +107,25 @@ def restart_game(): screen = pygame.display.get_surface() scroller_w = round((screen.get_width()) / 10.7) scroller_h = round((screen.get_height()) / 40) - b_diameter = round((scroller_w) / 3.75) y_scrol = (screen.get_height() - 10) - scroller_h - 70 + self.balls = [] + new_ball() + self.bat = Bat((screen.get_width() / 2, y_scrol), (scroller_w, scroller_h)) + self.lives = 3 self.score = 0 - self.state = self.ball_still - - self.paddle = pygame.Rect( - int(screen.get_width() / 2), y_scrol, scroller_w, scroller_h - ) - self.ball = pygame.Rect( - int(screen.get_width() / 2), - y_scrol - b_diameter, - b_diameter, - b_diameter, - ) + self.state = State.STILL brick_make() + def new_ball(): + scroller_w = round((screen.get_width()) / 10.7) + scroller_h = round((screen.get_height()) / 40) + b_diameter = round((scroller_w) / 3.75) + y_scrol = (screen.get_height() - 10) - scroller_h - 70 + self.balls.append(Ball(((screen.get_width() - b_diameter) / 2, y_scrol - b_diameter), b_diameter / 2)) + def sx(x): screen = pygame.display.get_surface() scale = screen.get_width() / 1200 @@ -139,61 +139,49 @@ def brick_make(): brick_start_pos_y = 70 self.bricks_arr = [] - for i in range(7): + for _ in range(7): brick_start_pos_x = (screen.get_width() - (brick_w + sx(10)) * 8) / 2 - for j in range(8): + for _ in range(8): self.bricks_arr.append( - pygame.Rect( - brick_start_pos_x, brick_start_pos_y, brick_w, brick_h - ) + Brick((brick_start_pos_x, brick_start_pos_y), (brick_w, brick_h)) ) brick_start_pos_x += brick_w + sx(10) brick_start_pos_y += brick_h + 5 def draw_bricks(): - screen = pygame.display.get_surface() - scroller_w = round((screen.get_width()) / 10.7) - if self.shake > pygame.time.get_ticks(): rand = (random() - 0.5) * 6, (random() - 0.5) * 6 else: rand = 0, 0 for brick in self.bricks_arr: - pygame.draw.rect( - screen, - self.brick_col, - (brick.x + rand[0], brick.y + rand[1], brick.width, brick.height), - ) + brick.draw(offset = rand) def check_input(): - screen = pygame.display.get_surface() - scroller_w = round((screen.get_width()) / 10.7) - x_max_scrol = screen.get_width() - scroller_w while Gtk.events_pending(): Gtk.main_iteration() keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: - self.paddle.left -= 12 - if self.paddle.left < 0: - self.paddle.left = 0 + self.bat.move(-1) if keys[pygame.K_RIGHT]: - self.paddle.left += 12 - if self.paddle.left > x_max_scrol: - self.paddle.left = x_max_scrol + self.bat.move(1) - if keys[pygame.K_c] and self.state == self.ball_still: + if keys[pygame.K_c] and self.state == State.STILL: if self.score > 150: - self.ball_vel = pygame.Vector2(10, -10) + vel = (10, -10) elif self.score > 100: - self.ball_vel = pygame.Vector2(8, -8) + vel = (8, -8) else: - self.ball_vel = pygame.Vector2(7, -7) - self.state = self.ball_play + vel = (7, -7) + + for ball in self.balls: + ball.set_velocity(vel) + + self.state = State.PLAY elif keys[pygame.K_n] and ( - self.state == self.ball_game_over or self.state == self.ball_won + self.state == State.LOST or self.state == State.WON ): restart_game() elif keys[pygame.K_s]: @@ -202,67 +190,31 @@ def check_input(): pygame.quit() quit() - def move_ball(): - screen = pygame.display.get_surface() - scroller_w = round((screen.get_width()) / 10.7) - scroller_h = round((screen.get_height()) / 40) - b_diameter = round((scroller_w) / 3.75) - x_max_ball = (screen.get_width() - sx(10)) - b_diameter - y_max_ball = (screen.get_height() - 10) - b_diameter - - self.ball.left += self.ball_vel.x - self.ball.top += self.ball_vel.y - - if self.ball.left <= 0: - self.ball.left = 0 - self.ball_vel.x = -self.ball_vel.x - elif self.ball.left >= x_max_ball: - self.ball.left = x_max_ball - self.ball_vel.x = -self.ball_vel.x - - if self.ball.top < 0: - self.ball.top = 0 - self.ball_vel.y = -self.ball_vel.y - elif self.ball.top >= y_max_ball: - self.ball.top = y_max_ball - self.ball_vel.y = -self.ball_vel.y - def handle_collisions(): - screen = pygame.display.get_surface() - scroller_w = round((screen.get_width()) / 10.7) - scroller_h = round((screen.get_height()) / 40) - b_diameter = round((scroller_w) / 3.75) - y_scrol = (screen.get_height() - 10) - scroller_h - 70 - + # Bricks collision for brick in self.bricks_arr: - if self.ball.colliderect(brick): - self.score += 3 - self.bricks_arr.remove(brick) - self.shake = pygame.time.get_ticks() + 200 - dr = abs(self.ball.right - brick.left) - dl = abs(self.ball.left - brick.right) - db = abs(self.ball.bottom - brick.top) - dt = abs(self.ball.top - brick.bottom) - if min(dl, dr) < min(dt, db): - self.ball_vel.x = -self.ball_vel.x - else: - self.ball_vel.y = -self.ball_vel.y - self.ball_vel.rotate_ip(random() * 10 - 5) - break + for ball in self.balls: + if ball.check_collision(brick.rect): + self.score += 3 + self.bricks_arr.remove(brick) + ball.bounce_against(brick.rect) + self.shake = pygame.time.get_ticks() + 200 + break + + # Bat collision + for ball in self.balls: + if ball.check_collision(self.bat.rect) and self.bat.rect.y > ball.position[1]: + ball.bounce_against(self.bat.rect) if len(self.bricks_arr) == 0: - self.state = self.ball_won - - if self.ball.colliderect(self.paddle): - self.ball.top = y_scrol - b_diameter - self.ball_vel.y = -self.ball_vel.y - self.ball_vel.rotate_ip(random() * 10 - 5) - elif self.ball.top > self.paddle.top: + self.state = State.WON + if len(self.balls) == 0: self.lives -= 1 - if self.lives > 0: - self.state = self.ball_still - else: - self.state = self.ball_game_over + new_ball() + self.state = State.STILL + if self.lives == 0: + self.state = State.LOST + def score_lives(): screen = pygame.display.get_surface() @@ -396,8 +348,6 @@ def settings(): def gameLoop(): screen = pygame.display.get_surface() - scroller_w = round((screen.get_width()) / 10.7) - b_diameter = round((scroller_w) / 3.75) pygame.display.update() restart_game() @@ -409,34 +359,34 @@ def gameLoop(): if event.type == pygame.KEYDOWN: if event.key == pygame.K_p: self.pause = True - pause = True paused() self.clock.tick(50) screen.fill(self.back_col) + check_input() draw_bricks() - pygame.draw.rect(screen, self.scroll_col, self.paddle) - pygame.draw.circle( - screen, - self.scroll_col, - ( - self.ball.left + int(b_diameter / 2), - self.ball.top + int(b_diameter / 2), - ), - int(b_diameter / 2), - ) score_lives() - if self.state == self.ball_play: - move_ball() + self.bat.update() + if self.state == State.PLAY: + for ball in self.balls: + ball.update() + if ball.is_lost(): + self.balls.remove(ball) + handle_collisions() - elif self.state == self.ball_still: - self.ball.left = self.paddle.left + self.paddle.width / 2 - self.ball.top = self.paddle.top - self.ball.height + + elif self.state == State.STILL: + for ball in self.balls: + n_x = self.bat.rect.left + self.bat.rect.width / 2 + n_y = self.bat.rect.top - ball.radius * 2 + ball.set_position((n_x, n_y)) + ball.draw() message_to_screen( "Press C to play", self.brick_col, 0, size="large" ) - elif self.state == self.ball_game_over: + + elif self.state == State.LOST: message_to_screen("Game Over", self.brick_col, 50, size="large") message_to_screen( "Press N for New Game", self.brick_col, 150, size="medium" @@ -451,7 +401,8 @@ def gameLoop(): "Press Q to quit", self.brick_col, 290, size="medium" ) pygame.mixer.music.stop() - elif self.state == self.ball_won: + + elif self.state == State.WON: message_to_screen("You Won", self.brick_col, 50, size="large") message_to_screen( "Press N for New Game", self.brick_col, 150, size="medium" From b06dc00826adbc5b91b61121835304f233ddeade Mon Sep 17 00:00:00 2001 From: jriyyya Date: Wed, 5 Jul 2023 12:18:38 +0000 Subject: [PATCH 08/17] Changed units for calculating widht/ height - vw vh get x and y relative to viewport dimensions --- game.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/game.py b/game.py index bb283ba..b9be62f 100644 --- a/game.py +++ b/game.py @@ -101,17 +101,20 @@ def read_file(self, file_path): pass def run(self): + def vw(x): + return (x / 100) * pygame.display.get_surface().get_width() + + def vh(y): + return (y / 100) * pygame.display.get_surface().get_height() + def restart_game(): pygame.mixer.music.load("assets/jazz.ogg") pygame.mixer.music.play(-1) - screen = pygame.display.get_surface() - scroller_w = round((screen.get_width()) / 10.7) - scroller_h = round((screen.get_height()) / 40) - y_scrol = (screen.get_height() - 10) - scroller_h - 70 + self.bat = Bat((vw(50), vh(88)), (vw(11.7), vw(2))) + self.balls = [] new_ball() - self.bat = Bat((screen.get_width() / 2, y_scrol), (scroller_w, scroller_h)) self.lives = 3 self.score = 0 @@ -120,11 +123,8 @@ def restart_game(): brick_make() def new_ball(): - scroller_w = round((screen.get_width()) / 10.7) - scroller_h = round((screen.get_height()) / 40) - b_diameter = round((scroller_w) / 3.75) - y_scrol = (screen.get_height() - 10) - scroller_h - 70 - self.balls.append(Ball(((screen.get_width() - b_diameter) / 2, y_scrol - b_diameter), b_diameter / 2)) + r = vw(1.4) + self.balls.append(Ball((vw(50), vh(88) - r - 3), r)) def sx(x): screen = pygame.display.get_surface() From 44e695d8928581336ac95c7e364dc70ea8e0d968 Mon Sep 17 00:00:00 2001 From: jriyyya Date: Wed, 5 Jul 2023 12:24:11 +0000 Subject: [PATCH 09/17] Added license --- ball.py | 15 +++++++++++++++ bat.py | 15 +++++++++++++++ brick.py | 15 +++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/ball.py b/ball.py index 15fcf43..a056ce7 100644 --- a/ball.py +++ b/ball.py @@ -1,3 +1,18 @@ +# Copyright (C) 2023 Riya Jain +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + import pygame from random import random diff --git a/bat.py b/bat.py index 929acb4..97bc498 100644 --- a/bat.py +++ b/bat.py @@ -1,3 +1,18 @@ +# Copyright (C) 2023 Riya Jain +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + import pygame class Bat: diff --git a/brick.py b/brick.py index ddd515d..2fd28fa 100644 --- a/brick.py +++ b/brick.py @@ -1,3 +1,18 @@ +# Copyright (C) 2023 Riya Jain +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + import pygame class Brick: From adcc57211bc2bde3a3013c392890c60f1e63ff1a Mon Sep 17 00:00:00 2001 From: Riya Jain Date: Tue, 18 Jul 2023 18:19:20 +0000 Subject: [PATCH 10/17] improve readability of a expression in ball.py --- ball.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ball.py b/ball.py index a056ce7..8712676 100644 --- a/ball.py +++ b/ball.py @@ -83,7 +83,7 @@ def bounce_against(self, rect): else: self.position.y = rect.bottom self.velocity.y *= -1 - self.velocity.rotate_ip(random() * 10 - 5) + self.velocity.rotate_ip((random() * 10) - 5) def draw(self): pygame.draw.circle( From e0a2490fa1dba296f2e02506e630ef45e35ceb9e Mon Sep 17 00:00:00 2001 From: Riya Jain Date: Tue, 18 Jul 2023 18:27:54 +0000 Subject: [PATCH 11/17] change variable name from d to diameter --- ball.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ball.py b/ball.py index 8712676..c47f998 100644 --- a/ball.py +++ b/ball.py @@ -67,19 +67,19 @@ def is_lost(self): return self.position.y > self.gameDisplay.get_height() def bounce_against(self, rect): - d = self.radius * 2 + diameter = self.radius * 2 overlap_x = max(0, min(rect.right, self.position.x + self.velocity.x) - max(rect.left, self.position.x)) overlap_y = max(0, min(rect.bottom, self.position.y + self.velocity.y) - max(rect.top, self.position.y)) if overlap_x < overlap_y: if self.velocity.x > 0: - self.position.x = rect.left - d + self.position.x = rect.left - diameter else: self.position.x = rect.right self.velocity.x *= -1 else: if self.velocity.y > 0: - self.position.y = rect.top - d + self.position.y = rect.top - diameter else: self.position.y = rect.bottom self.velocity.y *= -1 From d637d452fa3733b1b6630aac25308a394ad3f13e Mon Sep 17 00:00:00 2001 From: Riya Jain Date: Tue, 18 Jul 2023 18:30:16 +0000 Subject: [PATCH 12/17] remove no new line at EOF warning --- brick.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/brick.py b/brick.py index 2fd28fa..433f699 100644 --- a/brick.py +++ b/brick.py @@ -35,4 +35,4 @@ def draw(self, offset = (0, 0)): self.rect.y += offset [1] pygame.draw.rect(self.gameDisplay, self.color, self.rect) self.rect.x = x - self.rect.y = y \ No newline at end of file + self.rect.y = y From d35e1df93a5fce1762260696d65e9e8c987f7743 Mon Sep 17 00:00:00 2001 From: Riya Jain Date: Tue, 18 Jul 2023 18:33:38 +0000 Subject: [PATCH 13/17] add two line break before first class defination --- game.py | 1 + 1 file changed, 1 insertion(+) diff --git a/game.py b/game.py index b9be62f..9c98ebd 100644 --- a/game.py +++ b/game.py @@ -31,6 +31,7 @@ State = Enum('State', ['STILL', 'PLAY', 'WON', 'LOST']) + class BallAndBrick: def __init__(self): self.green = (34, 139, 34) From 20f6ff48f4c2a135197f16db96263ace0a42ef92 Mon Sep 17 00:00:00 2001 From: Riya Jain Date: Tue, 18 Jul 2023 18:40:20 +0000 Subject: [PATCH 14/17] remove unnecessary line break between conditions --- game.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/game.py b/game.py index 9c98ebd..3bb7d23 100644 --- a/game.py +++ b/game.py @@ -376,7 +376,6 @@ def gameLoop(): self.balls.remove(ball) handle_collisions() - elif self.state == State.STILL: for ball in self.balls: n_x = self.bat.rect.left + self.bat.rect.width / 2 @@ -386,7 +385,6 @@ def gameLoop(): message_to_screen( "Press C to play", self.brick_col, 0, size="large" ) - elif self.state == State.LOST: message_to_screen("Game Over", self.brick_col, 50, size="large") message_to_screen( @@ -402,7 +400,6 @@ def gameLoop(): "Press Q to quit", self.brick_col, 290, size="medium" ) pygame.mixer.music.stop() - elif self.state == State.WON: message_to_screen("You Won", self.brick_col, 50, size="large") message_to_screen( From be9cd5a73e6b971b0cc84efe5797aa0b6add1f4c Mon Sep 17 00:00:00 2001 From: Riya Jain Date: Wed, 19 Jul 2023 14:51:33 +0000 Subject: [PATCH 15/17] Made state declaration to be all caps - as state was a constant, so for convention made it in all caps --- game.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/game.py b/game.py index 3bb7d23..0c5e952 100644 --- a/game.py +++ b/game.py @@ -29,7 +29,7 @@ gi.require_version("Gtk", "3.0") from gi.repository import Gtk -State = Enum('State', ['STILL', 'PLAY', 'WON', 'LOST']) +STATE = Enum('STATE', ['STILL', 'PLAY', 'WON', 'LOST']) class BallAndBrick: @@ -119,7 +119,7 @@ def restart_game(): self.lives = 3 self.score = 0 - self.state = State.STILL + self.state = STATE.STILL brick_make() @@ -169,7 +169,7 @@ def check_input(): if keys[pygame.K_RIGHT]: self.bat.move(1) - if keys[pygame.K_c] and self.state == State.STILL: + if keys[pygame.K_c] and self.state == STATE.STILL: if self.score > 150: vel = (10, -10) elif self.score > 100: @@ -180,9 +180,9 @@ def check_input(): for ball in self.balls: ball.set_velocity(vel) - self.state = State.PLAY + self.state = STATE.PLAY elif keys[pygame.K_n] and ( - self.state == State.LOST or self.state == State.WON + self.state == STATE.LOST or self.state == STATE.WON ): restart_game() elif keys[pygame.K_s]: @@ -208,13 +208,13 @@ def handle_collisions(): ball.bounce_against(self.bat.rect) if len(self.bricks_arr) == 0: - self.state = State.WON + self.state = STATE.WON if len(self.balls) == 0: self.lives -= 1 new_ball() - self.state = State.STILL + self.state = STATE.STILL if self.lives == 0: - self.state = State.LOST + self.state = STATE.LOST def score_lives(): @@ -369,14 +369,14 @@ def gameLoop(): draw_bricks() score_lives() self.bat.update() - if self.state == State.PLAY: + if self.state == STATE.PLAY: for ball in self.balls: ball.update() if ball.is_lost(): self.balls.remove(ball) handle_collisions() - elif self.state == State.STILL: + elif self.state == STATE.STILL: for ball in self.balls: n_x = self.bat.rect.left + self.bat.rect.width / 2 n_y = self.bat.rect.top - ball.radius * 2 @@ -385,7 +385,7 @@ def gameLoop(): message_to_screen( "Press C to play", self.brick_col, 0, size="large" ) - elif self.state == State.LOST: + elif self.state == STATE.LOST: message_to_screen("Game Over", self.brick_col, 50, size="large") message_to_screen( "Press N for New Game", self.brick_col, 150, size="medium" @@ -400,7 +400,7 @@ def gameLoop(): "Press Q to quit", self.brick_col, 290, size="medium" ) pygame.mixer.music.stop() - elif self.state == State.WON: + elif self.state == STATE.WON: message_to_screen("You Won", self.brick_col, 50, size="large") message_to_screen( "Press N for New Game", self.brick_col, 150, size="medium" From 1a10e6eb677e3200aabd3efabb4a467be570a13e Mon Sep 17 00:00:00 2001 From: Riya Jain Date: Wed, 19 Jul 2023 15:04:17 +0000 Subject: [PATCH 16/17] remove space for kwargs --- brick.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/brick.py b/brick.py index 433f699..b7d8bab 100644 --- a/brick.py +++ b/brick.py @@ -29,7 +29,7 @@ def __init__(self, position, dimensions): def update(self): self.draw() - def draw(self, offset = (0, 0)): + def draw(self, offset=(0, 0)): x, y = self.rect.x, self.rect.y self.rect.x += offset [0] self.rect.y += offset [1] From 860901c41c5069cee99cbff21cb268ea9171ddda Mon Sep 17 00:00:00 2001 From: Riya Jain Date: Tue, 25 Jul 2023 12:29:32 +0000 Subject: [PATCH 17/17] Change variable name r to radius --- game.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/game.py b/game.py index 0c5e952..35521dd 100644 --- a/game.py +++ b/game.py @@ -124,8 +124,8 @@ def restart_game(): brick_make() def new_ball(): - r = vw(1.4) - self.balls.append(Ball((vw(50), vh(88) - r - 3), r)) + radius = vw(1.4) + self.balls.append(Ball((vw(50), vh(88) - radius - 3), radius)) def sx(x): screen = pygame.display.get_surface()