Créer des jeux interactifs avec Python 3 et Pygame : Partie 4

WBOY
Libérer: 2023-08-27 15:01:14
original
1277 Les gens l'ont consulté

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

Vue d'ensemble

Il s'agit du quatrième d'une série de didacticiels en cinq parties sur la création de jeux avec Python 3 et Pygame. Dans la troisième partie, nous avons plongé dans le cœur de Breakout, appris à gérer les événements, examiné les principales classes de Breakout et vu comment déplacer différents objets du jeu.

Dans cette partie, nous apprendrons comment détecter les collisions et ce qui se passe lorsque la balle touche divers objets tels que des raquettes, des briques, des murs, des plafonds et des sols. Enfin, nous passerons en revue des sujets importants concernant l'interface utilisateur du jeu, en particulier comment créer des menus avec nos propres boutons personnalisés.

Détection de collision

Dans le jeu, les choses entrent en collision. La percée ne fait pas exception. La plupart du temps, c'est la balle qui frappe quelque chose. handle_ball_collisions() 方法有一个嵌套函数,名为 intersect(), utilisé pour tester si la balle touche un objet et où elle touche l'objet. Si la balle manque un objet, renvoie "Gauche", "Droite", "Haut", "Bas" ou "Aucun".

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'
Copier après la connexion

Frappez la balle avec la raquette

Lorsque la balle touche la raquette, elle rebondit. S'il touche le haut de la pagaie, il rebondira mais conservera la même composante de vitesse horizontale.

Cependant, si elle heurte un côté de la pagaie, elle rebondira de l'autre côté (gauche ou droite) et poursuivra son mouvement vers le bas jusqu'à ce qu'elle touche le sol. Ce code utilise la fonction d'intersection ().

# 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])
Copier après la connexion

Atterrissage

Lorsque la raquette manque la balle en descendant (ou que la balle touche le côté de la raquette), la balle continuera de tomber et finira par toucher le sol. À ce stade, le joueur perd une vie et la balle est recréée pour que le jeu puisse continuer. Le jeu se termine lorsque le joueur n'a plus de vie.

# Hit floor
if self.ball.top > c.screen_height:
    self.lives -= 1
	if self.lives == 0:
		self.game_over = True
	else:
		self.create_ball()
Copier après la connexion

Cosses aux plafonds et aux murs

Lorsque la balle touche un mur ou un plafond, elle rebondit simplement.

# 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])
Copier après la connexion

Brique Break

Quand la balle touche une brique, c'est un événement majeur dans Breakout - la brique disparaît, le joueur marque un point, la balle rebondit et quelques autres choses se produisent (effets sonores et éventuellement effets spéciaux), j'en discuterai ça plus tard.

Pour déterminer si une brique a été touchée, le code vérifie si des briques croisent la balle :

# 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])
Copier après la connexion

Programmer le menu du jeu

La plupart des jeux ont une sorte d'interface utilisateur. Breakout a un menu simple avec deux boutons, "PLAY" et "QUITTER". Ce menu apparaît au démarrage du jeu et disparaît lorsque le joueur clique sur "Démarrer". Voyons comment les boutons et les menus sont implémentés et comment ils s'intègrent au jeu.

Créer un bouton

Pygame n'a pas de bibliothèque d'interface utilisateur intégrée. Il existe des extensions tierces, mais j'ai décidé de créer mon propre bouton pour le menu. Les boutons sont des objets de jeu avec trois états : normal, survolé et enfoncé. L'état normal est lorsque la souris n'est pas sur le bouton, et l'état de survol est lorsque la souris est sur le bouton mais que le bouton gauche de la souris n'est pas enfoncé. L'état enfoncé est lorsque la souris est sur le bouton et que le joueur appuie sur le bouton gauche de la souris.

Le bouton est implémenté sous la forme d'un rectangle avec une couleur d'arrière-plan et du texte affiché dessus. Le bouton reçoit également une fonction on_click (par défaut une fonction noop lambda), qui est appelée lorsque l'on clique sur le bouton.

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)
Copier après la connexion

Les boutons gèrent leurs propres événements de souris et modifient leur état interne en fonction de ces événements. Lorsque le bouton est enfoncé, la fonction MOUSEBUTTONUP 事件,表示玩家点击了按钮,并调用 on_click() est reçue.

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'
Copier après la connexion

La propriété back_color utilisée pour dessiner le rectangle d'arrière-plan renvoie toujours une couleur qui correspond à l'état actuel du bouton, afin que le joueur puisse clairement voir que le bouton est actif :

@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]
Copier après la connexion

Créer un menu

create_menu() 函数创建一个带有两个按钮的菜单,其中包含文本“PLAY”和“QUIT”。它有两个嵌套函数,名为 on_play()on_quit() ,它提供给相应的按钮。每个按钮都添加到 objects 列表(待绘制)以及 menu_buttonschamps.

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)
Copier après la connexion

Lorsque vous cliquez sur le bouton PLAY, on_play() est appelé, qui est défini de objects 列表中删除按钮,这样就不再绘制它们了。此外,触发游戏开始的布尔字段 is_game_runningstart_level à True.

Défini sur True lorsque vous cliquez sur le bouton de sortie, déclenchant la séquence de jeu finale. is_game_running 设置为 False (有效暂停游戏)并且 game_over

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
Copier après la connexion
Afficher et masquer le menu du jeu

Afficher et masquer les menus est implicite. Lorsque les boutons sont dans la liste

, le menu est visible ; lorsqu'ils sont supprimés, il est masqué. C'est aussi simple que cela. objects

Il est possible de créer un menu imbriqué avec sa propre surface qui restitue des sous-composants comme des boutons, puis d'ajouter/supprimer simplement ce composant de menu, mais ce menu simple n'en a pas besoin.

Conclusion

Dans cette section, nous abordons la détection de collision et ce qui se passe lorsque la balle touche divers objets tels que des raquettes, des briques, des murs, des plafonds et des sols. De plus, nous avons créé notre propre menu avec des boutons personnalisés qui se cachent et s'affichent en fonction des commandes.

Dans cette dernière partie de la série, nous examinerons le jeu final, en accordant une attention particulière aux scores et aux vies, aux effets sonores et à la musique.

Ensuite, nous développerons un système d'effets spéciaux complexe pour ajouter de l'intérêt au jeu. Enfin, nous discutons des orientations futures et des améliorations potentielles.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal