2
\$\begingroup\$

Here's the code for a Breakout style game I made in Python. I was hoping to see if someone can give me some advice on improving anything.

I have a bug with the collision between the ball and the top bricks/blocks, and I'm still working on that. Since it doesn't follow "code review" I have removed what I said earlier and want to focus on the code in general and not fixing bugs.

The following is from several different files. I wasn't sure if there was a better way of formatting it here.

import time
from turtle import Screen
from paddle import Paddle
from ball import Ball
from brick import Brick
from scoreboard import Scoreboard
import random
screen = Screen()
screen.setup(width=800, height=600)
screen.bgcolor("black")
screen.title("Breakout Remake")
screen.tracer(0)
paddle = Paddle((0, -275))
ball = Ball((random.randint(-300, 300), 0))
scoreboard = Scoreboard()
brick_list = []
x, y = 350, 285
for i in range(0, 4):
 for i in range(0, 9):
 brick_list.append(Brick((x, y)))
 x -= 85
 x = 350
 y -= 25
screen.listen()
screen.onkeypress(paddle.go_left, "Left")
screen.onkeypress(paddle.go_right, "Right")
game_is_on = True
while game_is_on:
 time.sleep(ball.move_speed)
 screen.update()
 ball.move()
 # Detect collision with side wall
 if ball.xcor() > 370 or ball.xcor() < -360:
 ball.bounce_side()
 # Detect collision against top
 if ball.ycor() > 280:
 ball.bounce_top()
 # Detect collision with paddle
 if ball.distance(paddle) < 50 and ball.ycor() <= -260:
 ball.bounce_paddle()
 # Detect paddle miss
 if ball.ycor() < -300:
 scoreboard.display()
 game_is_on = False
 # Detect brick hit
 for brick in brick_list:
 if ball.distance(brick) < 25:
 print(ball.position())
 ball.bounce_brick()
 brick.hideturtle()
 brick_list.remove(brick)
 scoreboard.score += 1
screen.exitonclick() 
from turtle import Turtle
import random
class Ball(Turtle):
 def __init__(self, position):
 super().__init__()
 self.shape("circle")
 self.color("white")
 self.penup()
 self.goto(position)
 self.x_move = -10 * random.choice([-1, 1])
 self.y_move = -10
 self.move_speed = 0.1
 self.speed = 6
 def move(self):
 new_x = self.xcor() + self.x_move
 new_y = self.ycor() + self.y_move
 self.goto(new_x, new_y)
 def bounce_side(self):
 self.x_move *= -1
 def bounce_top(self):
 self.y_move = -abs(self.y_move)
 def bounce_brick(self):
 self.y_move *= -1
 self.x_move *= 1.05
 self.y_move *= 1.05
 def bounce_paddle(self):
 self.y_move = abs(self.y_move)
 # for later use if game restart is implemented
 # def reset_position(self):
 # self.goto((random.randint(-300, 300), 0))
 # self.x_move = -10 * random.choice([-1, 1])
from turtle import Turtle
class Scoreboard(Turtle):
 def __init__(self):
 super().__init__()
 self.score = 0
 with open("data.txt", mode="r") as file:
 self.high_score = int(file.read())
 self.penup()
 self.hideturtle()
 self.color("white")
 self.goto(-200, 0)
 
 def display(self):
 self.write(f"Game Over\nScore: {self.score} | High Score: {self.high_score}", font=("Calibri", 40, "bold"))
from turtle import Turtle
class Brick(Turtle):
 def __init__(self, position):
 super().__init__()
 self.shape("square")
 self.color("white")
 self.shapesize(stretch_wid=1, stretch_len=4)
 self.penup()
 self.goto(position)
from turtle import Turtle
class Paddle(Turtle):
 def __init__(self, position):
 #inherit superclass (Turtle)
 super().__init__()
 self.shape("square")
 self.color("white")
 self.shapesize(stretch_wid=1, stretch_len=6)
 self.penup()
 self.goto(position)
 def go_left(self):
 if self.xcor() >= -320:
 new_x = self.xcor() - 40
 self.goto(new_x, self.ycor())
 def go_right(self):
 if self.xcor() <= 320:
 new_x = self.xcor() + 40
 self.goto(new_x, self.ycor())
asked Jul 12, 2022 at 2:03
\$\endgroup\$
2
  • 1
    \$\begingroup\$ General review of your code is on topic but fixing your collision bug is not \$\endgroup\$ Commented Jul 12, 2022 at 2:24
  • \$\begingroup\$ Okay, sorry. I will remove the collision bug part. I still would like to know about any improvements to be made other than that as the program still works even with the bug. \$\endgroup\$ Commented Jul 12, 2022 at 2:26

1 Answer 1

1
\$\begingroup\$

This nested loop:

for i in range(0, 4):
 for i in range(0, 9):

really shouldn't use the same iteration variable name for both levels - unless, of course, it's _ indicating that they're both unused (which they are). However, this disguises what you're actually iterating over, which is x and y. So it should look something like

for y in range(285, 185, -25):
 for x in range(350, -415, -85):

From your screen = Screen() through your exitonclick(), all of that code should be moved into a main() function. Luckily this is quite easy as your classes hold no references to those variables.

Add type hints such as

def __init__(self, position: tuple[int, int]) -> None:

Rather than -10 * random.choice([-1, 1]) why not just write

random.choice((-10, 10))

data.txt is not a good name for that file; consider instead high_score.txt. Don't open it in r - it will always fail the first time around; instead create it if it doesn't exist:

 with open("high_score.txt", 'a+') as file:
 score_str = file.read()
 if score_str == '':
 self.high_score = 0
 else:
 self.high_score = int(score_str)

And yes, your collision code needs some love. It's not enough to just xcor() on your object to get its centre; you need to calculate the edge of your objects and do the math to see whether they collide.

answered Jul 13, 2022 at 0:51
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.