def main(): """ This program simulates a bouncing ball at (START_X, START_Y) that has VX as x velocity and 0 as y velocity. Each bounce reduces y velocity to REDUCE of itself. """ global times,switch,VY ball=GOval(SIZE,SIZE,x=START_X,y=START_Y) ball.filled= True ball.fill_color='black' window.add(ball) switch = False onmouseclicked(turn_on) while True: pause(DELAY) if switch==True: VY+=GRAVITY ball.move(VX,VY) pause(DELAY) if ball.y>window.height: VY=-REDUCE*VY if ball.x>window.width: ball.x=START_X ball.y=START_Y times +=1 if times>=3: break else: pass
def bouncing(m): global START_X, START_Y, VX, GRAVITY, DELAY, click, Time if Time > 0: # remove the ball at START_X and START_Y window.remove(ball) while click is True: # The ball will not be influenced by click as moving # creating the ball at the next moving place ball2 = GOval(SIZE, SIZE, x=START_X + VX, y=START_Y + GRAVITY) ball2.filled = True window.add(ball2) # the primary down speed gravity = 0 while True: # the process of moving click = False gravity = gravity + GRAVITY ball2.move(VX, gravity) if ball2.y >= window.height: gravity = -gravity gravity = gravity * REDUCE ball2.move(VX, gravity) pause(DELAY) if ball2.x > window.width: break # back to the primary place window.add(ball) # count the time Time -= 1 click = True
def move_function(m): global life, switch # use the variables on the upper side of def main() while life > 0 and switch == 1: # the condition to determine whether the ball can move or not original_ball = window.get_object_at( x=START_X + SIZE / 2, y=START_Y + SIZE / 2) # select the ball at the original position window.remove( original_ball) # remove the ball at the original position life -= 1 # life number minus one switch *= -1 # switch turns off, which let user not operate during the ball moving ball = GOval(SIZE, SIZE, x=START_X, y=START_Y) # create the ball that will move later ball.filled = True # fill the ball with black color window.add(ball) # put the ball that will move later on the window x_speed = VX # control the speed of the ball at x direction y_speed = 0 # control the speed of the ball at y direction height = window.height - START_Y # the height of the ball at the original position while True: y_speed += GRAVITY # speed at y direction will be changed due to the gravity height *= REDUCE # reflecting height will decrease when the ball touches to the ground ball.move(x_speed, y_speed) # give the ball the speeds at x and y direction pause( DELAY ) # give a delay time that human can see the moving of the ball if ball.y >= ( window.height - SIZE ) or ball.y <= height: # the condition that ball will reflect y_speed = -1 * y_speed # the speed of y direction will be changed at every reflection if ball.x >= window.width: # if the ball moves out of the window.width, it will stop window.add( ball, x=START_X, y=START_Y ) # put a ball on the original position that will move next time switch *= -1 # turn on the switch that user can operate break if switch == 1: # break the while loop and ready for the next move (next mouse click) break
class BreakoutGraphics: def __init__(self, ball_radius=BALL_RADIUS, paddle_width=PADDLE_WIDTH, paddle_height=PADDLE_HEIGHT, paddle_offset=PADDLE_OFFSET, brick_rows=BRICK_ROWS, brick_cols=BRICK_COLS, brick_width=BRICK_WIDTH, brick_height=BRICK_HEIGHT, brick_offset=BRICK_OFFSET, brick_spacing=BRICK_SPACING, title='Breakout'): # Create a graphical window, with some extra space. window_width = brick_cols * (brick_width + brick_spacing) - brick_spacing window_height = brick_offset + 2.7 * (brick_rows * (brick_height + brick_spacing) - brick_spacing) self.window = GWindow(width=window_width, height=window_height, title=title) # Create a paddle. self.paddle = GRect(paddle_width, paddle_height) self.paddle.color = 'navy' self.paddle.filled = True self.paddle.fill_color = 'navy' self.window.add(self.paddle, (self.window.width - self.paddle.width) / 2, self.window.height - paddle_offset) # Center a filled ball in the graphical window. self.ball = GOval(ball_radius * 2, ball_radius * 2) self.ball.color = 'navy' self.ball.filled = True self.ball.fill_color = 'navy' self.window.add(self.ball, (self.window.width - self.ball.width) / 2, (self.window.height - self.ball.height) / 2 + 50) # a list dynamically stores four detecting points of the ball self.ball_boundary = [] # Default initial velocity for the ball. self.__dx = random.randint(3, MAX_X_SPEED) self.__dy = INITIAL_Y_SPEED # Initialize our mouse listeners. self.mouse_click = False onmouseclicked(self.start_game) # check accessibility self.is_game_over = False # total numbers of bricks self.total_bricks = brick_rows * brick_cols # bricks storing box self.bricks_box = [] # create a list to store random number, if the same number of brick be removed, a magic accessories will appear. self.accessories_number = [] # create a list to store accessories. self.accessories_box = {} # generate accessories self.blue_acc = GRect(0, 0) # set a score board self.score = 0 self.score_board_label = GLabel(f'scores:{self.score}') # create a heart icon and a list to store these icons. # self.heart_point = [(7.5, 15), (0, 5), (3.75, 0), (7.5, 3), (11.25, 0), (15, 5), (7.5, 15)] self.heart_icon_box = [] # give result label to present end of game self.result_label = GLabel('Game Over or You Win') def dx_getter(self): print(f'this is dx value: {self.__dx}.') def dy_getter(self): print(f'this is dy value: {self.__dy}.') def set_velocity(self): self.__dx = random.randint(1, MAX_X_SPEED) self.__dy = INITIAL_Y_SPEED if random.random() > 0.5: self.__dx = -self.__dx def start_game(self, m): """ The game will triggered by this method once player click the mouse. :param m: mouse position in (x,y) expression. """ if not self.is_game_over: if self.mouse_click: print('Game already start.') else: self.mouse_click = True print('Game started') onmousemoved(self.__paddle_move) else: print('There\'s no chance left') def __paddle_move(self, m): """ This method will listen to mouse click, making paddle's position always align to mouse position. :param m: mouse position in (x,y) expression. """ if self.mouse_click: self.paddle.x = m.x - self.paddle.width / 2 if self.paddle.x < 0: self.paddle.x = 0 elif self.paddle.x > self.window.width - self.paddle.width: self.paddle.x = self.window.width - self.paddle.width def ball_move(self, ball_radius=BALL_RADIUS): self.ball.move(self.__dx, self.__dy) if self.ball.x < 0: # right and left boundary of window self.ball.x = 0 self.__dx = -self.__dx elif self.ball.x > self.window.width - ball_radius * 2: # left boundary of window self.ball.x = self.window.width - ball_radius * 2 self.__dx = -self.__dx elif self.ball.y < 0: # top boundary of window self.ball.y = 0 self.__dy = -self.__dy self.__ball_detect_obj() def __ball_detect_obj( self, ball_radius=BALL_RADIUS, brick_width=BRICK_WIDTH, brick_offset=BRICK_OFFSET, brick_spacing=BRICK_SPACING, ): """ The method will detects object around the ball, once it detects a brick, the brick will be removed. Also, depending on the color of brick removed, different accelerate velocity will be adding to the ball. """ self.ball_boundary = [(self.ball.x, self.ball.y), (self.ball.x + ball_radius * 2, self.ball.y), (self.ball.x, self.ball.y + ball_radius * 2), (self.ball.x + ball_radius * 2, self.ball.y + ball_radius * 2)] for i in range(len(self.ball_boundary)): my_obj = self.window.get_object_at(self.ball_boundary[i][0], self.ball_boundary[i][1]) if my_obj in self.bricks_box: # has detected bricks if self.bricks_box.index( my_obj ) in self.accessories_number: # the index of the brick equals accessories number, blue or red blocks will be generated. if self.accessories_number.index( self.bricks_box.index( my_obj)) % 2 == 0: # create blue accessories self.blue_acc = GRect(15, 15) self.blue_acc.filled = True self.blue_acc.fill_color = 'navy' self.accessories_box[self.blue_acc] = 'navy' self.window.add(self.blue_acc, (my_obj.x + my_obj.width / 2), (my_obj.y + my_obj.height / 2)) else: # create blue accessories self.red_acc = GRect(15, 15) self.red_acc.filled = True self.red_acc.fill_color = 'red' self.accessories_box[self.red_acc] = 'red' self.window.add(self.red_acc, (my_obj.x + my_obj.width / 2), (my_obj.y + my_obj.height / 2)) self.__dy = -self.__dy self.window.remove(my_obj) self.total_bricks -= 1 if 80 <= self.bricks_box.index(my_obj): self.__dy *= random.uniform(1.006, 1.02) self.__dx *= random.uniform(1.006, 1.02) self.score += 1 elif 50 <= self.bricks_box.index(my_obj) < 80: self.__dy *= random.uniform(1.004, 1.01) self.__dx *= random.uniform(1.004, 1.01) self.score += 3 elif 20 <= self.bricks_box.index(my_obj) < 50: self.__dy *= random.uniform(1.001, 1.006) self.__dx *= random.uniform(1.001, 1.006) self.score += 5 elif 0 <= self.bricks_box.index(my_obj) < 20: self.__dy *= random.uniform(1.001, 1.003) self.__dx *= random.uniform(1.001, 1.003) self.score += 10 self.score_board_label.text = f'scores:{self.score}' self.window.add(self.score_board_label, brick_width + brick_spacing, brick_offset - 15) return elif my_obj is self.paddle: # has detected the paddle self.__dy = -self.__dy self.ball.y = my_obj.y - ball_radius * 2 # To avoid ball sticking on paddle by reset y-position of the ball. return def accessory_move(self): for key, value in list(self.accessories_box.items()): key.move(2 * self.__dx / abs(self.__dx), random.randint(3, 8)) # accessory blocks move down. obj = self.window.get_object_at((key.x + key.width / 2), (key.y + key.height + 1)) if obj is self.paddle: if value == 'navy': # when paddle get blue block, paddle width increased. self.paddle.width *= 1.4 if self.paddle.width > self.window.width * 0.8: self.paddle.width = self.window.width * 0.8 else: # when paddle get red block, paddle width cut back. self.paddle.width *= 0.5 if self.paddle.width < 50: self.paddle.width = 50 self.window.remove(key) del self.accessories_box[ key] # delete key value pair after the block reaches paddle. self.window.remove(self.paddle) self.window.add(self.paddle, self.paddle.x, self.paddle.y) # renew paddle width to screen. if key.y > self.window.height: # It should be removed if accessory block didn't caught by paddle. self.window.remove(key) del self.accessories_box[key] def reset_ball_paddle(self, paddle_offset=PADDLE_OFFSET): """ When ball is out of button range, the method will reset ball and paddle's position and clear accessories. :param paddle_offset: """ if self.ball.y > self.window.height: print('reset ball and paddle.') self.mouse_click = False # reset mouse state. self.ball.x = (self.window.width - self.ball.width ) / 2 # reset the x-position of ball. self.ball.y = (self.window.height - self.ball.height ) / 2 # reset the y-position of ball. self.paddle.x = (self.window.width - self.paddle.width ) / 2 # reset the x-position of paddle. self.paddle.y = self.window.height - paddle_offset # reset the y-position of paddle. for i in self.accessories_box: # clear all accessories on the window. self.window.remove(i) self.accessories_box.clear() def draw_bricks(self, brick_width=BRICK_WIDTH, brick_height=BRICK_HEIGHT, brick_offset=BRICK_OFFSET, brick_spacing=BRICK_SPACING): """ When player enter game page, this method called by main function, it will displays bricks from left top corner until all bricks displayed. It also give bricks different colors depends on which row the brick exactly occupy. Moreover, at the moment brick generated, it will be store in list in order to be used later. """ for i in range(12): for j in range(10): brick = GRect(brick_width, brick_height, x=(brick_width + brick_spacing) * j, y=brick_offset + (brick_height + brick_spacing) * i) brick.filled = True if i < 2: brick.fill_color = '#204051' self.bricks_box.append(brick) self.window.add(brick) elif 2 <= i < 5: brick.fill_color = '#3b6978' self.bricks_box.append(brick) self.window.add(brick) elif 5 <= i < 8: brick.fill_color = '#84a9ac' self.bricks_box.append(brick) self.window.add(brick) elif 8 <= i < 12: brick.fill_color = '#e4e3e3' self.bricks_box.append(brick) self.window.add(brick) def add_score_board( self, brick_width=BRICK_WIDTH, brick_offset=BRICK_OFFSET, brick_spacing=BRICK_SPACING, ): """ Setting a score board on to left-top screen and align to second column. """ self.score_board_label.font = '-15' self.window.add(self.score_board_label, brick_width + brick_spacing, brick_offset - 15) def add_accessories(self, num): """ This method randomly chose numbers between 0 to numbers of total bricks, and each numbers will not be repeated. :param num: total number of accessories. :return: return self until number of list - self.accessories_number - equals to num. """ if len(self.accessories_number) < num <= len(self.bricks_box): for i in range(num - len(self.accessories_number)): random_number = random.randint(0, len(self.bricks_box)) if not random_number in self.accessories_number: self.accessories_number.append(random_number) return self.add_accessories(num) else: return def show_result_label(self): """ This method shows game result when game finished, it depends on if the player clears all bricks in three game times. """ if self.is_game_over: self.result_label.text = 'Game Over' self.result_label.font = '-40' self.window.add(self.result_label, (self.window.width - self.result_label.width) / 2, (self.window.height - self.result_label.height) * 3 / 4) else: self.result_label.text = 'You Win' self.result_label.color = 'red' self.result_label.font = '-40' self.window.add(self.result_label, (self.window.width - self.result_label.width) / 2, (self.window.height - self.result_label.height) / 2) def draw_heart_icon(self): """ To represent how many NUM_LIVES left onto screen. P.S: I am trying to use GPolygon to create heart shape but it seems to conflict to windows.get_obj_at method. """ self.heart_shape = GOval(15, 15) self.heart_shape.color = 'lightgray' self.heart_shape.filled = True self.heart_shape.fill_color = 'pink' self.heart_icon_box.append(self.heart_shape) return self.heart_shape
class BreakoutGraphics: def __init__(self, ball_radius=BALL_RADIUS, paddle_width=PADDLE_WIDTH, paddle_height=PADDLE_HEIGHT, paddle_offset=PADDLE_OFFSET, brick_rows=BRICK_ROWS, brick_cols=BRICK_COLS, brick_width=BRICK_WIDTH, brick_height=BRICK_HEIGHT, brick_offset=BRICK_OFFSET, brick_spacing=BRICK_SPACING, title='Breakout'): # Create a graphical window, with some extra space. window_width = brick_cols * (brick_width + brick_spacing) - brick_spacing window_height = brick_offset + 3 * (brick_rows * (brick_height + brick_spacing) - brick_spacing) self.__window = GWindow(width=window_width, height=window_height, title=title) # Switch controls whether the game starts. If True, start the game. self.switch = False # Greeting Page involves: bg as background / wd1 as welcome words / wd2 as start bottom # / button as the background of the start button. self.__grt_bg = GRect(self.__window.width, self.__window.height) self.__grt_bg.filled = True self.__grt_bg.fill_color = 'white' self.__grt_bg.color = 'white' # grt_wd: Welcome to BREAKOUT GAME. self.__grt = GLabel('WELCOME\nTO\nBREAKOUT\nGAME') self.__grt_wd1 = GLabel('WELCOME\nTO\nBREAKOUT\nGAME', self.__window.width / 3 - self.__grt.width / 2, self.__window.height / 3) font_size = 18 * self.__window.width / 445 self.__grt_wd1.font = 'Courier-18' # grt_bottom: black rectangle self.__grt_button = GRect( 100, 40, x=self.__window.width / 3 - self.__grt.width / 2, y=self.__window.height * 2 / 3 - self.__grt.height * 2.5) self.__grt_button.filled = True # grt_wd: START! self.__grt_wd2 = GLabel('START!', self.__window.width / 3 - self.__grt.width / 2, self.__window.height * 2 / 3) self.__grt_wd2.font = 'Courier-28' self.__grt_wd2.color = 'white' # Create a paddle to catch the ball and make it bounce. self.__paddle = GRect(paddle_width, paddle_height, y=window_height - paddle_offset) self.__paddle_offset = paddle_offset self.__paddle.filled = True # Center a filled ball in the graphical window. self.__ball = GOval(ball_radius * 2, ball_radius * 2, x=window_width / 2 - ball_radius, y=window_height / 2 - ball_radius) self.__ball.filled = True self.__ball_radius = ball_radius # Default initial velocity for the ball. self.__dx = random.randint(1, MAX_X_SPEED) self.__dy = INITIAL_Y_SPEED # Initialize our mouse listeners. onmousemoved(self.__handle_move) # Draw bricks in rows and columns. self.__brick_width = brick_width self.__brick_height = brick_height self.__brick_spacing = brick_spacing self.__brick_offset = brick_offset self.__brick_rows = brick_rows self.__brick_cols = brick_cols self.__left_bricks = self.__brick_rows * self.__brick_cols # Add the elements(bg / wd1 / button / wd2) to start screen. self.__window.add(self.__grt_bg) self.__window.add(self.__grt_wd1) self.__window.add(self.__grt_button) self.__window.add(self.__grt_wd2) # Scoreboard records the score. self.__scores = 0 self.__scoreboard = GLabel('Score: ' + str(self.__scores), x=0, y=window_height) self.__scoreboard.font = 'Courier-18' # Click on mouse and start game. onmouseclicked(self.start_game) # Set up the start screen of the game in this function. def start_game(self, event): click = self.__window.get_object_at(event.x, event.y) b = self.__grt_button grt = self.__grt_wd2 # While the mouse click on the button, start the game. if click == b or click == grt and b.x <= event.x <= b.x + b.width and b.y <= event.y <= b.y + b.height: self.__window.remove(self.__grt_wd1) # Remove the greeting words. self.__window.remove(self.__grt_wd2) # Remove the greeting words. self.__window.remove(self.__grt_button) # Remove the start button. self.__window.remove( self.__grt_bg) # Remove the greeting background. self.switch = True # Turn on the switch. # Set the ball on the start position, in the middle of the window. self.__window.add( self.__ball, x=self.__window.width / 2 - self.__ball.width / 2, y=self.__window.height / 2 - self.__ball.height / 2) self.__window.add(self.__paddle) # Add the paddle to the window. self.__draw_bricks() # Add the bricks to the window. self.__window.add( self.__scoreboard) # Add the scoreboard to the window. pause(300) # Delay time serving a ball. # Set ball at a random position in certain area, below bricks and above paddle. def set_ball_position(self): self.__ball.x = random.randint(0, self.__window.width - self.__ball.width) self.__ball.y = random.randint( self.__brick_offset + self.__brick_rows * (self.__brick_height + self.__brick_spacing) - self.__brick_spacing, self.__window.height - self.__paddle_offset - self.__paddle.height - self.__ball_radius * 2) pause(500) # Delay serving a ball # Set the ball in random velocity. def set_ball_velocity(self): if random.random() > 0.5: self.__dx = -self.__dx # Determine whether the ball is out of the window. # Leave the window from the bottom edge / return boolean (True) def ball_out(self): if self.__ball.y >= self.__window.height: return True # If the ball is out of bounds, reset 'position' and 'velocity' of ball, and add it to screen. def reset_ball(self): self.set_ball_position() self.set_ball_velocity() self.__window.add(self.__ball) # Move ball as animation in velocity of dx and dy. def move_ball(self): if self.switch: self.__ball.move(self.__dx, self.__dy) # Check whether the ball collides with walls, then bounce back. def wall_collisions(self): # Ball collides with up right edge and left edge. if self.__ball.x <= 0 or self.__ball.x >= self.__window.width - self.__ball.width: self.__dx = -self.__dx # Ball collides with upper edge. if self.__ball.y <= 0: self.__dy = -self.__dy # Check whether the ball collides with paddle or bricks, then bounce back. def check_for_collisions(self): if self.switch: # if the game starts: # Set b1, b2, b3, b4 as four corners of ball. b1 = self.__window.get_object_at(self.__ball.x, self.__ball.y) b2 = self.__window.get_object_at( self.__ball.x + self.__ball_radius * 2, self.__ball.y) b3 = self.__window.get_object_at( self.__ball.x, self.__ball.y + self.__ball_radius * 2) b4 = self.__window.get_object_at( self.__ball.x + self.__ball_radius * 2, self.__ball.y + self.__ball_radius * 2) # Detecting whether four corners of ball collides with: if b1 is not None or b2 is not None or b3 is not None or b4 is not None: # Collides with paddle. if b1 is self.__paddle or b2 is self.__paddle or b3 is self.__paddle or b4 is self.__paddle: # Avoid ball stick to paddle. if self.__ball.y + self.__ball_radius * 2 >= self.__paddle.y: self.__ball.y = self.__paddle.y - self.__ball_radius * 2 self.set_ball_velocity() if self.__dy > 0: self.__dy = -self.__dy # Collides with scoreboard, then pass. elif b1 is self.__scoreboard or b2 is self.__scoreboard or \ b3 is self.__scoreboard or b4 is self.__scoreboard: pass # Collides with brick / remove the brick / bounce back. else: if b1 is not None and b1 is not self.__scoreboard: self.__window.remove( b1) # Remove a brick while colliding with a brick. self.__left_bricks -= 1 # Minus 1 while colliding with a brick. self.__scores += 10 # Add 10 scores while colliding with a brick. elif b2 is not None and b2 is not self.__scoreboard: self.__window.remove( b2) # Remove a brick while colliding with a brick. self.__left_bricks -= 1 # Minus 1 while colliding with a brick. self.__scores += 10 # Add 10 scores while colliding with a brick. elif b3 is not None and b3 is not self.__scoreboard: self.__window.remove( b3) # Remove a brick while colliding with a brick. self.__left_bricks -= 1 # Minus 1 while colliding with a brick. self.__scores += 10 # Add 10 scores while colliding with a brick. elif b4 is not None and b4 is not self.__scoreboard: self.__window.remove( b4) # Remove a brick while colliding with a brick. self.__left_bricks -= 1 # Minus 1 while colliding with a brick. self.__scores += 10 # Add 10 scores while colliding with a brick. self.__scoreboard.text = 'Score: ' + str( self.__scores) # Refresh score to scoreboard self.set_ball_velocity() # Reset x velocity of ball. self.__dy = -self.__dy # Reset y velocity of ball. # Draw bricks. def __draw_bricks(self): for i in range(self.__brick_rows): for j in range(self.__brick_cols): br1 = GRect(self.__brick_width, self.__brick_height) br1.filled = True br1.x = (self.__brick_width + self.__brick_spacing) * j br1.y = self.__brick_offset + (self.__brick_height + self.__brick_spacing) * i rows_in_sec = self.__brick_rows / BRICK_SECTION if i <= rows_in_sec - 1: # Section 1 br1.fill_color = 'red' br1.color = 'red' elif rows_in_sec - 1 < i <= rows_in_sec * 2 - 1: # Section 2 br1.fill_color = 'orange' br1.color = 'orange' elif rows_in_sec * 2 - 1 < i <= rows_in_sec * 3 - 1: # Section 3 br1.fill_color = 'yellow' br1.color = 'yellow' elif rows_in_sec * 3 - 1 < i <= rows_in_sec * 4 - 1: # Section 4 br1.fill_color = 'green' br1.color = 'green' else: # Section 5 and so on. br1.fill_color = 'lightseagreen' br1.color = 'lightseagreen' self.__window.add(br1) # Handle the movement of paddle with mouse move. def __handle_move(self, event): if event.x < self.__paddle.width / 2: self.__paddle.x = 0 elif event.x > self.__window.width - self.__paddle.width / 2: self.__paddle.x = self.__window.width - self.__paddle.width else: self.__paddle.x = event.x - self.__paddle.width / 2 # If lives <= 0, then game over. def game_over(self): g_over = GLabel('GAME OVER!') g_over.font = 'Courier-25' g_over = GLabel('GAME OVER!', self.__window.width / 2 - g_over.width / 2, self.__window.height / 2) g_over.font = 'Courier-25' self.__window.add(g_over) # If the bricks are all removed, you win the game. def win_game(self): if self.__left_bricks <= 0: you_win = GLabel('YOU WIN!') you_win.font = 'Courier-25' you_win = GLabel('YOU WIN!', self.__window.width / 2 - you_win.width / 2, self.__window.height / 2) you_win.font = 'Courier-25' self.__window.add(you_win) return True
class BreakoutGraphics: def __init__(self, ball_radius=BALL_RADIUS, paddle_width=PADDLE_WIDTH, paddle_height=PADDLE_HEIGHT, paddle_offset=PADDLE_OFFSET, brick_rows=BRICK_ROWS, brick_cols=BRICK_COLS, brick_width=BRICK_WIDTH, brick_height=BRICK_HEIGHT, brick_offset=BRICK_OFFSET, brick_spacing=BRICK_SPACING, title='Breakout'): # Create a graphical window, with some extra space. self.window_width = brick_cols * (brick_width + brick_spacing) - brick_spacing self.window_height = brick_offset + 3 * ( brick_rows * (brick_height + brick_spacing) - brick_spacing) self.window = GWindow(width=self.window_width, height=self.window_height, title=title) # Create a paddle. self.pw = paddle_width self.ph = paddle_height self.paddle = GRect(self.pw, self.ph, x=(self.window_width - self.pw) / 2, y=self.window_height - paddle_offset) self.paddle.filled = True self.window.add(self.paddle) # Center a filled ball in the graphical window. self.bra = ball_radius * 2 self.ball = GOval(self.bra, self.bra) self.ball.filled = True self.window.add(self.ball, (self.window_width - self.bra) / 2, (self.window_height - self.bra) / 2) # Default initial velocity for the ball. self.__dx = 0 self.__dy = 0 # Initialize our mouse listeners. onmousemoved(self.paddle_move) onmouseclicked(self.ball_move) # Draw bricks. self.build_bricks() self.score = 0 self.score_text = GLabel('Score: ' + str(self.score)) self.score_text.font = '-15-bold' self.window.add(self.score_text, 0, self.window_height) self.lives_text = GLabel('Lives: ' + str(3)) self.lives_text.font = '-15-bold' self.window.add(self.lives_text, self.window_width - 80, self.window_height) def build_bricks(self): """ :return: Build bricks """ self.br = BRICK_ROWS self.bc = BRICK_COLS for i in range(self.br): for j in range(self.bc): self.bricks = GRect(BRICK_WIDTH, BRICK_HEIGHT, x=i * (BRICK_WIDTH + BRICK_SPACING), y=j * (BRICK_HEIGHT + BRICK_SPACING)) self.bricks.filled = True if j < 5: self.bricks.fill_color = 'red' else: self.bricks.fill_color = 'blue' self.window.add(self.bricks) def paddle_move(self, e): """ :param e: Mouse position :return: Only change the X-axis position of the mouse """ if self.pw / 2 < e.x < self.window_width - self.pw / 2: self.paddle.x = e.x - self.paddle.width / 2 def ball_move(self, e): """ :return: Give the ball x and y speed """ self.__dx = random.randint(1, MAX_X_SPEED) self.__dy = INITIAL_Y_SPEED if (random.random() > 0.5): self.__dx = -(self.__dx) def check(self): """ :return: Determine the state of the ball and other objects """ # Avoid the ball beyond the window if self.ball.x < 0 or self.ball.x > (self.window_width - self.bra): self.__dx *= -1 if self.ball.y < 0 or self.ball.y > (self.window_height - self.bra): self.__dy *= -1 # Record old scores self.old_score = self.score # Set four points as the judgment state maybe_object1 = self.window.get_object_at(self.ball.x, self.ball.y) maybe_object2 = self.window.get_object_at(self.ball.x + self.bra, self.ball.y) maybe_object3 = self.window.get_object_at(self.ball.x, self.ball.y + self.bra) maybe_object4 = self.window.get_object_at(self.ball.x + self.bra, self.ball.y + self.bra) # Judgment points and the status of bricks if maybe_object1 is not self.paddle and maybe_object2 is not self.paddle and \ maybe_object3 is not self.paddle and maybe_object4 is not self.paddle \ and maybe_object1 is not self.lives_text and maybe_object2 is not self.lives_text \ and maybe_object3 is not self.lives_text and maybe_object4 is not self.lives_text \ and maybe_object1 is not self.score_text and maybe_object2 is not self.score_text \ and maybe_object3 is not self.score_text and maybe_object4 is not self.score_text: while True: if maybe_object1 is not None or maybe_object2 is not None: if maybe_object1 is not None and maybe_object2 is not None: self.window.remove(maybe_object1) self.window.remove(maybe_object2) self.__dy *= -1 if maybe_object1 is maybe_object2: self.score += 1 else: self.score += 2 else: if maybe_object1 is not None: self.window.remove(maybe_object1) self.__dy *= -1 self.score += 1 else: self.window.remove(maybe_object2) self.__dy *= -1 self.score += 1 if maybe_object2 is not None or maybe_object4 is not None: if maybe_object2 is not None and maybe_object4 is not None: self.window.remove(maybe_object2) self.window.remove(maybe_object4) self.__dx *= -1 if maybe_object2 is maybe_object4: self.score += 1 else: self.score += 2 else: if maybe_object4 is not None: self.window.remove(maybe_object4) self.__dx *= -1 self.score += 1 if maybe_object1 is not None or maybe_object3 is not None: if maybe_object1 is not None and maybe_object3 is not None: self.window.remove(maybe_object1) self.window.remove(maybe_object3) self.__dx *= -1 if maybe_object1 is maybe_object3: self.score += 1 else: self.score += 2 else: if maybe_object3 is not None: self.window.remove(maybe_object3) self.__dx *= -1 self.score += 1 break # Judgment point and paddle state if maybe_object3 is self.paddle or maybe_object4 is self.paddle: self.__dy *= -1 self.ball.move(0, -10) # If the score changes, change the score on the window if self.old_score != self.score: self.score_text.text = 'Score: ' + str(self.score) self.window.add(self.score_text, 0, self.window_height) # After the inspection, the ball moves self.ball.move(self.__dx, self.__dy) def reset(self): """ Reset the position and speed of the ball """ self.ball.x = (self.window_width - self.bra) / 2 self.ball.y = (self.window_height - self.bra) / 2 self.__dx = 0 self.__dy = 0 def lose(self): """ :return:(bool) Check if the ball is under the paddle """ ball_lose = self.ball.y > self.paddle.y + 15 return ball_lose def lives_time(self, lives): """ :param lives: (int) The number of times you can play :return: (int) Remaining times """ lives -= 1 self.lives = lives return lives def print_lives(self): self.lives_text.font = '-15-bold' self.lives_text.text = 'Lives: ' + str(self.lives) self.window.add(self.lives_text, self.window_width - 80, self.window_height) def faster(self, rate): ''' :param rate: (int) Game speed :return: (int) Speed of the game after acceleration ''' rate += self.score * 0.01 return rate def end(self): """ :return: End screen """ pic = GRect(self.window_width, self.window_height) pic.filled = True pic.fill_color = 'gold' end_word = GLabel('Your score: ' + str(self.score)) end_word.font = '-20-bold' self.window.add(pic) self.window.add(end_word, self.window_width / 4 + 30, self.window_height / 2)
class BreakoutGraphics: def __init__(self, ball_radius=BALL_RADIUS, paddle_width=PADDLE_WIDTH, paddle_height=PADDLE_HEIGHT, paddle_offset=PADDLE_OFFSET, brick_rows=BRICK_ROWS, brick_cols=BRICK_COLS, brick_width=BRICK_WIDTH, brick_height=BRICK_HEIGHT, brick_offset=BRICK_OFFSET, brick_spacing=BRICK_SPACING, title='Breakout'): """ Parameter settings. :param ball_radius: Controls the radius of the ball. :param paddle_width: Controls the width of the paddle. :param paddle_height: Controls the height of the paddle. :param paddle_offset: Controls the y-position of the paddle. :param brick_rows: Controls the number of rows of bricks. :param brick_cols: Controls the number of columns of bricks. :param brick_width: Controls the width of a single brick. :param brick_height: Controls the height of a single brick. :param brick_offset: Controls the y-position of the highest row of bricks. :param brick_spacing: Controls the interval between any two bricks. :param title: Set the title of the canvas. """ self.ball_radius = ball_radius self.paddle_width = paddle_width self.paddle_height = paddle_height self.paddle_offset = paddle_offset self.brick_cols = brick_cols self.brick_rows = brick_rows self.brick_width = brick_width self.brick_height = brick_height self.brick_offset = brick_offset self.brick_spacing = brick_spacing # Create a label for usernames before create a window. self.name = GLabel('Player: ' + input('Nickname: ')) self.name.font = '-15-bold' # Create a graphical window, with some extra space. self.window_width = self.brick_cols * (brick_width+brick_spacing) - brick_spacing self.window_height = brick_offset + 3 * (brick_rows * (brick_height+brick_spacing) - brick_spacing) self.window = GWindow(width=self.window_width, height=self.window_height, title=title) # Initial settings before the game starts. self.score = 0 self.score_label = GLabel('Score: ' + str(self.score)) self.score_label.font = '-15-bold' self.lives = 3 self.lives_label = GLabel('Lives: ' + str(self.lives)) self.lives_label.font = '-15-bold' self.click2start = GLabel('Click to Start !') self.click2start.font = '-20-bold' self.window.add(self.name, 5, self.brick_offset - 25) self.window.add(self.click2start, 130, self.window.height-150) self.window.add(self.score_label, 5, self.window.height) self.window.add(self.lives_label, self.window_width-100, self.window_height-5) # Create a paddle. self.count = 1 # For paddle width resetting after losing one live. self.paddle = GRect(self.paddle_width, self.paddle_height) self.paddle.filled = True self.window.add(self.paddle, x=(self.window_width-self.paddle_width)/2, y=self.window_height-paddle_offset) # Center a filled ball in the graphical window. self.ball = GOval(ball_radius*2, ball_radius*2) self.ball.filled = True self.window.add(self.ball, (self.window_width-self.ball.width)/2, (self.window_height-brick_height)/2) # Default initial velocity for the ball. self.__dx = 0 self.__dy = INITIAL_Y_SPEED self.set_x_velocity() # Initialize our mouse listeners. self.is_game_started = False onmouseclicked(self.handle_click) # Draw bricks. self.brick_left = self.brick_cols * self.brick_rows for i in range(self.brick_rows): for j in range(self.brick_cols): # Different colors for every two rows. self.brick = GRect(self.brick_width, self.brick_height) self.brick.filled = True if i < 2: self.brick.fill_color = 'lightcoral' elif 2 <= i < 4: self.brick.fill_color = 'peachpuff' elif 4 <= i < 6: self.brick.fill_color = 'lightyellow' elif 6 <= i < 8: self.brick.fill_color = 'palegreen' elif 8 <= i < 10: self.brick.fill_color = 'aqua' self.window.add(self.brick, x=j*(self.brick_width+self.brick_spacing), y=self.brick_offset+i*(self.brick_height+self.brick_spacing)) def paddle_move(self, event): """ This function will execute if the the game is started. If the game is started, it will detect the position of the mouse so that players can control the paddle with their mouse. :param event: Detects position of the mouse. """ if self.is_game_started: # If the mouse is out of the range of the width of the window, the paddle will still remain in the window. if event.x <= self.paddle.width/2: self.paddle.x = 0 elif event.x >= self.window_width - self.paddle_width/2: self.paddle.x = self.window_width - self.paddle_width else: self.paddle.x = event.x - self.paddle_width/2 def get_x_velocity(self): """ Since self.__dx is private instance variable, we need to create a getter for the user-end. :return: The value of self.__dx (the x-velocity) """ return self.__dx def get_y_velocity(self): """ Since self.__dy is private instance variable, we need to create a getter for the user-end. :return: The value of self.__dy (the y-velocity) """ return self.__dy def set_x_velocity(self): """ Setting a random x-velocity and y-velocity for the ball. The y-velocity is a constant, and the x-velocity is set between 1 and MAX_X_SPEED, There is a 50% chance that the ball will have opposite direction in x dimension. """ self.__dx = random.randint(2, MAX_X_SPEED) if random.random() < 0.5: self.__dx = -self.__dx def handle_click(self, _): """ This function will execute if a click on the mouse. After a single click, the game will start, and any clicks can no longer affect the game. :param _: Detects a click on the mouse. :return: self.count """ self.window.remove(self.click2start) self.is_game_started = True onmousemoved(self.paddle_move) def probe_obj(self): """ This function will detect any collision between the ball with other objects. :return: True, if the ball bump into the paddle or the bricks. """ # The variable 'obj' will change to the next corner if the checked None. obj1 = self.window.get_object_at(self.ball.x, self.ball.y) obj2 = self.window.get_object_at(self.ball.x + self.ball.width, self.ball.y) obj3 = self.window.get_object_at(self.ball.x, self.ball.y + self.ball.height) obj4 = self.window.get_object_at(self.ball.x + self.ball.width, self.ball.y + self.ball.height) point = obj1 if point is None or point is self.name and point is self.score_label and point is self.lives_label: point = obj2 if point is None or point is self.name and point is self.score_label and point is self.lives_label: point = obj3 if point is None or point is self.name and point is self.score_label and point is self.lives_label: point = obj4 if point is None or point is self.name and point is self.score_label and point is self.lives_label: pass if point is self.paddle: # To avoid the ball from sticking on the paddle, I move the ball above the paddle. self.ball.move(0, -self.paddle_height - self.ball.height) # When the ball touches the paddle, the paddle will change its color to the ball's color. self.paddle.color = self.ball.color self.paddle.fill_color = self.ball.fill_color return True if point is not self.paddle and point is not None and point is not self.name\ and point is not self.score_label and point is not self.lives_label: # Every time when the ball bump into a brick, the score will reset. self.window.remove(point) self.brick_left -= 1 # The formula of score counting. self.score = int((self.brick_rows * self.brick_cols - self.brick_left) ** 1.5) if self.brick_left == (self.brick_rows * self.brick_cols) * 1/2: self.lives += 1 self.window.remove(self.lives_label) self.lives_label = GLabel('Lives: ' + str(self.lives)) self.lives_label.font = '-15-bold' self.window.add(self.lives_label, self.window_width-100, self.window_height-5) self.window.remove(self.score_label) self.score_label = GLabel('Score: ' + str(self.score)) self.score_label.font = '-15-bold' self.window.add(self.score_label, 5, self.window.height) # The color of the ball depends on how many bricks are left. if self.brick_rows * self.brick_cols * 3/5 < self.brick_left <= self.brick_rows * self.brick_cols * 4/5: self.ball.color = 'palegreen' self.ball.fill_color = 'palegreen' elif self.brick_rows * self.brick_cols * 2/5 < self.brick_left <= self.brick_rows * self.brick_cols * 3/5: self.ball.color = 'lightyellow' self.ball.fill_color = 'lightyellow' elif self.brick_rows * self.brick_cols * 1/5 < self.brick_left <= self.brick_rows * self.brick_cols * 2/5: self.ball.color = 'peachpuff' self.ball.fill_color = 'peachpuff' # More difficult to see the ball. elif self.brick_left <= self.brick_rows * self.brick_cols * 1/5: self.ball.color = 'black' self.ball.fill_color = 'black' return True # Lives will reset when the ball fall out of the lower margin of the window. def fall_out(self): self.is_game_started = False # Every chance loses, the variable 'count', which affects the length of the paddle, will add 0.15. self.count += 0.15 self.lives -= 1 self.window.remove(self.lives_label) self.lives_label = GLabel('Lives: ' + str(self.lives)) self.lives_label.font = '-15-bold' self.window.add(self.lives_label, self.window_width - 100, self.window_height - 5) self.set_x_velocity() return self.count, self.lives, self.__dx def build_ball(self): """ This function will first remove the original ball and create a new ball. The color of the ball depends on the number of remaining bricks. """ self.window.remove(self.ball) self.ball = GOval(self.ball_radius*2, self.ball_radius*2) self.ball.filled = True # The color of the ball depends on how many bricks are left. if self.brick_rows * self.brick_cols * 3 / 5 < self.brick_left <= self.brick_rows * self.brick_cols * 4 / 5: self.ball.color = 'palegreen' self.ball.fill_color = 'palegreen' elif self.brick_rows * self.brick_cols * 2 / 5 < self.brick_left <= self.brick_rows * self.brick_cols * 3 / 5: self.ball.color = 'lightyellow' self.ball.fill_color = 'lightyellow' elif self.brick_rows * self.brick_cols * 1 / 5 < self.brick_left <= self.brick_rows * self.brick_cols * 2 / 5: self.ball.color = 'peachpuff' self.ball.fill_color = 'peachpuff' # More difficult to see the ball. elif self.brick_left <= self.brick_rows * self.brick_cols * 1 / 5: self.ball.color = 'black' self.ball.fill_color = 'black' self.window.add(self.ball, (self.window_width-self.ball.width)/2, (self.window_height-self.brick_height)/2) def build_paddle(self): """ This function will first remove the original paddle and create a new one. The width of the new paddle depends on the variable of count. """ self.window.remove(self.paddle) self.paddle = GRect(self.paddle_width/self.count, self.paddle_height, x=(self.window_width-self.paddle_width)/2, y=self.window_height-self.paddle_offset) self.paddle.filled = True self.paddle.color = self.ball.color self.paddle.fill_color = self.ball.fill_color self.window.add(self.paddle) def game_over(self): """ This function execute when no lives are remaining. The window will show the game is over and the final score. The score depends on the number of remaining bricks and the variable count. """ self.is_game_started = False self.window.clear() game_over = GLabel('Game Over') game_over.font = '-60-bold' lose = GLabel('You Lose...') lose.font = '-30-bold' score_label = GLabel('Your Score:' + str(self.score)) score_label.font = 'courier-25-bold' background = GRect(self.window.width, self.window.height) background.filled = True background.color = 'red' background.fill_color = 'red' self.window.add(background) self.window.add(game_over, 2, (self.window.height/2)+30) self.window.add(lose, 120, (self.window.height/2+120)) self.window.add(score_label, 100, self.window.height) def winner(self): """ This function will execute if and only if a player successfully eliminates all the bricks. After all bricks are eliminated, the window will show 'You win!!!!' and the final score. The score depends on the number of remaining bricks and the variable count. """ self.window.clear() you_win = GLabel('Love Cindy!!!!') you_win.font = '-60-bold' # One live remaining worth 100 points. self.score += self.lives * 100 score_label = GLabel('Your Score is:' + str(self.score), 0, 20) score_label.font = 'courier-25-bold' background = GRect(self.window.width, self.window.height) background.filled = True background.color = 'pink' background.fill_color = 'pink' self.window.add(background) self.window.add(you_win, 5, (self.window.height/2)+30) self.window.add(score_label, 50, self.window.height)
class ZoneGraphics: def __init__(self, window_width=WINDOW_WIDTH, window_height=WINDOW_HEIGHT, zone_width=ZONE_WIDTH, zone_height=ZONE_HEIGHT, ball_radius=BALL_RADIUS): # Create window self.window = GWindow(window_width, window_height, title='Zone Game') # Create zone self.zone = GRect(zone_width, zone_height, x=(window_width - zone_width) / 2, y=(window_height - zone_height) / 2) self.zone.color = 'blue' self.window.add(self.zone) # Create ball and initialize velocity/position self.ball = GOval(2 * ball_radius, 2 * ball_radius) self.ball.filled = True self.ball.fill_color = 'salmon' self.dx = 0 self.dy = 0 self.reset_ball() # Initialize mouse listeners onmouseclicked(self.handle_click) # Set ball position at random inside the window def set_ball_position(self): self.ball.x = random.randint(0, self.window.width - self.ball.width) self.ball.y = random.randint(0, self.window.height - self.ball.height) def set_ball_velocity(self): self.dx = random.randint(0, MAX_SPEED) if random.random() > 0.5: self.dx = -self.dx self.dy = random.randint(MIN_Y_SPEED, MAX_SPEED) if random.random() > 0.5: self.dy = -self.dy def reset_ball(self): self.set_ball_position() while self.ball_in_zone(): self.set_ball_position() self.set_ball_velocity() self.window.add(self.ball) def move_ball(self): self.ball.move(self.dx, self.dy) def handle_wall_collisions(self): if self.ball.x + self.ball.width >= self.window.width or self.ball.x <= 0: self.dx = -self.dx if self.ball.y + self.ball.height >= self.window.height or self.ball.y <= 0: self.dy = -self.dy def ball_in_zone(self): zone_left_side = self.zone.x zone_right_side = self.zone.x + self.zone.width ball_x_in_zone = zone_left_side <= self.ball.x <= zone_right_side - self.ball.width zone_top_side = self.zone.y zone_bottom_side = self.zone.y + self.zone.height ball_y_in_zone = zone_top_side <= self.ball.y <= zone_bottom_side - self.ball.height return ball_x_in_zone and ball_y_in_zone def handle_click(self, event): obj = self.window.get_object_at(event.x, event.y) if self.ball == obj: self.reset_ball()
class BreakoutGraphics: def __init__(self, ball_radius=BALL_RADIUS, paddle_width=PADDLE_WIDTH, paddle_height=PADDLE_HEIGHT, paddle_offset=PADDLE_OFFSET, brick_rows=BRICK_ROWS, brick_cols=BRICK_COLS, brick_width=BRICK_WIDTH, brick_height=BRICK_HEIGHT, brick_offset=BRICK_OFFSET, brick_spacing=BRICK_SPACING, title='Breakout'): # Create a graphical window, with some extra space window_width = brick_cols * (brick_width + brick_spacing) - brick_spacing window_height = brick_offset + 3 * (brick_rows * (brick_height + brick_spacing) - brick_spacing) self.window = GWindow(width=window_width, height=window_height, title='Breakout') # Element score label self.score = 0 self.score_label = GLabel('Score: ' + str(self.score)) # Element for game winning self.win_show = GLabel('Create by Mike Lin', x=100, y=100) self.win_show2 = GLabel('March 20 stanCode SC101', x=135, y=115) # Create a paddle self.paddle = GRect(paddle_width, paddle_height, x=(window_width - paddle_width) / 2, y=window_height - paddle_offset) self.window.add(self.paddle) self.paddle.filled = True # Center a filled ball in the graphical window self.ball = GOval(2 * ball_radius, 2 * ball_radius, x=window_width / 2 - ball_radius, y=window_height / 2 - ball_radius) self.ball_x = window_width / 2 - ball_radius self.ball_y = window_height / 2 - ball_radius # Default initial velocity for the ball self.__dx = 0 self.__dy = 0 # Other variables self.total_bricks = 0 # Initialize our mouse listeners onmousemoved( self.paddle_move) # using own method must add 'self.' in the front onmouseclicked(self.clicked) self.draw_bricks_and_ball() def draw_bricks_and_ball(self): """ set the bricks and balls """ self.window.add(self.score_label, x=0, y=15) self.window.add(self.ball) self.ball.filled = True color_num = BRICK_COLS / 5 for i in range(BRICK_ROWS): for j in range(BRICK_COLS): if j // color_num == 0: color = 'red' elif j // color_num == 1: color = 'orange' elif j // color_num == 2: color = 'yellow' elif j // color_num == 3: color = 'green' else: color = 'blue' bricks = GRect(BRICK_WIDTH, BRICK_HEIGHT) self.window.add(bricks, x=0 + i * (BRICK_WIDTH + BRICK_SPACING), y=BRICK_OFFSET + j * (BRICK_HEIGHT + BRICK_SPACING)) bricks.filled = True bricks.fill_color = color self.total_bricks += 1 def paddle_move(self, m): """ :param m: mouse you move this function controls the moving of the paddle and prevents it from disappearing """ if self.paddle.width / 2 <= m.x <= self.window.width - self.paddle.width / 2: self.paddle.x = m.x - self.paddle.width / 2 elif m.x >= self.window.width: self.paddle.x = self.window.width - self.paddle.width elif m.x < 0: self.paddle.x = 0 def clicked(self, m): """ the boolean that controls the start of the game once you clicked the mouse """ if (self.ball.x, self.ball.y) == (self.ball_x, self.ball_y): self.__dx = random.randint(1, MAX_X_SPEED) if random.random() > 0.5: self.__dx = -self.__dx self.__dy = INITIAL_Y_SPEED def set_ball_direct(self): """ to set the ball's direction and the action the ball takes when hitting the walls, bricks, paddle """ self.ball.move(self.__dx, self.__dy) self.meet_the_wall() if self.meet_object() is self.paddle: self.__dy = -abs(self.__dy) elif self.meet_object() is self.ball: pass elif self.meet_object() is self.score_label: pass elif self.meet_object() is not None: self.window.remove(self.meet_object()) self.__dy *= -1 self.total_bricks -= 1 self.score += 1 self.score_label.text = 'Score: ' + str(self.score) if self.total_bricks == 0: self.ball.x = self.ball_x self.ball.y = self.ball_y self.window.add(self.win_show) self.window.add(self.win_show2) self.win_show.font = '-30' def meet_the_wall(self): """ the function that determines the ball's vy """ if self.ball.x <= 0: self.__dx *= -1 elif self.ball.x + self.ball.width >= self.window.width: self.__dx *= -1 elif self.ball.y <= 0: self.__dy *= -1 elif self.ball.y + self.ball.height >= self.window.height: self.__dx = 0 self.__dy = 0 def dead(self): """ to set the ball to start point when falling under the bottom window """ if self.ball.y + self.ball.height >= self.window.height: self.ball.x = self.ball_x self.ball.y = self.ball_y return True def meet_object(self): """ the detector for checking what the ball hits :return: the obstacle that ball hits """ obstacle1 = self.window.get_object_at(self.ball.x, self.ball.y) obstacle2 = self.window.get_object_at(self.ball.x + self.ball.width, self.ball.y) obstacle3 = self.window.get_object_at(self.ball.x + self.ball.width, self.ball.y + self.ball.height) obstacle4 = self.window.get_object_at(self.ball.x, self.ball.y + self.ball.height) if obstacle1 is not None and not self.ball: return obstacle1 elif obstacle2 is not None: return obstacle2 elif obstacle3 is not None: return obstacle3 elif obstacle4 is not None: return obstacle4 else: return None def get_dx(self): """ to get dx speed :return: dx speed """ return self.__dx def get_dy(self): """ to get dy speed :return: dy speed """ return self.__dy
class BreakoutGraphics: def __init__(self, ball_radius=BALL_RADIUS, paddle_width=PADDLE_WIDTH, paddle_height=PADDLE_HEIGHT, paddle_offset=PADDLE_OFFSET, brick_rows=BRICK_ROWS, brick_cols=BRICK_COLS, brick_width=BRICK_WIDTH, brick_height=BRICK_HEIGHT, brick_offset=BRICK_OFFSET, brick_spacing=BRICK_SPACING, title='Breakout'): # Create a graphical window, with some extra space. window_width = brick_cols * (brick_width + brick_spacing) - brick_spacing window_height = brick_offset + 3 * (brick_rows * (brick_height + brick_spacing) - brick_spacing) self.window = GWindow(width=window_width, height=window_height, title=title) # Create a paddle. self.paddle = GRect(paddle_width, paddle_height) self.paddle.filled = True self.window.add(self.paddle, (window_width - paddle_width) / 2, window_height - paddle_offset) # Center a filled ball in the graphical window. self.ball = GOval(ball_radius * 2, ball_radius * 2, x=window_width / 2 - ball_radius, y=window_height / 2 - ball_radius) self.ball.filled = True self.window.add(self.ball) # Create a scoreboard. self.__score = 0 self.__board = GLabel('Score: ' + str(self.__score)) self.__board.font = '-30' self.window.add(self.__board, 0, self.__board.height + 5) # Default initial velocity for the ball. self.__dx = 0 self.__dy = 0 self.reverse_dy = -INITIAL_Y_SPEED # Initialize our mouse listeners. onmousemoved(self.move_paddle) onmouseclicked(self.click_to_start) self.__start = False # Draw bricks. self.__count = 0 for i in range(brick_rows): for j in range(brick_cols): self.__brick = GRect(brick_width, brick_height) self.__brick.filled = True if i // 2 == 0: self.__brick.fill_color = 'red' self.__brick.color = 'red' if i // 2 == 1: self.__brick.fill_color = 'orange' self.__brick.color = 'orange' if i // 2 == 2: self.__brick.fill_color = 'yellow' self.__brick.color = 'yellow' if i // 2 == 3: self.__brick.fill_color = 'green' self.__brick.color = 'green' if i // 2 == 4: self.__brick.fill_color = 'blue' self.__brick.color = 'blue' brick_y = brick_offset + (brick_height + brick_spacing) * i brick_x = (brick_width + brick_spacing) * j self.window.add(self.__brick, brick_x, brick_y) self.__count += 1 def move_paddle(self, mouse): """ Set the paddle to move horizontally with mouse moved and is contained in window. Input: event (GMouseEvent): mouse moved event """ self.paddle.x = mouse.x - self.paddle.width / 2 if self.paddle.x <= 0: self.paddle.x = 0 if self.paddle.x + self.paddle.width >= self.window.width: self.paddle.x = self.window.width - self.paddle.width def click_to_start(self, event): """ Start the game if the mouse is clicked and detect whether the game is started. Input: event (GMouseEvents): mouse clicked event """ if not self.__start: self.set_ball_direction() self.__start = True def set_ball_direction(self): """ Give ball x, y velocity which will determine its initial direction. """ self.__dx = random.randint(1, MAX_X_SPEED) self.__dy = INITIAL_Y_SPEED if random.random() > 0.5: self.__dx = -self.__dx def get_x_velocity(self): """ Return ball x velocity. """ return self.__dx def get_y_velocity(self): """ Return ball y velocity. """ return self.__dy def move_ball(self): """ Move ball by the change in x and the change in y stored in class BreakoutGraphics. """ self.ball.move(self.__dx, self.__dy) def wall_collisions(self): """ Update dx and dy depending on whether the ball has hit walls. """ if 0 >= self.ball.x or self.ball.x + self.ball.width >= self.window.width: self.__dx = -self.__dx if 0 >= self.ball.y: self.__dy = -self.__dy def ball_collisions(self): """ Remove bricks and change ball's direction when the ball hit bricks. Rebound the ball by changing its y velocity when the ball hit the paddle. The score will add one when each time brick was removed. """ up_l_corner = self.window.get_object_at(self.ball.x, self.ball.y) up_r_corner = self.window.get_object_at(self.ball.x + self.ball.width, self.ball.y) down_l_corner = self.window.get_object_at( self.ball.x, self.ball.y + self.ball.height) down_r_corner = self.window.get_object_at( self.ball.x + self.ball.width, self.ball.y + self.ball.height) # The situation that the ball hits the paddle. if down_l_corner == self.paddle: self.__dy = self.reverse_dy elif down_r_corner == self.paddle: self.__dy = self.reverse_dy # The situation that the ball hits bricks and remove them. if up_l_corner is not None and up_l_corner is not self.paddle and up_l_corner is not self.__board: self.__dy = -self.__dy self.window.remove(up_l_corner) self.__count -= 1 self.__score += 1 self.__board.text = 'Score: ' + str(self.__score) elif up_r_corner is not None and up_r_corner is not self.paddle and up_r_corner is not self.__board: self.__dy = -self.__dy self.window.remove(up_r_corner) self.__count -= 1 self.__score += 1 self.__board.text = 'Score: ' + str(self.__score) elif down_l_corner is not None and down_l_corner is not self.paddle and down_l_corner is not self.__board: self.__dy = -self.__dy self.window.remove(down_l_corner) self.__count -= 1 self.__score += 1 self.__board.text = 'Score: ' + str(self.__score) elif down_r_corner is not None and down_r_corner is not self.paddle and down_r_corner is not self.__board: self.__dy = -self.__dy self.window.remove(down_r_corner) self.__count -= 1 self.__score += 1 self.__board.text = 'Score: ' + str(self.__score) def outside_window(self): """ Check whether the ball has fallen outside the window bottom. :return: Bool """ if self.ball.y >= self.window.height: return True def reset_ball(self): """ Reset the ball's location and velocity after the ball has fallen outside the window. :return: Bool """ self.window.remove(self.ball) self.ball.x = (self.window.width - self.ball.width) / 2 self.ball.y = (self.window.height - self.ball.height) / 2 self.__dx = 0 self.__dy = 0 self.window.add(self.ball) self.__start = False def game_over(self): """ One of the conditions for game over. When all chances were used out. """ self.reset_ball() lose = GLabel('You lose!') lose.font = '-70-bold' self.window.add(lose, (self.window.width - lose.width) / 2, 500) def end_game(self): """ One of the conditions for game over. When all bricks were remove. :return: Bool """ if self.__count == 0: self.window.remove(self.ball) congrats = GLabel('Congratulation!') congrats.font = '-70-bold' congrats.color = 'red' self.window.add(congrats, (self.window.width - congrats.width) / 2, 500) return True
class BreakoutGraphics: def __init__(self, ball_radius=BALL_RADIUS, paddle_width=PADDLE_WIDTH, paddle_height=PADDLE_HEIGHT, paddle_offset=PADDLE_OFFSET, brick_rows=BRICK_ROWS, brick_cols=BRICK_COLS, brick_width=BRICK_WIDTH, brick_height=BRICK_HEIGHT, brick_offset=BRICK_OFFSET, brick_spacing=BRICK_SPACING, title='Breakout', life=NUM_LIVES): # Create a graphical window, with some extra space. self.window_width = brick_cols * (brick_width + brick_spacing) - brick_spacing self.window_height = brick_offset + 3 * ( brick_rows * (brick_height + brick_spacing) - brick_spacing) self.window = GWindow(width=self.window_width, height=self.window_height, title=title) # Create a paddle. self.paddle = GRect(paddle_width, paddle_height, x=(self.window_width - paddle_width) / 2, y=self.window_height - paddle_offset + paddle_height) self.paddle.filled = True self.paddle.color = '#53414E' self.paddle.fill_color = '#53414E' self.window.add(self.paddle) # Center a filled ball in the graphical window. self.ball = GOval(ball_radius * 2, ball_radius * 2, x=self.window_width / 2 - ball_radius, y=self.window_height / 2 - ball_radius) self.ball.filled = True self.ball.fill_color = '#FF7146' self.window.add(self.ball, self.window_width / 2 - ball_radius, self.window_height / 2 - ball_radius) # Default initial velocity for the ball. self.__dx = 0 self.__dy = INITIAL_Y_SPEED self.__dx = random.randint(1, MAX_X_SPEED) # Initialize our mouse listeners. self.no_restart = False # to switch on the game self.count = 0 self.life = NUM_LIVES onmousemoved(self.move_paddle) onmouseclicked(self.move_ball) # Draw bricks. for i in range(brick_rows): for j in range(brick_cols): if j % 2 == 0: self.brick = GRect(brick_width, brick_height, x=i * (brick_width + brick_spacing), y=brick_offset + j * (brick_height + brick_spacing)) self.brick.filled = True self.brick.fill_color = '#B2CFD6' self.window.add(self.brick) else: self.brick = GRect(brick_width, brick_height, x=i * (brick_width + brick_spacing), y=brick_offset + j * (brick_height + brick_spacing)) self.brick.filled = True self.brick.fill_color = '#AED690' self.window.add(self.brick) #game over label self.over_label = GLabel('Game Over', x=self.window_width / 2, y=self.window_height / 2) self.over_label.color = 'black' #finish label self.brick_amount = int(brick_rows * brick_cols) self.finish_label = GLabel('Congrats', x=self.window_width / 2, y=self.window_height / 2) self.finish_label.color = 'red' #ball touch paddle self.ball_touch_paddle_1 = self.window.get_object_at( self.ball.x, self.ball.y + self.ball.height) self.ball_touch_paddle_2 = self.window.get_object_at( self.ball.x + self.ball.width, self.ball.y + self.ball.height) self.ball_touch_paddle_check = True #bounce self.ten_point = GOval(ball_radius * 2, ball_radius * 2) self.ten_point.filled = True self.ten_point.fill_color = 'black' def drop_ten_point(self): self.ten_point.move(0, 5) def get_ten_point(self): if self.ten_point.y + self.ten_point.height >= self.paddle.y and self.paddle.x <= self.ten_point.x <= self.paddle.width - self.ten_point.width: self.count += 10 def move_paddle(self, mouse): if 0 <= mouse.x <= self.window.width - self.paddle.width: self.paddle.x = mouse.x self.paddle.y = self.paddle.y def move_ball(self, event): if 0 <= event.x <= self.window.width and 0 <= event.y <= self.window.height and not self.no_restart: self.no_restart = True def get_dx(self): # getter: let breakout.py to get the dx return self.__dx def get_dy(self): # getter: let breakout.py to get the dy return self.__dy def ball_outside_window(self): ball_outside_window = self.ball.y > self.window.height return ball_outside_window def bouncing_dx(self): self.__dx = -self.__dx return self.__dx def bouncing_dy(self): self.__dy = -self.__dy return self.__dy def ball_touch_wall(self): ball_touch_x_left_wall = self.ball.x <= 0 ball_touch_x_right_wall = self.ball.x + self.ball.width >= self.window.width ball_touch_y_top = self.ball.y <= 0 return ball_touch_x_left_wall or ball_touch_x_right_wall or ball_touch_y_top def ball_touch_paddle(self): ball_touch_x_paddle = self.paddle.x - self.ball.width <= self.ball.x <= self.paddle.x + self.paddle.width ball_touch_y_paddle = self.paddle.y <= self.ball.y + self.ball.height <= self.paddle.y + self.paddle.height return ball_touch_x_paddle and ball_touch_y_paddle def ball_in_window(self): ball_in_window_x = self.ball.x == self.window_width / 2 - self.ball.width return ball_in_window_x def reset_ball(self): self.set_ball_position() while self.ball_outside_window(): self.set_ball_position() self.set_ball_velocity() self.window.add(self.ball) def set_ball_velocity(self): self.__dx = random.randint(1, MAX_X_SPEED) self.__dy = INITIAL_Y_SPEED def set_ball_position(self): self.window.add(self.ball, self.window_width / 2 - self.ball.width, self.window_height / 2 - self.ball.height) def remove_brick(self, obj): self.window.remove(obj) self.__dx = random.randint(1, MAX_X_SPEED) self.__dy = -self.__dy def game_over(self): self.window.add(self.over_label, x=self.window_width / 2, y=self.window_height / 2) self.window.remove(self.ball) def finish_game(self): self.window.add(self.finish_label, x=self.window_width / 2, y=self.window_height / 2) def remove_ball_paddle(self): self.window.remove(self.ball) self.window.remove(self.paddle)
class BreakoutGraphics: def __init__(self, ball_radius=BALL_RADIUS, paddle_width=PADDLE_WIDTH, paddle_height=PADDLE_HEIGHT, paddle_offset=PADDLE_OFFSET, brick_rows=BRICK_ROWS, brick_cols=BRICK_COLS, brick_width=BRICK_WIDTH, brick_height=BRICK_HEIGHT, brick_offset=BRICK_OFFSET, brick_spacing=BRICK_SPACING, title='Breakout'): num_bricks = 100 # Create a graphical window, with some extra space. window_width = brick_cols * (brick_width + brick_spacing) - brick_spacing window_height = brick_offset + 3 * (brick_rows * (brick_height + brick_spacing) - brick_spacing) self.window = GWindow(width=window_width, height=window_height, title=title) self.paddle = GRect(paddle_width, paddle_height, x=(window_width - paddle_width)/2, y = window_height - \ paddle_offset) # initializing the paddle self.paddle.filled = True self.paddle.fill_color = 'black' self.window.add(self.paddle) # initializing the ball self.ball = GOval(width=ball_radius * 2, height=ball_radius * 2, x=window_width / 2 - BALL_RADIUS, y=window_height / 2 - BALL_RADIUS) self.ball.filled = True self.ball.fill_color = 'black' self.window.add(self.ball) # initial velocity self.vx = 0 self.vy = INITIAL_Y_SPEED # draw bricks self.draw_bricks() # number of lives left self.num_lives = 3 # running? big question mark self.running = False # brick count self.brick_count = 100 # mouse listeners onmouseclicked(self.start) onmousemoved(self.move_paddle) def start(self, event): """ Starts game on mouse click. """ self.running = True def draw_bricks(self): """ Draws bricks by row and with color changing for each turn. """ x_init = 0 curr_y = BRICK_OFFSET color_index = 0 for row in range(1, BRICK_ROWS + 1): curr_x = x_init for col in range(BRICK_COLS): self.brick = GRect(BRICK_WIDTH, BRICK_HEIGHT, x=curr_x, y=curr_y) self.brick.filled = True self.brick.fill_color = COLORS[color_index] self.window.add(self.brick) curr_x += BRICK_WIDTH + BRICK_SPACING curr_y += BRICK_HEIGHT + BRICK_SPACING if row % 2 == 0: color_index += 1 def move_paddle(self, event): """ Moves paddle with mouse event. """ self.paddle.x = event.x - PADDLE_WIDTH / 2 def move_ball(self): """ Moves ball with proper x and y velocities. """ self.ball.move(self.vx, self.vy) def handle_collisions(self): """ Handles collisions as necessary per animation loop. """ # changing for wall collisions if self.side_wall_hit( ): # checks for side wall hits and changes x-component print('oop hit a side wall') self.vx = -self.vx elif self.top_wall_paddle_hit( ): # checks for top/paddle hits and changes y-component print('oop hit the top or a paddle') self.vy = -self.vy # changing for block collisions elif self.brick_paddle_hit( ) != -1 and self.ball.y != self.window.height - 2 * BALL_RADIUS - PADDLE_OFFSET - PADDLE_HEIGHT: loc_x, loc_y = self.brick_paddle_hit() print(loc_x, loc_y) self.remove_brick(loc_x, loc_y) self.vy = -self.vy self.vx = random.uniform(-MAX_X_SPEED, MAX_X_SPEED) # changing for bottom collision elif self.bottom_hit(): self.num_lives -= 1 print('the number of lives is', self.num_lives) self.reset() def bottom_hit(self): """ Checks if the bottom was hit. """ if self.ball.y + 2 * BALL_RADIUS >= self.window.height: return True else: return False def side_wall_hit(self): """ Checks if the left or right walls were hit. """ if self.ball.x <= 0 or self.ball.x >= self.window.width - 2 * BALL_RADIUS: return True else: return False def top_wall_paddle_hit(self): """ Checks if the top wall or paddle was hit. """ if self.ball.y <= 0: return True elif self.brick_paddle_hit( ) != -1 and self.ball.y >= self.window.height - 2 * BALL_RADIUS - PADDLE_OFFSET: return True else: return False def brick_paddle_hit(self): """ Checks, according to the guidelines in the handout, if a collision has occurred with the ball and a brick or the paddle. """ if self.window.get_object_at(self.ball.x, self.ball.y) != None: return self.ball.x, self.ball.y elif self.window.get_object_at(self.ball.x + 2 * BALL_RADIUS, self.ball.y) != None: return self.ball.x + 2, self.ball.y elif self.window.get_object_at(self.ball.x, self.ball.y + 2 * BALL_RADIUS) != None: return self.ball.x, self.ball.y + 2 * BALL_RADIUS elif self.window.get_object_at(self.ball.x + 2 * BALL_RADIUS, self.ball.y + 2 * BALL_RADIUS) != None: return self.ball.x + 2 * BALL_RADIUS, self.ball.y + 2 * BALL_RADIUS else: return -1 def remove_brick(self, loc_x, loc_y): """ Remove a brick when hit. """ if self.window.get_object_at(loc_x, loc_y) != self.paddle: self.window.remove(self.window.get_object_at(loc_x, loc_y)) self.brick_count -= 1 def reset(self): """ Resets the game when the bottom is hit. """ self.window.clear() self.window.remove(self.ball) self.ball = GOval(width=BALL_RADIUS * 2, height=BALL_RADIUS * 2, x=self.window.width / 2 - BALL_RADIUS, y=self.window.height / 2 - BALL_RADIUS) self.ball.filled = True self.ball.fill_color = 'black' self.window.add(self.ball) self.draw_bricks() self.brick_count = 100 self.vx = 0 self.vy = INITIAL_Y_SPEED self.paddle.filled = True self.paddle.fill_color = 'black' self.window.add(self.paddle) self.running = False def game_over(self): game_over_label = GLabel('GAME OVER', x=self.window.width / 2 - 40, y=self.window.height / 2) self.window.add(game_over_label)
class BreakoutGraphics: def __init__(self, ball_radius=BALL_RADIUS, paddle_width=PADDLE_WIDTH, paddle_height=PADDLE_HEIGHT, paddle_offset=PADDLE_OFFSET, brick_rows=BRICK_ROWS, brick_cols=BRICK_COLS, brick_width=BRICK_WIDTH, brick_height=BRICK_HEIGHT, brick_offset=BRICK_OFFSET, brick_spacing=BRICK_SPACING, title='Breakout'): """ Function: Create initial parameters such as window, ball, paddle,brick etc. :param ball_radius: Radius of the ball (in pixels). :param paddle_width: Width of the paddle (in pixels). :param paddle_height: Height of the paddle (in pixels). :param paddle_offset: Vertical offset of the paddle from the window bottom (in pixels). :param brick_rows: Number of rows of bricks. :param brick_cols: Number of cols of bricks. :param brick_width: Width of a brick (in pixels). :param brick_height: Height of a brick (in pixels). :param brick_offset: Vertical offset of the topmost brick from the window top (in pixels). :param brick_spacing: Space between bricks (in pixels). This space is used for horizontal and vertical spacing. :param title: Window title """ # Create a graphical window, with some extra space. window_width = brick_cols * (brick_width + brick_spacing) - brick_spacing window_height = brick_offset + 3 * (brick_rows * (brick_height + brick_spacing) - brick_spacing) self.window = GWindow(width=window_width, height=window_height, title=title) # Create a paddle. self.paddle = GRect(paddle_width, paddle_height, x=(window_width - paddle_width) / 2, y=window_height - paddle_offset) self.paddle.filled = True self.window.add(self.paddle) # Center a filled ball in the graphical window. self.ball = GOval(ball_radius * 2, ball_radius * 2, x=window_width / 2 - ball_radius, y=window_height / 2 - ball_radius) self.ball.filled = True self.window.add(self.ball) # Default initial velocity for the ball. self.__dx = 0 self.__dy = 0 print('dxdy') # Initialize our mouse listeners. self.brick_number = brick_rows * brick_cols # Draw bricks. self.__brick_site(brick_rows, brick_cols, brick_width, brick_height, brick_offset, brick_spacing) onmouseclicked(self.star_fire) onmousemoved(self.__move_paddle) self.star_switch = False self.ball_rest() def star_fire(self, mouse): """ Function: When you click the mouse, start the bool. :param mouse: Mouse parameters """ self.star_switch = True def __brick_site(self, b_r, b_c, b_w, b_h, b_offset, b_spacing): """ Function: Establish the position of the brick :param b_r: Number of rows of bricks. :param b_c: Number of cols of bricks. :param b_w: Width of a brick (in pixels). :param b_h: Height of a brick (in pixels). :param b_offset: Vertical offset of the topmost brick from the window top (in pixels). :param b_spacing: Space between bricks (in pixels). This space is used for horizontal and vertical spacing. """ dy = b_offset for j in range(b_r): dx = 0 for i in range(b_c): self.brick = GRect(b_w, b_h, x=dx, y=dy) self.brick.filled = True if j == 0 or j == 1: self.brick.fill_color = 'darkgreen' elif j == 2 or j == 3: self.brick.fill_color = 'forestgreen' elif j == 4 or j == 5: self.brick.fill_color = 'green' elif j == 6 or j == 7: self.brick.fill_color = 'limegreen' elif j == 8 or j == 9: self.brick.fill_color = 'lime' else: self.brick.fill_color = 'lawngreen' self.window.add(self.brick) dx += b_w + b_spacing dy += b_h + b_spacing def __move_paddle(self, mouse): """ Function: When moving the mouse, move the position of the paddle. :param mouse: Mouse parameters """ if (mouse.x <= self.window.width - self.paddle.width / 2) and ( mouse.x >= self.paddle.width / 2): self.paddle.x = mouse.x - (self.paddle.width / 2) elif mouse.x < self.paddle.width / 2: self.paddle.x = 0 elif mouse.x > self.window.width: self.paddle.x = self.window.width - self.paddle.width def set_ball_velocity(self): """ Function: set initial speed. """ self.__dx = random.randint(1, MAX_X_SPEED) if random.random() > 0.5: self.__dx = -self.__dx self.__dy = INITIAL_Y_SPEED def set_ball_site(self): """ Function: set initial site. """ self.ball.x = (self.window.width - self.ball.height) / 2 self.ball.y = (self.window.height - self.ball.height) / 2 def ball_move(self): """ Function: the distance the ball moves each time. """ self.ball.move(self.__dx, self.__dy) def get_ball_outside(self): """ Function: Report when the ball outside. """ if self.ball.y > self.window.height: return True def ball_rest(self): """ Function: Set the initialization of the ball """ self.set_ball_site() self.set_ball_velocity() while True: if self.star_switch: print(f'ball_rest {self.star_switch}') self.star_switch = False break pause(200) def ball_rebound_window(self): """ Function: The ball bounces to the window. """ if self.ball.x <= 0 or (self.ball.x + self.ball.width) >= self.window.width: self.__dx = -self.__dx if self.ball.y <= 0: self.__dy = -self.__dy def ball_rebound_obj(self): """ Function: The ball bounces to the object. """ obj_u = self.window.get_object_at(self.ball.x + self.ball.width / 2, self.ball.y - 0.1) obj_d = self.window.get_object_at(self.ball.x + self.ball.width / 2, self.ball.y + self.ball.height + 0.1) obj_l = self.window.get_object_at(self.ball.x - 0.1, self.ball.y + self.ball.height / 2) obj_r = self.window.get_object_at(self.ball.x + self.ball.width + 0.1, self.ball.y + self.ball.height / 2) if obj_u is not None: self.ball.y = obj_u.y + obj_u.height self.__dy = -self.__dy if obj_u != self.paddle: self.window.remove(obj_u) self.brick_number -= 1 elif obj_d is not None: self.ball.y = obj_d.y - self.ball.height self.__dy = -self.__dy if obj_d != self.paddle: self.window.remove(obj_d) self.brick_number -= 1 elif obj_l is not None: self.ball.x = obj_l.x + obj_l.width self.__dx = -self.__dx if obj_l != self.paddle: self.window.remove(obj_l) self.brick_number -= 1 elif obj_r is not None: self.ball.x = obj_r.x - self.ball.width self.__dx = -self.__dx if obj_r != self.paddle: self.window.remove(obj_r) self.brick_number -= 1
class BreakoutGraphics: def __init__(self, ball_radius=BALL_RADIUS, paddle_width=PADDLE_WIDTH, paddle_height=PADDLE_HEIGHT, paddle_offset=PADDLE_OFFSET, brick_rows=BRICK_ROWS, brick_cols=BRICK_COLS, brick_width=BRICK_WIDTH, brick_height=BRICK_HEIGHT, brick_offset=BRICK_OFFSET, brick_spacing=BRICK_SPACING, title='Breakout'): # Create a graphical window, with some extra space. self.window_width = brick_cols * (brick_width + brick_spacing) - brick_spacing self.window_height = brick_offset + 3 * ( brick_rows * (brick_height + brick_spacing) - brick_spacing) self.window = GWindow(width=self.window_width, height=self.window_height, title=title) # set up the paddle. self.paddle_width = paddle_width self.paddle_height = paddle_height self.paddle = GRect(paddle_width, paddle_height, x=(self.window_width - PADDLE_WIDTH) / 2, y=self.window_height - paddle_offset - paddle_height) self.paddle.filled = True self.paddle.color = 'slategrey' self.paddle.fill_color = 'slategrey' # set up a the ball. self.ball_radius = ball_radius self.ball = GOval(self.ball_radius * 2, self.ball_radius * 2, x=(self.window_width - self.ball_radius * 2) / 2, y=(self.window_height - self.ball_radius * 2) / 2) self.ball.filled = True self.ball.color = 'crimson' self.ball.fill_color = 'crimson' # Default initial velocity for the ball. self.__dx = random.randint(MIN_X_SPEED, MAX_X_SPEED) if random.random() > 0.5: self.__dx = -self.__dx self.__dy = INITIAL_Y_SPEED # Initialize our mouse listeners. onmousemoved(self.move_paddle) onmouseclicked(self.switch) # Control whether the user can start the game self.__start = False # Determine the lives the user gets self.__num_lives = 0 # Attributes relate to the score self.__score = 0 self.__win_score = BRICK_COLS * BRICK_ROWS * 10 self.score_sign = GLabel(f'SCORE : {self.__score}') self.can_move = False self.can_drop = True self.reward = 0 # Attribute relate to live sign self.live_2 = GOval(self.ball_radius * 2, self.ball_radius * 2, x=self.window_width - (self.ball_radius * 2 + 8), y=self.window_height - (self.ball_radius * 2 + 8)) self.live_1 = GOval(self.ball_radius * 2, self.ball_radius * 2, x=self.window_width - (self.ball_radius * 2 + 8) * 2, y=self.window_height - (self.ball_radius * 2 + 8)) # Attributes relate to extension opening self.o_ball = GOval(30, 30, x=(self.window.width - 30) / 2, y=240) self.start_button = GLabel('S T A R T') self.__enter_game = False # Attributes relate to extension 'game over' scene self.game_over_w = GLabel('G A M E O V E R') # Attributes relate to rewards self.hint_sign = 0 self.reverse_paddle = False self.paddle_adding = False self.adding_count = 0 # To store the mouse event self.paddle_x = 0 def set_game(self): """ This method set up the starting interface for the game. Including materials such as: paddle, window, score sign and bricks. """ # Create a paddle. self.window.add(self.paddle) # Center a filled ball in the graphical window. self.window.add(self.ball) # Build the score sign self.score_sign = GLabel(f'SCORE : {self.__score}') self.score_sign.color = 'crimson' self.score_sign.font = 'Mamelon-20' self.window.add(self.score_sign, x=8, y=self.window.height - 8) # Build lives sign self.live_2.filled = True self.live_2.color = 'crimson' self.live_2.fill_color = 'crimson' self.window.add(self.live_2) self.live_1.filled = True self.live_1.color = 'crimson' self.live_1.fill_color = 'crimson' self.window.add(self.live_1) # Draw bricks. for i in range(BRICK_ROWS): for j in range(BRICK_COLS): brick = GRect(BRICK_WIDTH, BRICK_HEIGHT, x=i * (BRICK_WIDTH + BRICK_SPACING), y=BRICK_OFFSET + j * (BRICK_HEIGHT + BRICK_SPACING)) brick.filled = True if j == 0 or j == 1: brick.color = 'darkslategrey' brick.fill_color = 'darkslategrey' elif j == 2 or j == 3: brick.color = 'teal' brick.fill_color = 'teal' elif j == 4 or j == 5: brick.color = 'cadetblue' brick.fill_color = 'cadetblue' elif j == 6 or j == 7: brick.color = 'lightseagreen' brick.fill_color = 'lightseagreen' else: brick.color = 'mediumturquoise' brick.fill_color = 'mediumturquoise' self.window.add(brick) def move_paddle(self, event): """ This method keep mouse event regarding reverse and not reverse situation of the paddle. Also, it keeps the paddle within the window . :param event: mouse event """ if self.reverse_paddle: # reverse paddle movement event_x = self.window_width - event.x else: # Normal paddle movement event_x = event.x # Keeping the paddle within the window if event_x - self.paddle_width / 2 < 0: self.paddle.x = 0 elif event_x + self.paddle_width / 2 > self.window.width: self.paddle.x = self.window.width - self.paddle_width # Control the paddle when the mouse is in the window else: self.paddle.x = event_x - self.paddle_width / 2 # To store the mouse event self.paddle_x = self.paddle.x def reset_ball(self): """ This method resets the ball at the starting position, and will not drop unless the the user clicks. """ self.ball = GOval(self.ball_radius * 2, self.ball_radius * 2, x=(self.window_width - self.ball_radius * 2) / 2, y=(self.window_height - self.ball_radius * 2) / 2) self.ball.filled = True self.ball.color = 'crimson' self.ball.fill_color = 'crimson' self.window.add(self.ball) self.__start = False # getter for the ball's moving speed. def get_dx(self): return self.__dx # getter for the ball's moving speed. def get_dy(self): return self.__dy # getter, see if the ball is ready to be click and fall def start(self): return self.__start # getter, see if the start button in the opening scene is clicked def get_enter_game(self): return self.__enter_game # setter, the user can set up the initial lives. def set_num_lives(self, num_lives): self.__num_lives = num_lives def switch(self, e): """ This method is the switch for 2 purpose. 1. whether the user can start the game. In the start of each round, if user's lives > 0, the switch will set to open, the ball will move after the user click the window. 2. whether the start button in the opening scene is clicked. If clicked, set up the game. If not, wait for the click. """ if self.__num_lives > 0: self.__start = True if self.window.get_object_at(e.x, e.y) is self.o_ball or \ self.window.get_object_at(e.x, e.y) is self.start_button: self.__enter_game = True # To get the position of the 4 corners of the ball def corner_hits(self): """ This method check from corner_1 to corner_4, to see if any corner of the ball has encounter obstacles. If so, return the method to remove object encountered. If not, move on to the next corner. :return: method, remove the object on the encountered corner. """ # To get position of each corner of the ball corner_1 = self.window.get_object_at(self.ball.x, self.ball.y) corner_2 = self.window.get_object_at( self.ball.x + 2 * self.ball_radius, self.ball.y) corner_3 = self.window.get_object_at( self.ball.x, self.ball.y + 2 * self.ball_radius) corner_4 = self.window.get_object_at( self.ball.x + 2 * self.ball_radius, self.ball.y + 2 * self.ball_radius) # To check which corner hits things if corner_1 is not None: return corner_1 elif corner_2 is not None: return corner_2 elif corner_3 is not None: return corner_3 elif corner_4 is not None: return corner_4 else: pass # To check whether the ball hits the wall def if_hits_walls(self): """ This method checks whether the ball hits the side walls and the the top wall. If so, the ball will bounce back. """ # The ball hits the side walls and the the top wall if self.ball.x <= 0 or self.ball.x + 2 * self.ball_radius >= self.window.width: self.__dx *= -1 # The ball hits the the top wall if self.ball.y <= 0: self.__dy *= -1 # To check what the ball hits def if_hits_things(self): """ This method determines what kind of object the ball hits, and run the actions after hitting certain objects. """ # The ball hits the paddle if self.corner_hits() is self.paddle: # bounce back if self.__dy >= 0: self.__dy *= -1 else: # debug: keep the ball from sticking on the paddle pass # Clean up the hint sign self.window.remove(self.hint_sign) # the ball hits other item, pass elif self.corner_hits() is self.score_sign or self.corner_hits() is self.hint_sign or self.corner_hits() is self.reward \ or self.corner_hits() is self.live_2 or self.corner_hits() is self.live_1: pass # The ball hits the paddle elif self.corner_hits() is not None: # The thing hit by the ball need to be removed self.window.remove(self.corner_hits()) # Speed up and bounce self.__dy *= -1.005 self.__score += 10 # Show score self.show_score() # The reward will dropped everytime the user get 70 more score. if self.__score % 70 == 0 and self.can_drop: # Choose the dropping x position randomly t_x = random.choice(range(1, 10)) # Set up the reward object self.reward = GRect(10, 10, x=self.window.width * t_x // 10, y=self.window.height / 3) self.reward.filled = True self.reward.fill_color = 'darkslateblue' self.reward.color = 'darkslateblue' self.window.add(self.reward) self.can_move = True else: pass def show_score(self): """ This method remove the previous score sign and create a new one. """ self.window.remove(self.score_sign) self.score_sign = GLabel(f'SCORE : {self.__score}') self.score_sign.color = 'crimson' self.score_sign.font = 'Mamelon-20' self.window.add(self.score_sign, x=8, y=self.window.height - 8) # To check: if the reward is allowed to drop / if it was obtained or missed. def test_move(self): if self.can_move: self.can_drop = False self.reward.move(0, 5) # The user got the reward if self.window.get_object_at(self.reward.x + 7, self.reward.y + 15) is self.paddle: self.window.remove(self.reward) self.run_reward() self.can_move = False self.can_drop = True # The user miss the reward -- clean up if self.reward.y + 15 >= self.window.height: self.window.remove(self.reward) self.can_move = False self.can_drop = True def run_reward(self): """ This method uses random to choose a reward to run randomly. Also, it shows a sign for the running reward. Possible situation are listed below: 1. Make the paddle longer 2. Make the paddle shorter 3. Reverse the paddle's movement 4. Speed up the ball 5. Slow down the ball """ # Choose a reward randomly choice = random.choice(range(6)) self.window.remove(self.hint_sign) # paddle width ++ if choice == 0: self.window.remove(self.paddle) self.paddle_width += 20 self.paddle = GRect(self.paddle_width, self.paddle_height, x=self.paddle_x - self.paddle_width / 2, y=self.window_height - PADDLE_OFFSET - self.paddle_height) self.build_paddle() self.hint_sign = GLabel('ADD UP') self.show_hint() # paddle width -- elif choice == 1: self.paddle_adding = False if self.paddle_width <= 30: pass else: self.window.remove(self.paddle) self.paddle_width -= 30 self.paddle = GRect(self.paddle_width, self.paddle_height, x=self.paddle_x - self.paddle_width / 2, y=self.window_height - PADDLE_OFFSET - self.paddle_height) self.build_paddle() self.hint_sign = GLabel('WATCH OUT') self.show_hint() # Set reverse paddle movement elif choice == 2 or choice == 3: if self.reverse_paddle: self.reverse_paddle = False self.hint_sign = GLabel('REVERSE AGAIN') self.show_hint() else: self.reverse_paddle = True self.hint_sign = GLabel('REVERSE') self.show_hint() # Speed up the ball elif choice == 4: self.__dy *= 1.1 self.hint_sign = GLabel('SPEED UP') self.show_hint() # Slow down the ball else: self.__dy *= 0.9 self.hint_sign = GLabel('SLOW DOWN') self.show_hint() def build_paddle(self): """ This methods build up paddle for each reward. """ self.window.add(self.paddle) self.paddle.filled = True self.paddle.color = 'slategrey' self.paddle.fill_color = 'slategrey' def show_hint(self): """ This method shows a sign to tell user that clicking can earn rewards """ self.hint_sign.color = 'crimson' self.hint_sign.font = 'Mamelon-20' self.window.add(self.hint_sign, x=(self.window.width - self.hint_sign.width) / 2, y=self.window_height - PADDLE_OFFSET - PADDLE_HEIGHT - 30) def if_lose_life(self): """ This method check if the user lost life. If so, will reset the ball if there's still lives remain. """ if self.ball.y >= self.window.height: self.window.remove(self.ball) self.window.remove(self.hint_sign) self.__num_lives -= 1 if self.__num_lives == 2: # Build 1 point self.window.remove(self.live_1) elif self.__num_lives == 1: # empty self.window.remove(self.live_2) # Avoid being too hard for players to get ball with reverse paddle self.reverse_paddle = False self.__dy = INITIAL_Y_SPEED if self.__num_lives > 0: # User still has chances self.reset_ball() # Getter, to check if it's the end of the game (either win or lose) def end_game(self): if self.__num_lives <= 0 or self.__score >= self.__win_score: return True # To check if the game is over def game_over(self): if self.__num_lives <= 0: self.__enter_game = False return True def build_game_over(self): """ This method builds the 'Game Over' scene """ # delete the score line = GLine(4, self.window.height - 18, 12 + self.score_sign.width, self.window.height - 18) line.color = 'crimson' self.window.add(line) # Clean up self.window.remove(self.reward) self.window.remove(self.hint_sign) # Build up the 'Game Over' sign self.game_over_w.font = "Mamelon-35" self.game_over_w.color = 'midnightblue' self.window.add(self.game_over_w, x=(self.window.width - self.game_over_w.width) / 2, y=self.window.height / 2) # Create the movement of the 'Game Over' sign speed = self.__dy while True: self.game_over_w.move(0, speed) speed += 0.5 if self.game_over_w.y >= self.window.height * 2 // 3: speed *= -0.7 pause(10) # The sign will end with a shaking animation. # To check if the user won the game def win_game(self): if self.__score >= self.__win_score: return True def build_win(self): """ This method builds the 'Winning' scene """ win_sign_1 = GLabel('S A V A G E') win_sign_1.font = 'Mamelon-40' win_sign_1.color = 'mediumturquoise' win_sign_2 = GLabel('S A V A G E') win_sign_2.font = 'Mamelon-40' win_sign_2.color = 'mediumturquoise' win_sign_3 = GLabel('S A V A G E') win_sign_3.font = 'Mamelon-40' win_sign_3.color = 'mediumturquoise' # To create the flashing animation for i in range(12): if i % 2 != 0: self.window.add(win_sign_1, x=(self.window.width - win_sign_1.width) / 2, y=(self.window.height - win_sign_1.height) / 2) self.window.add( win_sign_2, x=(self.window.width - win_sign_2.width) / 2, y=(self.window.height - win_sign_2.height) / 2 + 50) self.window.add( win_sign_3, x=(self.window.width - win_sign_3.width) / 2, y=(self.window.height - win_sign_3.height) / 2 + 100) else: self.window.remove(win_sign_1) self.window.remove(win_sign_2) self.window.remove(win_sign_3) pause(100) self.fire_work() def fire_work(self): """ This method creates a firework animation. """ # Numbers of the firework for i in range(10): f_x = random.randint(self.window.width // 8, self.window.width * 7 // 8) f_y = random.randint(self.window.height // 10, self.window.height * 9 // 10) size = random.randint(4, 7) # The size of the firework for j in range(size): fire = GOval(10 + 20 * j, 10 + 20 * j, x=f_x - 10 * j, y=f_y - 10 * j) # Choose color randomly fire.color = self.choose_color() self.window.add(fire) pause(100) self.window.remove(fire) pause(500) @staticmethod def choose_color(): """ This method help choose the color for each circle of the firework randomly """ num = random.choice(range(6)) if num == 0: return "crimson" elif num == 1: return "midnightblue" elif num == 2: return "limegreen" elif num == 3: return "cyan" elif num == 4: return 'darkviolet' else: return "gold" def window_clear(self): """ This method clean up the whole window after the opening scene is over. """ self.window.clear() def set_opening(self): """ This method set up the whole opening scene. """ # To create the tube start_button_1 = GRect(60, 211, x=(self.window.width - 60) / 2, y=-1) start_button_1.color = 'slategrey' start_button_1.filled = True start_button_1.fill_color = 'slategrey' start_button_2 = GRect(50, 206, x=(self.window.width - 50) / 2) start_button_2.color = 'gainsboro' start_button_2.filled = True start_button_2.fill_color = 'gainsboro' self.window.add(start_button_1) self.window.add(start_button_2) head = GPolygon() head.add_vertex(((self.window.width - 60) / 2, 210)) head.add_vertex(((self.window.width - 60) / 2 + 60, 210)) head.add_vertex(((self.window.width - 60) / 2 + 60 + 20, 240)) head.add_vertex(((self.window.width - 60) / 2 - 20, 240)) head.color = 'slategrey' head.filled = True head.fill_color = 'slategrey' self.window.add(head) # Loading animation for i in range(10): load = GRect(40, 15, x=(self.window.width - 60) / 2 + 10, y=5 + 20 * i) load.filled = 'True' load.color = 'slategrey' load.fill_color = 'slategrey' self.window.add(load) pause(100) # Bouncing ball self.o_ball.filled = 'True' self.o_ball.color = 'crimson' self.o_ball.fill_color = 'crimson' self.window.add(self.o_ball) ball_vy = 5 count = 0 while True: self.o_ball.move(0, ball_vy) ball_vy += 1 if self.o_ball.y + 30 >= self.window.height: ball_vy *= -0.9 count += 1 if count == 5 and ball_vy >= 0: break pause(10) self.window.remove(self.o_ball) # Blowing balloon animation for i in range(55): self.o_ball = GOval(30 + i, 30 + i, x=(self.window.width - 30 + i) / 2 - i, y=415 - i) self.o_ball.filled = 'True' self.o_ball.color = 'crimson' self.o_ball.fill_color = 'crimson' self.window.add(self.o_ball) pause(7) # Flashing start sign animation for i in range(10): self.start_button.font = 'Mamelon-20' if i % 2 == 0: self.start_button.color = 'crimson' else: self.start_button.color = 'snow' self.window.add(self.o_ball) self.window.add(self.start_button, x=(self.window.width - 64) / 2, y=413) pause(100) # Show the rules rule_1 = GLabel('3 LIVES.') rule_1.color = 'darkslategrey' rule_1.font = 'Mamelon-20' rule_2 = GLabel("CATCH ' ' FOR RANDOM EFFECTS.") rule_2.color = 'darkslategrey' rule_2.font = 'Mamelon-20' rule_3 = GLabel('SCORE 1000 ---> FIREWORKS.') rule_3.color = 'crimson' rule_3.font = 'Mamelon-20' square = GRect(10, 10, x=self.window.width / 10 + 63, y=self.window.height * 4 // 5 + 10) square.filled = True square.fill_color = 'darkslateblue' square.color = 'darkslateblue' self.window.add(square) self.window.add(rule_1, x=self.window.width / 10, y=self.window.height * 4 // 5) self.window.add(rule_2, x=self.window.width / 10, y=self.window.height * 4 // 5 + 25) self.window.add(rule_3, x=self.window.width / 10, y=self.window.height * 4 // 5 + 50)
class BreakoutGraphics: def __init__(self, ball_radius=BALL_RADIUS, paddle_width=PADDLE_WIDTH, paddle_height=PADDLE_HEIGHT, paddle_offset=PADDLE_OFFSET, brick_rows=BRICK_ROWS, brick_cols=BRICK_COLS, brick_width=BRICK_WIDTH, brick_height=BRICK_HEIGHT, brick_offset=BRICK_OFFSET, brick_spacing=BRICK_SPACING, title='Breakout'): # Create a graphical window, with some extra space. window_width = brick_cols * (brick_width + brick_spacing) - brick_spacing window_height = brick_offset + 3 * (brick_rows * (brick_height + brick_spacing) - brick_spacing) self.window = GWindow(width=window_width, height=window_height, title=title) # Create a paddle. self.paddle = GRect(paddle_width, paddle_height) self.paddle.filled = True self.paddle.fill_color = 'black' # set paddle's instance variable self.pad_width = paddle_width self.pad_height = paddle_height self.pad_offset = paddle_offset """ go will be a variable set to 0 or 1 go equal 1 means it's touch paddle already and go to bricks go equals 0 means it's touch bricks and can go back to paddle """ self.go = 0 # set ball's instance variable self.radius = ball_radius # Center a filled ball in the graphical window. self.ball = GOval(2 * self.radius, 2 * self.radius) self.set_ball() # start set_ball method # set brick's instance variable self.bri_width = brick_width self.bri_height = brick_height self.bri_cols = brick_cols self.bri_rows = brick_rows self.bri_spacing = brick_spacing self.bri_offset = brick_offset self.brick = GRect(self.bri_width, self.bri_height) self.tot_brick = brick_rows * brick_cols self.move_brick = 0 # Default initial velocity for the ball. self.__dx = 0 # use to storage the x speed self.__dy = 0 # use to storage the y speed self.dx = self.get_dx() # get the x speed self.dy = self.get_dy() # get the y speed # Initialize our mouse listeners. onmouseclicked(self.mouse_click) onmousemoved(self.paddle_move) # Draw bricks. self.set_brick() # set label for the text self.dead_label = GLabel('') self.cry_label = GLabel('') self.win_label = GLabel('') self.smile_label = GLabel('') def dead(self): """ if the lives equal zero, it mean the player dead. so it will remove the ball and show you are dead """ self.window.remove(self.ball) # remove the ball self.dead_label = GLabel('You are dead') # add label context self.dead_label.font = 'courier-40' # set text size and type self.cry_label = GLabel('(〒︿〒)') # add label context self.cry_label.font = 'courier-30' # set text size and type self.window.add(self.dead_label, x=self.window.width / 2 - 195, y=self.window.height / 2) # add on windows of specific location self.window.add(self.cry_label, x=self.window.width / 2 - 80, y=(self.window.height / 2 + 80)) # add on windows of specific location def win(self): """ if all the bricks are remove, it means you win the game """ self.window.remove(self.ball) # remove the ball self.win_label = GLabel('Congratulation') # add label context self.win_label.font = 'courier-40' # set text size and type self.smile_label = GLabel('(ノ>ω<)ノ') # add label context self.smile_label.font = 'courier-30' # set text size and type self.window.add(self.win_label, x=self.window.width / 2 - 250, y=self.window.height / 2) # add on windows of specific location self.window.add(self.smile_label, x=self.window.width / 2 - 85, y=(self.window.height / 2 + 80)) # add on windows of specific location def set_ball(self): """ let a ball filled with color """ self.ball.filled = True # True to fill color self.ball.fill_color = 'navy' # choose the color self.__dy = 0 # speed of initial position of the ball self.__dx = 0 # speed of initial position of the ball """ put the ball on a specific location on window """ self.window.add(self.ball, x=(self.window.width - self.radius) / 2, y=(self.window.height - self.radius) / 2) def detect_brick(self): """ use four corner to detect if it touch a brick or not maybe_obj1 to maybe_obj4 is use to get if there is object or not """ maybe_obj1 = self.window.get_object_at(self.ball.x, self.ball.y) maybe_obj2 = self.window.get_object_at(self.ball.x, self.ball.y + (2 * self.radius)) maybe_obj3 = self.window.get_object_at(self.ball.x + (2 * self.radius), self.ball.y) maybe_obj4 = self.window.get_object_at(self.ball.x + (2 * self.radius), self.ball.y + (2 * self.radius)) if maybe_obj1 is not self.paddle and maybe_obj1 is not None: # if it has object and is not paddle - means brick self.window.remove(maybe_obj1) # remove the object self.__dy = -self.__dy # change the direction self.go = 0 # ball can touch the paddle now self.move_brick += 1 # number of remove brick plus 1 elif maybe_obj2 is not self.paddle and maybe_obj2 is not None: # if it has object and is not paddle - means brick self.window.remove(maybe_obj2) # remove the object self.__dy = -self.__dy # change the direction self.go = 0 # ball can touch the paddle now self.move_brick += 1 # number of remove brick plus 1 elif maybe_obj3 is not self.paddle and maybe_obj3 is not None: # if it has object and is not paddle - means brick self.window.remove(maybe_obj3) # remove the object self.__dy = -self.__dy # change the direction self.go = 0 # ball can touch the paddle now self.move_brick += 1 # number of remove brick plus 1 elif maybe_obj4 is not self.paddle and maybe_obj4 is not None: # if it has object and is not paddle - means brick self.window.remove(maybe_obj4) # remove the object self.__dy = -self.__dy # change the direction self.go = 0 # ball can touch the paddle now self.move_brick += 1 # number of remove brick plus 1 def detect_paddle(self): """ use four corner to detect if it touch a paddle or not maybe_obj1 to maybe_obj4 is use to get if there is object or not """ maybe_obj1 = self.window.get_object_at(self.ball.x, self.ball.y) maybe_obj2 = self.window.get_object_at(self.ball.x + (2 * self.radius), self.ball.y) maybe_obj3 = self.window.get_object_at(self.ball.x + (2 * self.radius), self.ball.y) maybe_obj4 = self.window.get_object_at(self.ball.x + (2 * self.radius), self.ball.y + (2 * self.radius)) if self.go == 0: # go is use to let the ball detect the paddle only one times if maybe_obj1 is self.paddle: # if it is paddle self.__dy = -self.__dy # change the direction self.go = 1 # go equal 1 means it's touch and go to bricks elif maybe_obj2 is self.paddle: # if it is paddle self.__dy = -self.__dy # change the direction self.go = 1 # go equal 1 means it's touch and go to bricks elif maybe_obj3 is self.paddle: # if it is paddle self.__dy = -self.__dy # change the direction self.go = 1 # go equal 1 means it's touch and go to bricks elif maybe_obj4 is self.paddle: # if it is paddle self.__dy = -self.__dy # change the direction self.go = 1 # go equal 1 means it's touch and go to bricks def mouse_click(self, event): """ if the x speed of ball and y speed of the ball is 0, it means it's a new start, and click will let the ball move :param event: mouse detect """ if self.__dx == 0 and self.__dy == 0: # x speed and y speed is both zero self.set_ball_velocity() # decide the velocity of ball self.move_ball() # ball move def wall_collision(self): """ 1.touch the wall, and it need to change the direction, beside, consider that it may not touch brick to reflect to paddle, so when touch the wall, go also need to change into 0 2. ball can not touch the bottom of window, it will cause dead, using other way to figure iy out """ if self.ball.x <= 0 or self.ball.x + self.ball.width >= self.window.width: # touch the right and left wall self.__dx = -self.__dx # change the direction self.go = 0 # it can touch the paddle now if self.ball.y <= 0: # touch the up wall self.__dy = -self.__dy # change the direction self.go = 0 # it can touch the paddle now def set_ball_velocity(self): """ let the ball have speed and have different way to move forward """ self.__dx = random.randint( 0, MAX_X_SPEED) # choose a speed rate from 0 and MAX_X_SPEED self.__dy = random.randint( 0, INITIAL_Y_SPEED) # choose a speed rate from 0 and INITIAL_Y_SPEED if self.__dx == 0: # let ball not just move up and down self.__dx = random.randint(0, MAX_X_SPEED) # re-choose a x speed rate if self.__dy == 0: # let the ball not just move left and right self.__dy = random.randint( 0, INITIAL_Y_SPEED) # re-choose a y speed rate if random.random( ) > 0.5: # let the ball have 50-50 chance to move left or right self.__dx = -self.__dx # set to have opposite way if random.random( ) > 0.5: # let the ball have 50-50 chance to move up or down self.__dy = -self.__dy # set to have opposite way def move_ball(self): """ ball move with the speed __dx and __dy """ self.ball.move(self.__dx, self.__dy) def get_dx(self): """ set a getter to get x speed :return: the value of x speed """ return self.__dx # return the x speed def get_dy(self): """ getter to get y speed :return: the value of y speed """ return self.__dy # return the y speed def paddle_move(self, mouse): """ mouse detect to let paddle follow the mouse :param mouse: mouse detect """ paddle_x_position = mouse.x - (self.pad_width / 2 ) # set into middle part of paddle if mouse.x + self.pad_width >= self.window.width: # when the mouse on left side outside of windoe paddle_x_position = self.window.width - self.pad_width # x set into left of window if mouse.x - self.pad_width <= 0: # when the mouse on the right side outside of window paddle_x_position = 0 # x position set into right of window """ add paddle into specific location on the window """ self.window.add(self.paddle, x=paddle_x_position, y=self.window.height - self.pad_offset - self.pad_height) def set_brick(self): """ set brick into initial position """ brick_width_in_window = 0 # initial position of brick in x brick_height_in_window = self.bri_offset # initial position of brick in y for i in range( self.bri_rows): # for loop based on how many rows it has for j in range(self.bri_cols ): # for loop based on how many columns it has self.brick = GRect(self.bri_width, self.bri_height) # set a brick self.brick.filled = True # True to fill with color if j % 4 == 0: # base on the columns to choose color self.brick.fill_color = 'red' self.brick.color = 'red' if j % 4 == 1: # base on the columns to choose color self.brick.fill_color = 'salmon' self.brick.color = 'salmon' if j % 4 == 2: # base on the columns to choose color self.brick.fill_color = 'orange' self.brick.color = 'orange' if j % 4 == 3: # base on the columns to choose color self.brick.fill_color = 'tomato' self.brick.color = 'tomato' self.window.add( self.brick, x=brick_width_in_window, y=brick_height_in_window) # add brick to windows """ move forward to next columns position, include brick width and spacing """ brick_width_in_window += self.bri_width brick_width_in_window += self.bri_spacing brick_width_in_window = 0 # all the row start at x = 0 """ move forward to next rows position, include brick height and spacing """ brick_height_in_window += self.bri_height brick_height_in_window += self.bri_spacing
class BreakoutGraphics: def __init__(self, ball_radius=BALL_RADIUS, paddle_width=PADDLE_WIDTH, paddle_height=PADDLE_HEIGHT, paddle_offset=PADDLE_OFFSET, brick_rows=BRICK_ROWS, brick_cols=BRICK_COLS, brick_width=BRICK_WIDTH, brick_height=BRICK_HEIGHT, brick_offset=BRICK_OFFSET, brick_spacing=BRICK_SPACING, title='Breakout'): self.game_started = False # Create a graphical window, with some extra space. window_width = brick_cols * (brick_width + brick_spacing) - brick_spacing window_height = brick_offset + 3 * (brick_rows * (brick_height + brick_spacing) - brick_spacing) self.window = GWindow(width=window_width, height=window_height, title=title) # Create a score and a live self.sscore = GLabel('{score}: 0') self.sscore.font = '-20' self.window.add(self.sscore, x=0, y=self.sscore.height + 20) self.live = GLabel('3 :{live}') self.live.font = '-20' self.window.add(self.live, x=window_width - self.live.width, y=self.live.height + 20) # Create a paddle. self.paddle = GRect(paddle_width, paddle_height, x=window_width // 2 - paddle_width // 2, y=window_height - paddle_offset) self.paddle.filled = True self.window.add(self.paddle) # Center a filled ball in the graphical window. self.ball = GOval(ball_radius * 2, ball_radius * 2, x=window_width // 2 - ball_radius, y=window_height // 2 - ball_radius) self.ball.filled = True self.window.add(self.ball) # Default initial velocity for the ball. self.__dyr__dxr() # Initialize our mouse listeners. onmousemoved(self.move_paddle) onmouseclicked(self.start) # Draw bricks. for cols in range(brick_cols): for row in range(brick_rows): block = GRect(brick_width, brick_height) self.block = block block.filled = True block.color = self.block_color(cols) block.fill_color = self.block_color(cols) self.window.add(block, x=(block.width + brick_spacing) * row, y=brick_offset + (brick_spacing + block.height) * cols) # draw a disturb playing block self.brick_width = brick_width self.disturb = GRect(brick_width + 20, brick_height, x=self.window.width - brick_width, y=250) self.disturb.color = 'magenta' self.disturb.filled = True self.disturb.fill_color = 'magenta' self.window.add(self.disturb) self.d = -1 # set self self.brick_c = brick_cols self.brick_row = brick_rows def __dyr__dxr(self): """ set __dx and __dy """ self.__dy = INITIAL_Y_SPEED self.__dx = random.randint(1, MAX_X_SPEED) if (random.random() > 0.5): self.__dx = -self.__dx def block_color(self, c): """ :param c: brick's cols :return: the brick's color """ if int(c // 2) == 0: return 'red' elif int(c // 2) == 1: return 'orange' elif int(c // 2) == 2: return 'yellow' elif int(c // 2) == 3: return 'green' elif int(c // 2) == 4: return 'blue' def move_paddle(self, event): """ :param event: mouse """ if not event.x < 0 + self.paddle.width // 2 and not event.x + self.paddle.width // 2 > self.window.width: self.paddle.x = event.x - self.paddle.width // 2 def get_dx(self): """ :return __dx: the speed of the ball x """ return self.__dx def get_dy(self): """ :return __dy: the speed of the ball y """ return self.__dy def bounce_ball(self, dx, dy, lives, score, delay, score2): """ :param dx: the speed of the ball x :param dy: the speed of the ball y :param lives: the lives you left :param score: the score you have :param delay: the pause time :return lives, score, delay: the lives , score, pause time """ self.disturb.x += self.d self.d -= 1 if self.disturb.x <= 0: self.d = -self.d elif self.disturb.x > self.window.width - self.disturb.width: self.disturb.x = self.window.width - self.brick_width - 50 self.d = -1 # bounce at the edge if self.ball.x + self.ball.width > self.window.width or self.ball.x < 0: # x if self.ball.y + self.ball.width > self.window.height or self.ball.y < 0: # if the ball bounce at the corner dx *= -1 dy *= -1 else: dx *= -1 elif self.ball.y < 0: # y if self.ball.x + self.ball.width > self.window.width or self.ball.x < 0: # if the ball bounce at the corner dy *= -1 dx *= -1 else: dy *= -1 elif self.ball.y + self.ball.width > self.window.height: # if the ball bounce at the ground lives -= 1 # live - 1 self.game_started = False # the ball is not bouncing now self.ball.x = self.window.width // 2 - self.ball.width // 2 self.ball.y = self.window.height // 2 - self.ball.width // 2 self.__dyr__dxr() self.sscore.text = '{score}: ' + str(score) self.live.text = str(lives) + ' :{live}' return lives, score, delay, score2, self.brick_c * self.brick_row # bounce at the block elif self.window.get_object_at(self.ball.x, self.ball.y): maybe_obj = self.window.get_object_at(self.ball.x, self.ball.y) if self.ball.y > 50: if self.ball.y < 250 and self.ball.y > 49: self.window.remove(maybe_obj) score += self.score(maybe_obj.y) score2 += 1 delay -= 0.2 elif self.ball.y > 350: self.ball.y = self.paddle.y - self.ball.height if self.ball.y > 49: dy *= -1 elif self.window.get_object_at(self.ball.x + BALL_RADIUS * 2, self.ball.y): maybe_obj = self.window.get_object_at( self.ball.x + self.ball.width, self.ball.y) if self.ball.y > 50: if self.ball.y < 250 and self.ball.y > 49: self.window.remove(maybe_obj) score += self.score(maybe_obj.y) score2 += 1 delay -= 0.2 elif self.ball.y > 350: self.ball.y = self.paddle.y - self.ball.height if self.ball.y > 49: dy *= -1 elif self.window.get_object_at(self.ball.x, self.ball.y + self.ball.width): maybe_obj = self.window.get_object_at( self.ball.x, self.ball.y + self.ball.width) if self.ball.y > 50: if self.ball.y + self.ball.width < 250 and self.ball.y + self.ball.width > 49: self.window.remove(maybe_obj) score += self.score(maybe_obj.y) score2 += 1 delay -= 0.2 elif self.ball.y > 350: self.ball.y = self.paddle.y - self.ball.height if self.ball.y > 49: dy *= -1 elif self.window.get_object_at(self.ball.x + self.ball.width, self.ball.y + self.ball.width): maybe_obj = self.window.get_object_at( self.ball.x + self.ball.width, self.ball.y + self.ball.width) if self.ball.y > 50: if self.ball.y + self.ball.width < 250 and self.ball.y + self.ball.width > 49: self.window.remove(maybe_obj) score += self.score(maybe_obj.y) score2 += 1 delay -= 0.2 elif self.ball.y > 350: self.ball.y = self.paddle.y - self.ball.height if self.ball.y > 49: dy *= -1 self.ball.move(dx, dy) self.__dx = dx self.__dy = dy self.sscore.text = '{score}: ' + str(score) self.live.text = str(lives) + ' :{live}' return lives, score, delay, score2, self.brick_c * self.brick_row def start(self, event): """ :param event: mouse """ if not self.game_started: self.game_started = True def get_game_state(self): """ :return game_start: is the game running? """ return self.game_started def score(self, y): if y < 80: return 5 elif y < 120: return 4 elif y < 160: return 3 elif y < 200: return 2 elif y < 240: return 1 def remove_all(self, score): self.window.remove(self.ball) self.window.remove(self.paddle) self.window.remove(self.sscore) self.window.remove(self.live) self.window.remove(self.disturb) if score == 300: win = GLabel('YOU WIN!! . . YA!!!!!!!!!\n U', x=50, y=350) win.font = '-20' self.window.add(win) else: sscore = GLabel('YOUR SCORE IS:' + str(score) + '\n HA HA HA YOU LOSE!!!', x=50, y=350) sscore.font = '-20' self.window.add(sscore)
class BreakoutGraphics: def __init__(self, ball_radius=BALL_RADIUS, paddle_width=PADDLE_WIDTH, paddle_height=PADDLE_HEIGHT, paddle_offset=PADDLE_OFFSET, brick_rows=BRICK_ROWS, brick_cols=BRICK_COLS, brick_width=BRICK_WIDTH, brick_height=BRICK_HEIGHT, brick_offset=BRICK_OFFSET, brick_spacing=BRICK_SPACING, title='Breakout'): # Create a graphical window, with some extra space. self.window_width = brick_cols * (brick_width + brick_spacing) - brick_spacing self.window_height = brick_offset + 3 * (brick_rows * (brick_height + brick_spacing) - brick_spacing) self.window = GWindow(width=self.window_width, height=self.window_height, title=title) # Create a paddle. self.paddle = GRect(width=PADDLE_WIDTH, height=PADDLE_HEIGHT, x=(self.window_width-PADDLE_WIDTH)/2, y=self.window_height-PADDLE_OFFSET+paddle_height) self.paddle.color = 'Navy' self.paddle.filled = True self.paddle.fill_color = 'Navy' self.window.add(self.paddle) # Center a filled ball in the graphical window. self.ball = GOval(width=2*ball_radius, height=2*ball_radius, x=self.window_width/2-ball_radius, y=(self.window_height-PADDLE_HEIGHT)/2) self.ball.filled = True self.ball.color = 'red' self.ball.fill_color = 'red' self.window.add(self.ball) # Default initial velocity for the ball. self.__dy = INITIAL_Y_SPEED self.__dx = random.randint(1, MAX_X_SPEED) if random.random() > 0.5: self.__dx = -self.__dx self.ball_radius = BALL_RADIUS self.switch = False # Initialize our mouse listeners. onmouseclicked(self.start) onmousemoved(self.paddle_move) # Draw bricks. for i in range(brick_rows): for j in range(brick_cols): self.brick = GRect(width=brick_width, height=brick_height) self.window.add(self.brick, x=(brick_width+brick_spacing)*j, y=BRICK_OFFSET+(brick_height+brick_spacing)*i) self.brick.filled = True if i <= 1: self.brick.color = 'red' self.brick.fill_color = 'red' elif 2 <= i <= 3: self.brick.color = 'orange' self.brick.fill_color = 'orange' elif 4 <= i <= 5: self.brick.color = 'yellow' self.brick.fill_color = 'yellow' elif 6 <= i <= 7: self.brick.color = 'green' self.brick.fill_color = 'green' elif 8 <= i <= 9: self.brick.color = 'blue' self.brick.fill_color = 'blue' else: self.brick.color = 'grey' self.brick.fill_color = 'grey' self.check_hit_object() self.brick_counts = BRICK_ROWS * BRICK_COLS def check_hit_object(self): a = self.window.get_object_at(self.ball.x, self.ball.y) b = self.window.get_object_at(self.ball.x+2*self.ball_radius, self.ball.y) c = self.window.get_object_at(self.ball.x, self.ball.y+2*self.ball_radius) d = self.window.get_object_at(self.ball.x+2*self.ball_radius, self.ball.y+2*self.ball_radius) if c is self.paddle or d is self.paddle: self.__dy = -1 * self.__dy elif a is not None and a is not self.paddle: self.window.remove(a) self.__dy = -1 * self.__dy self.brick_counts -= 1 elif b is not None and b is not self.paddle: self.window.remove(b) self.__dy = -1 * self.__dy self.brick_counts -= 1 elif c is not None and c is not self.paddle: self.window.remove(c) self.__dy = -1 * self.__dy self.brick_counts -= 1 elif d is not None and d is not self.paddle: self.window.remove(d) self.__dy = -1 * self.__dy self.brick_counts -= 1 def get_vy(self): return self.__dy def get_vx(self): return self.__dx def start(self, event): self.switch = True def ball_move(self, vx, vy): self.ball.move(dx=vx, dy=vy) def paddle_move(self, mouse): if self.paddle.width/2 < mouse.x <= self.window.width-(self.paddle.width / 2): self.paddle.x = mouse.x-self.paddle.width/2 elif mouse.x <= self.paddle.width/2: self.paddle.x = 0 elif mouse.x >= self.window.width-(self.paddle.width/2): self.paddle.x = self.window.width-self.paddle.width def set_vx(self, new_speed): self.__dx = new_speed def set_vy(self, new_speed): self.__dy = new_speed def reset(self): self.switch = False self.ball.x = self.window_width/2-self.ball_radius self.ball.y = (self.window_height-PADDLE_HEIGHT)/2
class BreakoutGraphics: def __init__(self, ball_radius=BALL_RADIUS, paddle_width=PADDLE_WIDTH, paddle_height=PADDLE_HEIGHT, paddle_offset=PADDLE_OFFSET, brick_rows=BRICK_ROWS, brick_cols=BRICK_COLS, brick_width=BRICK_WIDTH, brick_height=BRICK_HEIGHT, brick_offset=BRICK_OFFSET, brick_spacing=BRICK_SPACING, title='Breakout'): self.ball_radius = ball_radius self.over = GLabel('GAME OVER') self.over.color = 'red' # Create a graphical window, with some extra space. self.window_width = brick_cols * (brick_width + brick_spacing) - brick_spacing self.window_height = brick_offset + 3 * ( brick_rows * (brick_height + brick_spacing) - brick_spacing) self.window = GWindow(width=self.window_width, height=self.window_height, title=title) # Create a paddle. self.pad = GRect(paddle_width, paddle_height) self.pad.filled = True self.pad.fill_color = 'black' self.window.add(self.pad, x=(self.window_width - paddle_width) / 2, y=self.window_height - paddle_offset) # Default initial velocity for the ball. self.__dx = 0 self.__dy = 0 # Initialize our mouse listeners. onmousemoved(self.move_pad) onmouseclicked(self.start_check) # the checker to decide whether the game can start,if 1, start, if 0, pending self.chk = 0 # Draw bricks. for y in range( brick_offset, brick_rows * (brick_height + brick_spacing) + brick_offset, brick_height + brick_spacing): for x in range(0, self.window_width - brick_width + 1, brick_width + brick_spacing): self.brick = GRect(brick_width, brick_height) self.brick.filled = True self.brick.fill_color = 'yellow' self.brick.color = 'green' self.window.add(self.brick, x=x, y=y) self.num_bricks = brick_cols * brick_rows # Center a filled ball in the graphical window. self.ball = GOval(ball_radius * 2, ball_radius * 2) self.ball.filled = True self.ball.fill_color = 'navy' self.ball.color = 'blue' self.window.add(self.ball, x=self.window_width / 2 - ball_radius, y=self.window_height / 2 - ball_radius) def move_pad(self, event): """ To make the paddle moves following the mouse :param event: int, the coordinate(x,y) of the mouse """ if event.x < self.pad.width / 2: self.pad.x = 0 elif event.x > self.window.width - self.pad.width / 2: self.pad.x = self.window.width - self.pad.width else: self.pad.x = event.x - self.pad.width / 2 def get_dx(self): """ To return the hidden object dx :return: int, the distance to move on x-coordinate per movement """ return self.__dx def get_dy(self): """ To return the hidden object dy :return: int, the distance to move on y-coordinate per movement """ return self.__dy def reset_ball(self): """ To set the ball at initial position and resetting chk to 0 """ self.window.add(self.ball, x=self.window_width / 2 - self.ball_radius, y=self.window_height / 2 - self.ball_radius) self.chk = 0 def start_check(self, m): """ Check if the ball is at the center, if yes, start bouncing; if no, the click is ignored """ if self.ball.x == self.window_width / 2 - self.ball_radius and self.ball.y == self.window_height / 2 - \ self.ball_radius and self.num_bricks > 0: self.__dx = random.randint(1, MAX_X_SPEED) self.__dy = INITIAL_Y_SPEED if (random.random()) > 0.5: self.__dx = -self.__dx self.chk = 1 def get_chk(self): """ To return chk :return: int, the checker to detect whether the game should starts """ return self.chk def check_collision(self): """ Check if the 4 vertex touch paddle or brick :return: str or object, to indicate if the ball touches anything """ for i in range(0, self.ball_radius * 2 + 1, self.ball_radius * 2): for j in range(0, self.ball_radius * 2 + 1, self.ball_radius * 2): is_obj = self.window.get_object_at(self.ball.x + j, self.ball.y + i) if is_obj is not None: if is_obj is self.pad: self.ball.move(0, -self.pad.height) print('touch pad') return 'pad' else: self.window.remove(is_obj) self.num_bricks -= 1 print('touch brick') return 'brick' return 'not collide'
class BreakoutGraphics: # Constructor def __init__(self, ball_radius=BALL_RADIUS, paddle_width=PADDLE_WIDTH, paddle_height=PADDLE_HEIGHT, paddle_offset=PADDLE_OFFSET, brick_rows=BRICK_ROWS, brick_cols=BRICK_COLS, brick_width=BRICK_WIDTH, brick_height=BRICK_HEIGHT, brick_offset=BRICK_OFFSET, brick_spacing=BRICK_SPACING, title='Breakout'): # Create a graphical window, with some extra space. window_width = brick_cols * (brick_width + brick_spacing) - brick_spacing window_height = brick_offset + 3 * (brick_rows * (brick_height + brick_spacing) - brick_spacing) self.window = GWindow(width=window_width, height=window_height, title=title) # Create a paddle. self.paddle = GRect(paddle_width, paddle_height) self.paddle.filled = True self.window.add(self.paddle, x=(window_width - self.paddle.width) / 2, y=window_height - paddle_offset) # Center a filled ball in the graphical window. self.ball = GOval(ball_radius * 2, ball_radius * 2) self.ball.filled = True self.window.add(self.ball, x=(window_width - ball_radius) / 2, y=(window_height - ball_radius) / 2) # Default initial velocity for the ball. self.__dx = random.randint(1, MAX_X_SPEED) if random.random() > 0.5: self.__dx = -self.__dx self.__dy = INITIAL_Y_SPEED # Initialize our mouse listeners. onmouseclicked(self.game_start) # Todo: Need fixing!!! self.mouse_lock = False onmousemoved(self.paddle_move) # Draw bricks. for i in range(brick_rows): self.brick_x = 0 self.brick_y = brick_offset self.brick_y += (brick_height + brick_spacing) * i for j in range(brick_cols): self.brick = GRect(brick_width, brick_height) self.brick.filled = True self.brick_color(i) self.window.add(self.brick, x=self.brick_x, y=self.brick_y) self.brick_x += (brick_width + brick_spacing) self.brick_left = brick_rows * brick_cols # For detecting whether ball hit objects. self.obj = 0 # Methods def game_start(self, event): # Todo: Need fixing!! """ To detect whether the game has started or not. If not, the game will start and turns the mouse lock on (True). If yes, further mouse clicks should have no effects. """ self.mouse_lock = True def move_ball(self): """ Ball move by the velocity of __dx and __dy as defined in the constructor. """ self.ball.move(self.__dx, self.__dy) def reset_ball(self): """ Reset the ball back to its initial position. Mouse lock off (False). """ self.ball.x = (self.window.width - self.ball.width) / 2 self.ball.y = (self.window.height - self.ball.height) / 2 self.mouse_lock = False def handle_collision(self): """ Updates __dx and __dy depending on whether or not ball has hit a wall, the paddle or bricks. """ # Hit left/right wall if self.ball.x <= 0 or self.ball.x >= self.window.width - self.ball.width: self.__dx = -self.__dx # Hit top/bottom wall if self.ball.y <= 0 or self.ball.y >= self.window.height - self.ball.height: self.__dy = -self.__dy # Hit paddles/bricks self.detect_obj() self.hit_paddle_or_bricks() def detect_obj(self): """ Detect if the ball hit any objects. """ self.obj = self.window.get_object_at(self.ball.x, self.ball.y) if self.obj is not None: return self.obj else: self.obj = self.window.get_object_at(self.ball.x, self.ball.y + self.ball.width) if self.obj is not None: return self.obj else: self.obj = self.window.get_object_at( self.ball.x + self.ball.width, self.ball.y) if self.obj is not None: return self.obj else: self.obj = self.window.get_object_at( self.ball.x + self.ball.width, self.ball.y + +self.ball.width) if self.obj is not None: return self.obj else: return None def hit_paddle_or_bricks(self): """ Identify whether the object(s) hit is the paddle or brick. """ if self.obj == self.paddle: self.__dy = -self.__dy elif self.obj is not None and self.obj is not self.paddle: self.__dy = -self.__dy self.window.remove(self.obj) self.brick_left -= 1 def ball_out(self): """ Return whether or not the ball has fallen below the paddle/bottom wall. """ is_ball_out = self.ball.y >= self.window.height - self.ball.height return is_ball_out def paddle_move(self, event): """ Sync the center of the paddle and the location of the mouse while moving. """ if event.x - self.paddle.width / 2 <= 0: self.paddle.x = 0 elif self.window.width - event.x <= self.paddle.width / 2: self.paddle.x = self.window.width - self.paddle.width else: self.paddle.x = event.x - self.paddle.width / 2 def brick_color(self, i): """ Sets the bricks in color designated in the handout. """ if i <= 1: self.brick.fill_color = 'red' elif 1 < i <= 3: self.brick.fill_color = 'orange' elif 3 < i <= 5: self.brick.fill_color = 'yellow' elif 5 < i <= 7: self.brick.fill_color = 'green' elif 7 < i <= 9: self.brick.fill_color = 'blue' else: pass
class BreakoutGraphics: def __init__(self, ball_radius=BALL_RADIUS, paddle_width=PADDLE_WIDTH, paddle_height=PADDLE_HEIGHT, paddle_offset=PADDLE_OFFSET, brick_rows=BRICK_ROWS, brick_cols=BRICK_COLS, brick_width=BRICK_WIDTH, brick_height=BRICK_HEIGHT, brick_offset=BRICK_OFFSET, brick_spacing=BRICK_SPACING, title='Breakout'): """ The basic parameters for building these breakout game. :param ball_radius: The radius of the ball. :param paddle_width: The width of the paddle. :param paddle_height: The height of the paddle. :param paddle_offset: The distance between paddle and the bottom of the window. :param brick_rows: The number of rows in bricks. :param brick_cols: The number of column in bricks. :param brick_width: The width of each brick. :param brick_height: The height of each brick. :param brick_offset: The distance between the first row of bricks and the top of the window. :param brick_spacing: The spacing between each brick. :param title: The name of this program. """ # Create a graphical window, with some extra space self.window_width = brick_cols * (brick_width + brick_spacing) - brick_spacing self.window_height = brick_offset + 3 * ( brick_rows * (brick_height + brick_spacing) - brick_spacing) self.window = GWindow(width=self.window_width, height=self.window_height, title=title) # Create a paddle self.paddle = GRect(paddle_width, paddle_height, x=(self.window_width - paddle_width) / 2, y=(self.window_height - paddle_offset)) self.paddle.filled = True self.paddle.color = 'black' self.paddle.fill_color = 'black' self.window.add(self.paddle) self.paddle_width = paddle_width self.paddle_height = paddle_height self.paddle_offset = paddle_offset # Center a filled ball in the graphical window self.ball = GOval(ball_radius * 2, ball_radius * 2, x=(self.window_width - ball_radius * 2) / 2, y=(self.window_height - ball_radius * 2) / 2) self.ball.filled = True self.ball.fill_color = 'black' self.window.add(self.ball) self.ball_radius = ball_radius # Default initial velocity for the ball self.__dx = 0 # self.__dx = random.randint(1, MAX_X_SPEED) self.__dy = 0 # self.__dy = INITIAL_Y_SPEED # if random.random() > 0.5: # self.__dx = -self.__dx # The above is the mistake I made during doing this homework. # Draw bricks for i in range(brick_cols): for j in range(brick_rows): # Crucial point! This can't be placed at the outside of for loop. brick = GRect(brick_width, brick_height) brick.x = (brick_width + brick_spacing) * i brick.y = brick_offset + (brick_height + brick_spacing) * j brick.filled = True if j < 2: brick.fill_color = 'red' elif j < 4: brick.fill_color = 'orange' elif j < 6: brick.fill_color = 'yellow' elif j < 8: brick.fill_color = 'green' elif j < 10: brick.fill_color = 'blue' elif j < 12: brick.fill_color = 'teal' elif j < 14: brick.fill_color = 'chocolate' self.window.add(brick) # Initialize our mouse listeners onmouseclicked(self.is_start_game) onmousemoved(self.moving_paddle) # Total bricks self.total_bricks = brick_cols * brick_rows def is_start_game( self, event ): # Crucial point!!! Stuck here for three days! The initial velocity! """ The check point of the game start. :param event: The information of the mouse, including (x,y) of it. :return: Set the __dx and __dy of the ball. """ if event.x != -1 and event.y != -1 and self.__dx == 0 and self.__dy == 0: self.__dx = random.randint(1, MAX_X_SPEED) self.__dy = INITIAL_Y_SPEED if random.random() > 0.5: self.__dx = -self.__dx def check_for_collisions(self): """ Four check points of the ball to check the collision with objects. :return: boolean value. Build the information of object that the ball collide with. """ one = self.window.get_object_at(self.ball.x, self.ball.y) two = self.window.get_object_at(self.ball.x + 2 * self.ball_radius, self.ball.y) three = self.window.get_object_at(self.ball.x, self.ball.y + 2 * self.ball_radius) four = self.window.get_object_at(self.ball.x + 2 * self.ball_radius, self.ball.y + 2 * self.ball_radius) if one is not None: self.obj = self.window.get_object_at(self.ball.x, self.ball.y) return True elif two is not None: self.obj = self.window.get_object_at( self.ball.x + 2 * self.ball_radius, self.ball.y) return True elif three is not None: self.obj = self.window.get_object_at( self.ball.x, self.ball.y + 2 * self.ball_radius) return True elif four is not None: self.obj = self.window.get_object_at( self.ball.x + 2 * self.ball_radius, self.ball.y + 2 * self.ball_radius) return True def check_object_type(self): """ The objects above the half of the window height are bricks and the object below the half of the window height is paddle. :return: boolean value. Bricks return True and paddle returns False. """ if self.ball.y > self.window.height / 2: return True else: return False def moving_ball(self): """ The method for moving ball. :return: The moving result of the ball. """ self.ball.move(self.__dx, self.__dy) def moving_paddle(self, event): """ The method for moving paddle. :param event: The information of the mouse, including (x,y) of it. :return: The moving result of the paddle. """ if event.x - self.paddle_width / 2 >= 0 and event.x - self.paddle_width / 2 <= self.window_width - self.paddle_width: self.paddle.x = event.x - self.paddle_width / 2 def reset_ball(self): """ As the ball falls below the paddle and the game hasn't overed, the ball will be reset to the original position. :return: The ball at the original position. """ self.ball = GOval(self.ball_radius * 2, self.ball_radius * 2, x=(self.window_width - self.ball_radius * 2) / 2, y=(self.window_height - self.ball_radius * 2) / 2) self.ball.filled = True self.ball.fill_color = 'black' self.window.add(self.ball) self.ball_radius = self.ball_radius self.__dx = 0 self.__dy = 0 def set_dx(self, new_dx): """ Set the new __dx. :param new_dx: The new dx. :return: __dx. """ self.__dx = new_dx def set_dy(self, new_dy): """ Set the new __dy. :param new_dy: The new dy. :return: __dy. """ self.__dy = new_dy def get_dx(self): """ Get the information of __dx from class BreakoutGraphics. :return: The __dx for the ball. """ return self.__dx def get_dy(self): """ Get the information of __dy from class BreakoutGraphics. :return: The __dy for the ball. """ return self.__dy def set_dx_collision(self, new_dx): """ Set the new __dx for ball after colliding with bricks. :param new_dx: The new dx. :return: __dx. """ if random.random() > 0.5: self.__dx = new_dx else: self.__dx = -new_dx def game_over(self): """ The label for game over. :return: The label for game over. """ label = GLabel('Game Over!!!') # The condition below is for 10*10 bricks. # If coder change the number of rows or columns, the size would probably not fit. label.font = '-40' self.window.add(label, x=self.window_width / 2 - 100, y=self.window_height / 2 + 100) def game_win(self): """ The label for game win. :return: The label for game win. """ label = GLabel('You Win!!!') # The condition below is for 10*10 bricks. # If coder change the number of rows or columns, the size would probably not fit. label.font = '-40' self.window.add(label, x=self.window_width / 2 - 100, y=self.window_height / 2 + 100)
class NoBreakout(NoGraphics): def __init__(self, lives=LIVES, frame_rate=FRAME_RATE): super().__init__() self.__game_lives = lives self.__game_integral = 0 self.__frame_rate = 1000 / frame_rate self.__obj_game_integral = None self.__obj_game_lives = None self.__obj_game_brick = None # Identify code self.__menu_code = 9 # 介面碼 0:main 1:game 9:none self.__status_code = 0 # 狀態碼 0:wait 1:start 9:reade self.__obj_menu_code = None self.__obj_status_code = None # main menu self.__obj_main_txt_1 = None self.__obj_main_txt_2 = None self.__obj_main_txt_start = None self.__obj_main_button = None self.__obj_main_zone = None # game menu self.__obj_game_zone_line_u = None self.__obj_game_zone_line_d = None self.__obj_game_zone_line_l = None self.__obj_game_zone_line_r = None self.brick = None self.__game_zone_u = 0 self.__game_zone_d = 0 self.__game_zone_l = 0 self.__game_zone_r = 0 self.__game_zone_w = 0 self.__game_zone_h = 0 # game brick self.__game_brick_num = 0 # game ball self.__game_ball_size = BALL_SIZE self.__obj_game_ball = None self.__game_ball_vx = 0 self.__game_ball_vy = 0 self.__start_bool = False # game paddle self.__game_paddle_w = PADDLE_WIDTH self.__game_paddle_h = PADDLE_HEIGHT self.__game_paddle_offset = PADDLE_OFFSET self.__obj_game_paddle = None self.main_code_star() # self.main_button() # 首頁返回鈕 print(f'<<< end >>>') def main_code_star(self): # self.__obj_menu_code=GLabel(f'menu :{self.__menu_code}',x= self.__boundary_x + 1000, y=self.__boundary_y + 300) # self.__obj_menu_code.font = '-50' # self.window.add(self.__obj_menu_code) # # self.__obj_status_code=GLabel(f'status :{self.__status_code}',x= self.__boundary_x + 1000, y=self.__boundary_y + 400) # self.__obj_status_code.font = '-50' # self.window.add(self.__obj_status_code) self.__obj_game_lives = GLabel(f'lives = {self.__game_lives}', x=self.__boundary_x + 750, y=self.__boundary_y + 700) self.__obj_game_lives.font = '-25' self.window.add(self.__obj_game_lives) self.__obj_game_integral = GLabel(f'integral = {self.__game_integral}', x=self.__boundary_x + 0, y=self.__boundary_y + 700) self.__obj_game_integral.font = '-25' self.window.add(self.__obj_game_integral) # self.__obj_game_brick = GLabel(f'status :{self.__game_brick_num}', x=self.__boundary_x + 1000, y=self.__boundary_y + 200) # self.__obj_game_brick.font = '-50' # self.window.add(self.__obj_game_brick) def main_code_update(self): # self.__obj_menu_code.text = f'menu :{self.__menu_code}' # self.__obj_status_code.text = f'status :{self.__status_code}' self.__obj_game_lives.text = f'lives :{self.__game_lives}' self.__obj_game_integral.text = f'integral :{self.__game_integral}' # self.__obj_game_brick.text = f'brick :{self.__game_brick_num}' def mouse_start(self): onmousemoved(self.move_perform) onmouseclicked(self.click_perform) def main_menu(self, dx=0, dy=0): self.__menu_code = 0 # 建立邊界區 self.boundary_zone() # 大標體 self.__obj_main_txt_1 = GLabel('Breakout clone', x=200 + self.__boundary_x + dx, y=200 + self.__boundary_y + dy) self.__obj_main_txt_1.font = f'Times New Roman-100' self.window.add(self.__obj_main_txt_1) # 中標題 self.__obj_main_txt_2 = GLabel('Maker : Tsai NoNo', x=200 + self.__boundary_x + dx, y=300 + self.__boundary_y + dy) self.__obj_main_txt_2.font = f'Times New Roman-50' self.__obj_main_txt_2.color = "gray" self.window.add(self.__obj_main_txt_2) # 開始 self.__obj_main_txt_start = GLabel('Start', x=200 + self.__boundary_x + dx, y=400 + self.__boundary_y + dy) self.__obj_main_txt_start.font = f'Times New Roman-50' self.__obj_main_txt_start.color = "dimgray" self.window.add(self.__obj_main_txt_start) self.main_code_update() def game_menu(self): self.__menu_code = 1 self.boundary_zone() self.main_code_update() def menu_exit(self): """ 清除所有的物件 1.地毯式:優點:程式短,無差別清除,缺點:較久,無法針對特定 2.標記式:優點:快速,針對特定清除,缺點:每一筆都需記憶變數 """ for i in range(0, self.window.width - 300, 20): for j in range(0, self.window.height, 25): get_obj = self.window.get_object_at(i, j) self.window.remove(get_obj) # self.window.remove(self.__obj_main_txt_1) self.window.remove(self.__obj_main_txt_2) self.window.remove(self.__obj_main_txt_start) self.window.remove(self.__obj_main_zone) # self.window.remove(self.__obj_game_zone_line_u) self.window.remove(self.__obj_game_zone_line_d) self.window.remove(self.__obj_game_zone_line_l) self.window.remove(self.__obj_game_zone_line_r) # self.window.remove(self.__obj_game_ball) self.window.remove(self.__obj_game_paddle) def main_button(self, dx=0, dy=0): self.__obj_main_button = GOval(50, 50, x=1100 + self.__boundary_x + dx, y=600 + self.__boundary_y + dy) self.__obj_main_button.color = 'red' self.__obj_main_button.filled = True self.__obj_main_button.fill_color = 'red' self.window.add(self.__obj_main_button) def boundary_zone(self, dx=0, dy=0): if self.__menu_code == 0: # Main Zone main_zone_w = self.window.width - 2 * self.__boundary_x main_zone_h = self.window.height - 2 * self.__boundary_y self.__obj_main_zone = GRect(main_zone_w, main_zone_h, x=self.__boundary_x + dx, y=self.__boundary_y + dy) self.window.add(self.__obj_main_zone) elif self.__menu_code == 1: # Game Zone self.__game_zone_w = self.window.width - 2 * self.__boundary_x - 300 self.__game_zone_h = self.window.height - 2 * self.__boundary_y self.__game_zone_u = self.__boundary_y self.__game_zone_d = self.__boundary_y + self.__game_zone_h self.__game_zone_l = self.__boundary_x self.__game_zone_r = self.__boundary_x + self.__game_zone_w print(f'{self.__game_zone_w} , {self.__game_zone_h}') self.__obj_game_zone_line_u = GLine(self.__game_zone_l, self.__game_zone_u, self.__game_zone_r, self.__game_zone_u) self.__obj_game_zone_line_d = GLine(self.__game_zone_l, self.__game_zone_d, self.__game_zone_r, self.__game_zone_d) self.__obj_game_zone_line_l = GLine(self.__game_zone_l, self.__game_zone_u, self.__game_zone_l, self.__game_zone_d) self.__obj_game_zone_line_r = GLine(self.__game_zone_r, self.__game_zone_u, self.__game_zone_r, self.__game_zone_d) self.window.add(self.__obj_game_zone_line_u) self.window.add(self.__obj_game_zone_line_d) self.window.add(self.__obj_game_zone_line_l) self.window.add(self.__obj_game_zone_line_r) def click_perform(self, mouse): get_obj = self.window.get_object_at(mouse.x, mouse.y) # 進入遊戲畫面 if get_obj == self.__obj_main_txt_start and self.__menu_code != 1 and self.__status_code == 0: self.__menu_code = 1 # feedback print("<<< up to game >>>") self.menu_exit() self.game_menu() self.game_brick_build(self.game_level_formation(level=1)) self.game_ball_build() self.game_paddle_build() self.set_game_ball_rest() self.game_star() # 進入主畫面 # elif get_obj == self.__obj_main_button and self.__menu_code != 0: # self.__menu_code = 0 # feedback # # self.__status_code == 0 # print(f'get_obj:self.__obj_main_button menu_code:{self.__menu_code} status_code:{self.__status_code}') # print("<<< up to main >>>") # self.menu_exit() # self.main_menu() elif get_obj == self.__obj_game_ball and self.__menu_code == 1 and self.__status_code == 0: print( f'get_obj:self.__obj_game_ball menu_code:{self.__menu_code} status_code:{self.__status_code}' ) print(f'ok star') self.__start_bool = True self.main_code_update() elif get_obj is not None: print(f'obj') print( f'get_obj:??? menu_code:{self.__menu_code} status_code:{self.__status_code}' ) else: print(f'None') # print(str(get_obj)) def move_perform(self, mouse): get_obj = self.window.get_object_at(mouse.x, mouse.y) if self.__menu_code == 0: if get_obj == self.__obj_main_txt_start: self.__obj_main_txt_start.color = "red" else: self.__obj_main_txt_start.color = "dimgray" # 針對遊戲畫面,做各狀態判斷 elif self.__menu_code == 1: self.__game_paddle_move(mouse) if self.__status_code == 0: if get_obj == self.__obj_game_ball: self.__obj_game_ball.fill_color = "red" else: self.__obj_game_ball.fill_color = "black" # if get_obj == self.__obj_main_button: # self.__obj_main_button.color = "dimgray" # self.__obj_main_button.fill_color = "dimgray" # else: # self.__obj_main_button.color = "red" # self.__obj_main_button.fill_color = "red" @staticmethod def game_level_formation(self, level=1): """ 0 一單位空 1 一單位磚 2 二單位磚 3 三單位磚 _ NONE :param level: :return: """ if level == 1: formation = "1111111111|" \ "1111111111|" \ "1111111111|" \ "1111111111|" \ "1111111111|" \ "1111111111|" \ "1111111111|" \ "1111111111|" \ "1111111111|" \ "1111111111|" \ "1111111111|" return formation def game_brick_build(self, formation, b_w=85, b_h=20, b_offset_x=5, b_offset_y=30, b_spacing=5, row_max=10, cow_max=10): j = 0 num_cow = 0 dy = self.__boundary_y + b_offset_y while formation.find('|') != -1: if num_cow == cow_max: break # 抓第一段字串 site = formation[:formation.find('|')] # 存放剩下字串 formation = formation[formation.find('|') + 1:] # 將字串轉換成磚塊 dx = self.__boundary_x + b_offset_x / 2 num_row = 0 for i in site: if i != '0' and i != '_': num_row += int(i) if num_row <= row_max: self.brick = GRect(b_w * int(i) + b_spacing * (int(i) - 1), b_h, x=dx, y=dy) dx += (b_w + b_spacing) * int(i) self.__game_brick_num += 1 elif i == '0': num_row += 1 dx += b_w + b_spacing self.brick.filled = True self.window.add(self.brick) self.game_brick_color(j) print(f'{site} {j} {num_row} {self.__game_brick_num}') dy += b_h + b_spacing j += 1 num_cow += 1 def game_brick_color(self, j, mode=1): if mode == 1: if j == 0 or j == 1: self.brick.fill_color = 'darkgreen' elif j == 2 or j == 3: self.brick.fill_color = 'forestgreen' elif j == 4 or j == 5: self.brick.fill_color = 'green' elif j == 6 or j == 7: self.brick.fill_color = 'limegreen' elif j == 8 or j == 9: self.brick.fill_color = 'lime' else: self.brick.fill_color = 'lawngreen' # 亂數給特殊磚-高分 if random.randint(1, 10) == 1: self.brick.fill_color = 'red' def game_paddle_build(self): paddle_width = 75 paddle_height = 15 paddle_offset = 50 # Create a paddle. print(f'paddle {self.__game_zone_w} {self.__obj_game_ball.width}') self.__obj_game_paddle = GRect( self.__game_paddle_w, self.__game_paddle_h, x=(self.__game_zone_w - self.__game_paddle_w) / 2 + self.__boundary_x, y=self.__game_zone_h - self.__game_paddle_offset + self.__boundary_y) print( f'paddle x={self.__obj_game_paddle.x}, y= {self.__obj_game_paddle.y}' ) self.__obj_game_paddle.filled = True self.window.add(self.__obj_game_paddle) def __game_paddle_move(self, mouse): if (mouse.x <= self.__game_zone_r - self.__game_paddle_w / 2) and ( mouse.x >= self.__game_zone_l + self.__game_paddle_w / 2): self.__obj_game_paddle.x = mouse.x - (self.__game_paddle_w / 2) # print(mouse.x) elif mouse.x < self.__game_zone_l: self.__obj_game_paddle.x = self.__game_zone_l # print(mouse.x) elif mouse.x > self.__game_zone_r: self.__obj_game_paddle.x = self.__game_zone_r - self.__game_paddle_w # print(mouse.x) def game_star(self): num_lives = self.__game_lives print(f'game_star : OK') while True: if self.__menu_code == 0: break if self.get_ball_outside(): self.__game_lives -= 1 self.main_code_update() if self.__game_lives > 0: print('1') self.__status_code = 0 self.set_game_ball_rest() self.ball_speed_update() else: print('1 end') break if self.__game_brick_num == 0: print('2 end') break self.game_ball_move() self.ball_rebound_window() self.ball_rebound_obj() pause(self.__frame_rate) print('Game over') def game_ball_build(self): # Center a filled ball in the graphical window. self.__obj_game_ball = GOval( self.__game_ball_size, self.__game_ball_size, x=(self.__game_zone_w - self.__game_ball_size) / 2 + self.__boundary_x, y=(self.__game_zone_h - self.__game_ball_size) / 2 + self.__boundary_y) print(f'ball x={self.__obj_game_ball.x}, y={self.__obj_game_ball.y}') self.__obj_game_ball.filled = True self.window.add(self.__obj_game_ball) # self.__start_bool = True def __set_ball_velocity(self): self.__game_ball_vx = random.randint(1, BALL_X_SPEED_MAX) if random.random() > 0.5: self.__game_ball_vx = -self.__game_ball_vx self.__game_ball_vy = BALL_Y_SPEED print( f'set_ball_velocity {self.__game_ball_vx}, {self.__game_ball_vy}') def __set_ball_site(self): self.__obj_game_ball.x = ( self.__game_zone_w - self.__game_ball_size) / 2 + self.__boundary_x self.__obj_game_ball.y = ( self.__game_zone_h - self.__game_ball_size) / 2 + self.__boundary_y def game_ball_move(self): print(f'ball_move {self.__game_ball_vx}, {self.__game_ball_vy}') self.__obj_game_ball.move(self.__game_ball_vx, self.__game_ball_vy) def get_ball_outside(self): if self.__obj_game_ball.y > self.window.height - self.__boundary_y - self.__game_ball_size: return True def get_brick_number(self): return self.__game_brick_num def set_game_ball_rest(self): print(f'ball_rest : start') self.__set_ball_site() self.__set_ball_velocity() while True: if self.__start_bool: print(f'ball_rest {self.__start_bool}') self.__start_bool = False break pause(200) print(f'ball_rest : end') self.__status_code = 1 def ball_rebound_window(self): if self.__obj_game_ball.x <= self.__game_zone_l or \ (self.__obj_game_ball.x + self.__obj_game_ball.width) >= self.__game_zone_r: print('撞到兩側') self.__game_ball_vx = -self.__game_ball_vx if self.__obj_game_ball.y <= self.__game_zone_u: print('撞到上面') self.__game_ball_vy = -self.__game_ball_vy #下邊界要拿掉的 if self.__obj_game_ball.y >= self.__game_zone_d - self.__obj_game_ball.height: print('撞到下面') # self.__game_ball_vy = -self.__game_ball_vy def ball_rebound_obj(self): non_remove_obj = [] non_remove_obj.append(self.__obj_game_paddle) non_remove_obj.append(self.__obj_game_zone_line_u) non_remove_obj.append(self.__obj_game_zone_line_d) non_remove_obj.append(self.__obj_game_zone_line_l) non_remove_obj.append(self.__obj_game_zone_line_r) non_rebound_obj = [] non_rebound_obj.append(self.__obj_game_lives) non_rebound_obj.append(self.__obj_game_integral) ball_touch_obj = [] ball_touch_obj.append( self.window.get_object_at( self.__obj_game_ball.x + self.__obj_game_ball.width / 2, self.__obj_game_ball.y - 0.1)) ball_touch_obj.append( self.window.get_object_at( self.__obj_game_ball.x + self.__obj_game_ball.width / 2, self.__obj_game_ball.y + self.__obj_game_ball.height + 0.1)) ball_touch_obj.append( self.window.get_object_at( self.__obj_game_ball.x - 0.1, self.__obj_game_ball.y + self.__obj_game_ball.height / 2)) ball_touch_obj.append( self.window.get_object_at( self.__obj_game_ball.x + self.__obj_game_ball.width + 0.1, self.__obj_game_ball.y + self.__obj_game_ball.height / 2)) j = 0 for i in ball_touch_obj: if i is not None: if i not in non_rebound_obj: if i not in non_remove_obj: if i.fill_color == 'red': self.__game_integral += 50 else: self.__game_integral += 10 self.window.remove(i) self.__game_brick_num -= 1 self.main_code_update() if j == 0: if i == self.__obj_game_paddle: self.__obj_game_ball.y = self.__obj_game_paddle.y + self.__game_paddle_h self.__game_ball_vy = -self.__game_ball_vy elif j == 1: if i == self.__obj_game_paddle: self.__obj_game_ball.y = self.__obj_game_paddle.y - self.__obj_game_ball.height self.__game_ball_vy = -self.__game_ball_vy elif j == 2: if i == self.__obj_game_paddle: self.__obj_game_ball.x = self.__obj_game_paddle.x + self.__game_paddle_w self.__game_ball_vx = -self.__game_ball_vx # print(f'obj_r') elif j == 3: if i == self.__obj_game_paddle: self.__obj_game_ball.x = self.__obj_game_paddle.x - self.__obj_game_ball.width self.__game_ball_vx = -self.__game_ball_vx j += 1 def ball_speed_update(self, threshold=100): speed = 10 if self.__game_integral % threshold == 0 and self.__game_integral != 0: self.__frame_rate = 1000 / (FRAME_RATE + speed)