Table of Contents
Overview
Impact checking
Show and hide game menu
in conclusion
Home Backend Development Python Tutorial Creating interactive games with Python 3 and Pygame: Part 4

Creating interactive games with Python 3 and Pygame: Part 4

Aug 27, 2023 pm 03:01 PM

使用 Python 3 和 Pygame 创建互动游戏:第 4 部分

Overview

This is the fourth in a five-part tutorial series on making games with Python 3 and Pygame. In Part Three, we delved into the core of Breakout, learned how to handle events, looked at the main Breakout classes, and saw how to move different game objects.

In this part, we'll learn how to detect collisions and what happens when the ball hits various objects such as paddles, bricks, walls, ceilings, and floors. Finally, we'll review important topics of game UI, specifically how to create menus with our own custom buttons.

Impact checking

In the game, things collide with each other. Breakthrough is no exception. Most of the time it's the ball hitting something. The handle_ball_collisions() method has a nested function called intersect() that tests whether the ball hits an object and where it hits the object. If the ball misses an object, returns "Left", "Right", "Up", "Down", or "None".

def handle_ball_collisions(self):
    def intersect(obj, ball):
        edges = dict(
            left=Rect(obj.left, obj.top, 1, obj.height),
            right=Rect(obj.right, obj.top, 1, obj.height),
            top=Rect(obj.left, obj.top, obj.width, 1),
            bottom=Rect(obj.left, obj.bottom, obj.width, 1))
        collisions = set(edge for edge, rect in edges.items() if
                         ball.bounds.colliderect(rect))
        if not collisions:
            return None

        if len(collisions) == 1:
            return list(collisions)[0]

        if 'top' in collisions:
            if ball.centery >= obj.top:
                return 'top'
            if ball.centerx < obj.left:
                return 'left'
            else:
                return 'right'

        if 'bottom' in collisions:
            if ball.centery >= obj.bottom:
                return 'bottom'
            if ball.centerx < obj.left:
                return 'left'
            else:
                return 'right'
Copy after login

hit the ball with a racket

When the ball hits the racket, it bounces away. If it hits the top of the paddle, it will bounce back but maintain the same horizontal velocity component.

However, if it hits one side of the paddle, it will bounce to the other side (left or right) and continue its downward motion until it hits the floor. This code uses the intersect function().

# Hit paddle
s = self.ball.speed
edge = intersect(self.paddle, self.ball)
if edge is not None:
    self.sound_effects['paddle_hit'].play()
if edge == 'top':
	speed_x = s[0]
	speed_y = -s[1]
	if self.paddle.moving_left:
		speed_x -= 1
	elif self.paddle.moving_left:
		speed_x += 1
	self.ball.speed = speed_x, speed_y
elif edge in ('left', 'right'):
	self.ball.speed = (-s[0], s[1])
Copy after login

Landing

When the racket misses the ball on its way down (or the ball hits the side of the racket), the ball will continue to fall and eventually hit the floor. At this point, the player loses a life and the ball is recreated so the game can continue. The game ends when the player runs out of lives.

# Hit floor
if self.ball.top > c.screen_height:
    self.lives -= 1
	if self.lives == 0:
		self.game_over = True
	else:
		self.create_ball()
Copy after login

Hit the ceiling and walls

When the ball hits a wall or ceiling, it just bounces back.

# Hit ceiling
if self.ball.top < 0:
    self.ball.speed = (s[0], -s[1])

# Hit wall
if self.ball.left < 0 or self.ball.right > c.screen_width:
	self.ball.speed = (-s[0], s[1])
Copy after login

Brick Break

When the ball hits a brick, this is a major event in Breakout - the brick disappears, the player gets a point, the ball bounces back, and a few other things happen (sound effects, and possibly special effects ), which I will discuss later.

To determine if a brick was hit, the code checks to see if any bricks intersect the ball:

# Hit brick
for brick in self.bricks:
    edge = intersect(brick, self.ball)
	if not edge:
		continue

	self.bricks.remove(brick)
	self.objects.remove(brick)
	self.score += self.points_per_brick

	if edge in ('top', 'bottom'):
		self.ball.speed = (s[0], -s[1])
	else:
		self.ball.speed = (-s[0], s[1])
Copy after login

Programming the Game Menu

Most games have some kind of user interface. Breakout has a simple menu with two buttons, "PLAY" and "QUIT." This menu appears when the game starts and disappears when the player clicks "Start". Let's see how buttons and menus are implemented and how they integrate with the game.

Create button

Pygame does not have a built-in UI library. There are third party extensions, but I decided to build my own button for the menu. Buttons are game objects with three states: normal, hover, and pressed. The normal state is when the mouse is not over the button, and the hover state is when the mouse is over the button but the left mouse button is not pressed. The pressed state is when the mouse is over the button and the player presses the left mouse button.

The button is implemented as a rectangle with a background color and text displayed on it. The button also receives an on_click function (defaults to a noop lambda function), which is called when the button is clicked.

import pygame

from game_object import GameObject
from text_object import TextObject
import config as c


class Button(GameObject):
    def __init__(self, 
                 x, 
                 y, 
                 w, 
                 h, 
                 text, 
                 on_click=lambda x: None, 
                 padding=0):
        super().__init__(x, y, w, h)
        self.state = 'normal'
        self.on_click = on_click

        self.text = TextObject(x + padding, 
                               y + padding, lambda: text, 
                               c.button_text_color, 
                               c.font_name, 
                               c.font_size)

    def draw(self, surface):
        pygame.draw.rect(surface, 
                         self.back_color, 
                         self.bounds)
        self.text.draw(surface)
Copy after login

Buttons handle their own mouse events and change their internal state based on those events. When the button is pressed, the MOUSEBUTTONUP event is received, indicating that the player clicked the button, and the on_click() function is called.

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'
Copy after login

The back_color property used to draw the background rectangle always returns a color that matches the button's current state, so the player can clearly see that the button is active:

@property
def back_color(self):
    return dict(normal=c.button_normal_back_color,
                hover=c.button_hover_back_color,
                pressed=c.button_pressed_back_color)[self.state]
Copy after login

Create Menu

create_menu() Function creates a menu with two buttons containing the text "PLAY" and "QUIT". It has two nested functions named on_play() and on_quit() which are fed to the corresponding buttons. Each button is added to the objects list (to be drawn) and the menu_buttons field.

def create_menu(self):
    for i, (text, handler) in enumerate((('PLAY', on_play), 
                                         ('QUIT', on_quit))):
        b = Button(c.menu_offset_x,
                   c.menu_offset_y + (c.menu_button_h + 5) * i,
                   c.menu_button_w,
                   c.menu_button_h,
                   text,
                   handler,
                   padding=5)
        self.objects.append(b)
        self.menu_buttons.append(b)
        self.mouse_handlers.append(b.handle_mouse_event)
Copy after login

When the PLAY button is clicked, on_play() is called, which removes the button from the objects list so that they are no longer drawn. Additionally, the boolean fields is_game_running and start_level that trigger the start of the game are set to True.

When the exit button is clicked, is_game_running is set to False (effectively pausing the game) and game_over is set to True, triggering the final game sequence.

def on_play(button):
    for b in self.menu_buttons:
		self.objects.remove(b)

	self.is_game_running = True
	self.start_level = True

def on_quit(button):
	self.game_over = True
	self.is_game_running = False
Copy after login

Show and hide game menu

Showing and hiding menus is implicit. When the buttons are in the objects list, the menu is visible; when they are removed, it is hidden. It's that easy.

It's possible to create a nested menu with its own surface that renders subcomponents like buttons and then just add/remove that menu component, but this simple menu doesn't need it.

in conclusion

In this part, we cover collision detection and what happens when the ball hits various objects such as paddles, bricks, walls, ceilings, and floors. Additionally, we created our own menu with custom buttons that hide and show based on commands.

In this final part of the series, we'll look at the final game, paying close attention to scores and lives, sound effects, and music.

We will then develop a complex special effects system to add interest to the game. Finally, we discuss future directions and potential improvements.

The above is the detailed content of Creating interactive games with Python 3 and Pygame: Part 4. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

How to solve the permissions problem encountered when viewing Python version in Linux terminal? How to solve the permissions problem encountered when viewing Python version in Linux terminal? Apr 01, 2025 pm 05:09 PM

Solution to permission issues when viewing Python version in Linux terminal When you try to view Python version in Linux terminal, enter python...

How to efficiently copy the entire column of one DataFrame into another DataFrame with different structures in Python? How to efficiently copy the entire column of one DataFrame into another DataFrame with different structures in Python? Apr 01, 2025 pm 11:15 PM

When using Python's pandas library, how to copy whole columns between two DataFrames with different structures is a common problem. Suppose we have two Dats...

How to teach computer novice programming basics in project and problem-driven methods within 10 hours? How to teach computer novice programming basics in project and problem-driven methods within 10 hours? Apr 02, 2025 am 07:18 AM

How to teach computer novice programming basics within 10 hours? If you only have 10 hours to teach computer novice some programming knowledge, what would you choose to teach...

How to avoid being detected by the browser when using Fiddler Everywhere for man-in-the-middle reading? How to avoid being detected by the browser when using Fiddler Everywhere for man-in-the-middle reading? Apr 02, 2025 am 07:15 AM

How to avoid being detected when using FiddlerEverywhere for man-in-the-middle readings When you use FiddlerEverywhere...

What are regular expressions? What are regular expressions? Mar 20, 2025 pm 06:25 PM

Regular expressions are powerful tools for pattern matching and text manipulation in programming, enhancing efficiency in text processing across various applications.

How does Uvicorn continuously listen for HTTP requests without serving_forever()? How does Uvicorn continuously listen for HTTP requests without serving_forever()? Apr 01, 2025 pm 10:51 PM

How does Uvicorn continuously listen for HTTP requests? Uvicorn is a lightweight web server based on ASGI. One of its core functions is to listen for HTTP requests and proceed...

What are some popular Python libraries and their uses? What are some popular Python libraries and their uses? Mar 21, 2025 pm 06:46 PM

The article discusses popular Python libraries like NumPy, Pandas, Matplotlib, Scikit-learn, TensorFlow, Django, Flask, and Requests, detailing their uses in scientific computing, data analysis, visualization, machine learning, web development, and H

How to dynamically create an object through a string and call its methods in Python? How to dynamically create an object through a string and call its methods in Python? Apr 01, 2025 pm 11:18 PM

In Python, how to dynamically create an object through a string and call its methods? This is a common programming requirement, especially if it needs to be configured or run...

See all articles