📜 ⬆️ ⬇️

Making games in Python 3 and Pygame: Part 3

image
(The remaining parts of the tutorial: first , second , fourth , fifth .)

This is the third of the five parts of the game creation tutorial using Python 3 and Pygame. In the second part, we looked at the TextObject class, which is used to render text to the screen, created the main window, and learned how to draw objects: bricks, a ball, and a racket.

In this part, we dive deeper into the heart of Breakout and learn how to handle events, get to know the main Breakout class, and see how to move various objects in the game.
')

Event handling


Breakout has three types of events: keystroke events, mouse events, and timer events. The main loop in the Game class handles keystrokes and mouse events and passes them to subscribers (by calling a handler function).

Although the Game class is very general and does not have knowledge of the Breakout implementation, the subscription itself and event handling methods are very specific.

Breakout class


The Breakout class implements the majority of knowledge about how the game is controlled Breakout. In this series of tutorials, we will meet the Breakout class several times. Here are the lines that register various event handlers.

It should be noted that all key events (for both the left and right arrows) are transmitted to the same racket handler method.

 #   handle_mouse_event()   self.mouse_handlers.append(b.handle_mouse_event) #   handle()      self.keydown_handlers[pygame.K_LEFT].append(paddle.handle) self.keydown_handlers[pygame.K_RIGHT].append(paddle.handle) self.keyup_handlers[pygame.K_LEFT].append(paddle.handle) self.keyup_handlers[pygame.K_RIGHT].append(paddle.handle) 

Keystroke processing


The Game class calls registered handlers for each key event and passes the key. Note that this is not a Paddle class. In Breakout, the only object that is interested in such events is the racket. When a key is pressed or released, its handle() method is called. The Paddle object does not need to know whether it was a key press or key release event, because it controls the current state with a pair of boolean variables: moving_left and moving_right . If moving_left is True, then the left key was pressed, and the next event will be the release of the key, which will reset the variable. The same applies to the "right" key. The logic is simple and consists in switching the state of these variables in response to any event.

  def handle(self, key): if key == pygame.K_LEFT: self.moving_left = not self.moving_left else: self.moving_right = not self.moving_right 

Handling Mouse Events


Breakout has a game menu that we will meet soon. The menu button controls various mouse events, such as movement and button presses (mouse down and mouse up events). In response to these events, the button updates the internal state variable. Here is the mouse handling code:

  def handle_mouse_event(self, type, pos): if type == pygame.MOUSEMOTION: self.handle_mouse_move(pos) elif type == pygame.MOUSEBUTTONDOWN: self.handle_mouse_down(pos) elif type == pygame.MOUSEBUTTONUP: self.handle_mouse_up(pos) def handle_mouse_move(self, pos): if self.bounds.collidepoint(pos): if self.state != 'pressed': self.state = 'hover' else: self.state = 'normal' def handle_mouse_down(self, pos): if self.bounds.collidepoint(pos): self.state = 'pressed' def handle_mouse_up(self, pos): if self.state == 'pressed': self.on_click(self) self.state = 'hover' 

Notice that the handle_mouse_event() method, registered to receive mouse events, checks the type of the event and forwards it to the appropriate method that handles this type of event.

Timer event handling


Timer events are not processed in the main loop. However, since the main loop is called every frame, it is easy to check whether the time for a particular event has arrived. You will see this later when we discuss the temporary special effects.

Another situation is the need to pause the game. For example, when displaying a message that a player must read and so that nothing distracts him. The show_message() method of the Breakout class uses this approach and calls time.sleep() . Here is the corresponding code:

 import config as c class Breakout(Game): def show_message(self, text, color=colors.WHITE, font_name='Arial', font_size=20, centralized=False): message = TextObject(c.screen_width // 2, c.screen_height // 2, lambda: text, color, font_name, font_size) self.draw() message.draw(self.surface, centralized) pygame.display.update() time.sleep(c.message_duration) 

Game process


Gameplay (gameplay) is the place in which Breakout rules come into play. The gameplay consists of moving various objects in response to events and changing the state of the game based on their interactions.

Move the racket


You saw earlier that the Paddle class responds to keystrokes with arrows, updating its moving_left and moving_right . The movement itself takes place in the update() method. Certain calculations are performed here if the racket is close to the left or right edge of the screen. We do not want the racket to go beyond the screen (taking into account the specified offset).

Therefore, if the movement moves the object beyond the boundaries, then the code adjusts the movement so that it stops right at the border. Since the racket moves only horizontally, the vertical component of the movement is always zero.

 import pygame import config as c from game_object import GameObject class Paddle(GameObject): def __init__(self, x, y, w, h, color, offset): GameObject.__init__(self, x, y, w, h) self.color = color self.offset = offset self.moving_left = False self.moving_right = False ... def update(self): if self.moving_left: dx = -(min(self.offset, self.left)) elif self.moving_right: dx = min(self.offset, c.screen_width - self.right) else: return self.move(dx, 0) 

Move the ball


The ball simply uses the functionality of the base class GameObject , which moves objects based on their speed (its horizontal and vertical components). As we will see soon, the speed of the ball is determined by many factors in the Breakout class. Since the movement is simply to add speed to the current position, the direction in which the ball moves is completely determined by the speed along the horizontal and vertical axes.

Set the initial speed of the ball


The ball in Breakout arises from nowhere at the very beginning of the game every time a player loses a life. It simply materializes from the ether and begins to fall either straight down or at a slight angle. When the ball is created in the create_ball() method, it receives a speed with a random horizontal component in the interval from -2 to 2 and a vertical component specified in the config.py module (the default value is 3).

  def create_ball(self): speed = (random.randint(-2, 2), c.ball_speed) self.ball = Ball(c.screen_width // 2, c.screen_height // 2, c.ball_radius, c.ball_color, speed) self.objects.append(self.ball) 

Summarize


In this section, we looked at handling events like keystrokes, mouse movement, and mouse clicks. We also studied some elements of the Breakout gameplay: moving the racket, moving the ball and controlling the speed of the ball.

In the fourth part, we will look at the important topic of collision recognition and see what happens when the ball hits different game objects: racket, bricks, walls, ceiling and floor. Then we will pay attention to the game menu. We will create our own buttons that we use as a menu and will be able to show and hide if necessary.

Source: https://habr.com/ru/post/347256/


All Articles