Construire des jeux avec Python 3 et Pygame Partie 5

Vue d'ensemble

Il s’agit de la cinquième partie d’une série de tutoriels en cinq parties sur la création de jeux avec Python 3 et PyGame. Dans la quatrième partie, nous avons détecté des collisions, réagi à la frappe de divers objets du jeu et créé un menu de jeu avec des boutons personnalisés.. 

Dans cette dernière partie, nous aborderons divers sujets tels que le jeu final, la gestion des vies et des scores, les effets sonores, la musique et même un système flexible d’effets spéciaux. Pour le dessert, nous discuterons des améliorations potentielles et des orientations futures.

La fin du jeu

Finalement, le jeu doit se terminer. Dans cette version de Breakout, le jeu se termine de deux manières: soit le joueur perd la vie, soit il frappe toutes les briques. Il n'y a pas de prochain niveau (bien qu'il serait facile d'ajouter).

Jeu terminé!

Le champ game_over de la classe Game est défini sur False dans le champ. __init __ () méthode de la classe de jeu. La boucle principale tourne en rond jusqu'au jeu terminé variable est définie sur True:

class Game: def __init __ (self, légende, largeur, hauteur, back_image_filename, frame_rate):… self.game_over = False… def run (self): sans être self.game_over: self.surface.blit (self.background_image, (0 , 0)) self.handle_events () self.update () self.draw () pygame.display.update () self.clock.tick (self.frame_rate) 

Tout cela se passe dans la classe Breakout dans les cas suivants:

  • Le joueur a cliqué sur le bouton QUITTER du menu.
  • Le joueur perd sa dernière vie.
  • Le joueur a effacé toutes les briques.
def on_quit (button): self.game_over = True self.is_game_running = False def handle_ball_collisions (self):… # Hit floor si self.ball.top> c.screen_height: self.lives - = 1 si self.lives == 0 : self.game_over = True sinon self.bricks: self.show_message ('VOUS GAGNEZ !!!', centralisé = True) self.is_game_running = False self.game_over = True return def update (self):… sinon self. briques: self.show_message ('VOUS GAGNEZ !!!', centralisé = vrai) self.is_game_running = False self.game_over = Vrai retour 

Afficher le message de fin de partie

Habituellement, lorsque le jeu se termine, nous ne voulons pas que la fenêtre du jeu disparaisse comme si de rien n'était. L'exception est si vous avez cliqué sur le bouton QUITTER dans le menu. Lorsque le joueur perd sa dernière vie, Breakout affiche le traditionnel "GAME OVER!" message, et lorsque le joueur gagne, il affiche "VOUS GAGNEZ!"

le voir le message() fonction est utilisée dans les deux cas. Il affiche le texte en haut de l'écran actuel (le jeu sera mis en pause) et attend quelques secondes avant de revenir. À la prochaine itération de la boucle de jeu, le contrôle de la jeu terminé champ déterminera qu'il est vrai et le programme se terminera. 

Voici la voir le message() une fonction:

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, couleur, nom de police, taille de police) self.draw () message.draw (self.surface, centralisé) pygame.display.update () time.sleep (c.message_duration)

Garder le meilleur score entre les matchs

Dans cette version, je ne conserve pas le meilleur score, car il n'y a qu'un seul niveau, et le score de chacun sera le même s'il efface toutes les briques. En général, cela peut être fait localement en enregistrant le meilleur score dans un fichier, puis en affichant un autre message si le joueur a cassé le meilleur score..

Ajouter des effets sonores et de la musique

Les jeux sont une expérience audiovisuelle. La plupart des jeux ont des effets sonores qui sont de courts octets sonores qui sont joués lorsque le joueur tue un monstre, trouve un trésor ou explose horriblement. Certains jeux ont aussi une musique de fond, ce qui contribue à l'atmosphère. Breakout n'a que des effets sonores, mais je vais vous montrer comment jouer de la musique de fond dans vos jeux..

Effets sonores

Vous avez besoin de fichiers sonores (similaires aux fichiers image) pour jouer en tant qu’effets sonores. Ces fichiers peuvent être au format .wav, .mp3 ou .ogg. Breakout conserve ses effets sonores dans le effets sonores dossier:

~ / git / pygame-breakout> arbre sound_effects / sound_effects / ├── brick_hit.wav ├── effect_done.wav level_complete.wav paddle_hit.wav 

Voyons comment ces effets sonores sont chargés et joués au bon moment. Tout d'abord, pour jouer des effets sonores (ou une musique de fond), vous devez initialiser le système audio de Pygame. Cela se passe dans la classe de jeu: pygame.mixer.pre_init (44100, 16, 2, 4096)

Ensuite, dans la classe Breakout, tous les effets sonores sont chargés de la config dans la pygame.mixer.Sound objet et sont stockés dans un dictionnaire:

# Dans config.py sounds_effects = dict (brick_hit = "sound_effects / brick_hit.wav", effect_done = "sound_effects / effect_done.wav", paddle_hit = "sound_effects / paddle_hit.wav", level_complete = "sound_effets / level_complete.w) # Dans la classe breakout.py Breakout (jeu): def __init __ (self):… self.sound_effects = name: pygame.mixer.Sound (son) pour le nom, son dans c.sounds_effects.items ()… 

Maintenant, nous pouvons jouer les effets sonores quand quelque chose d'intéressant se produit. Par exemple, lorsque la balle frappe une brique:

# Frapper brique pour brique dans self.bricks: edge = intersecter (brique, self.ball) sinon bord: continuer self.sound_effects ['brick_hit']. Play () 

L'effet sonore est joué de manière asynchrone, ce qui signifie que le jeu ne se fige pas pendant la lecture du son. Plusieurs effets sonores peuvent être joués simultanément.

Enregistrez vos propres effets sonores et messages

Enregistrer vos effets sonores est à la fois facile et enrichissant. Contrairement à la conception des actifs visuels, il ne faut pas beaucoup de talent. Tout le monde peut dire "Kaboom!" ou "Boing" ou crier "Vous êtes mort. Meilleure chance la prochaine fois!"

Je demande souvent à mes enfants d'enregistrer des effets sonores ainsi que des messages vocaux accompagnant des messages texte du type «VOUS GAGNEZ! ou 'GAME OVER!' Votre imagination est la seule limite.

Jouer de la musique de fond

La musique de fond doit jouer en permanence. En théorie, vous pouvez obtenir un effet sonore très loooooooong, mais une approche plus courante consiste simplement à jouer la musique de fond en boucle. Les fichiers de musique peuvent être au format .wav, .mp3 ou .midi. Voici comment c'est fait:

music = pygame.mixer.music.load ('background_music.mp3') pygame.mixer.music.play (-1, 0.0) 

Vous ne pouvez avoir qu'un morceau de musique de fond à la fois. Mais plusieurs effets sonores peuvent jouer sur la musique de fond. C'est ça le mixage.

Ajout de fonctionnalités avancées

Soyons fantaisie. Casser des briques avec une balle, c'est cool, mais ça vieillit assez vite. Que diriez-vous d'un système générique d'effets spéciaux? Nous allons développer un système extensible d'effets spéciaux associés à certaines briques et qui s'activeront lorsque la balle frappera la brique. 

Voici le plan. Les effets ont une vie. L'effet commence lorsque la brique se brise et se termine lorsque la durée de l'effet est écoulée. Que se passe-t-il si la balle frappe une autre brique à effets spéciaux? En théorie, vous pourriez avoir des effets composés, mais pour simplifier les choses lors de la mise en œuvre initiale, l'effet actif s'arrête et le nouvel effet prend sa place..

Système d'effets spéciaux

Un effet spécial peut être défini de la manière la plus générique en tant que deux fonctions. La première fonction active l'effet et la seconde le réinitialise. Nous voulons attacher des effets aux briques et indiquer clairement au joueur quelles briques sont spéciales, afin qu'il puisse essayer de les toucher ou de les éviter à certains moments.. 

Le dict suivant du module breakout.py définit nos effets spéciaux. Chaque effet a un nom (par exemple, long_paddle) et une valeur, constituée de la couleur que sa brique aura ainsi que des deux fonctions. Les fonctions sont définies comme des fonctions lambda prenant une instance de jeu, qui inclut tout ce qu'un effet spécial de Breakout peut vouloir changer..

special_effects = dict (long_paddle = (colors.ORANGE, lambda g: g.paddle.bounds.inflate_ip (c.paddle_width // 2, 0), lambda g: g.paddle.bounds.inflate_ip (c.paddle_width // 2, 0), lambda g: g.paddle.bounds.inflate_ip (-c.paddle_width // 2 , 0)), slow_ball = (colors.AQUAMARINE2, lambda g: g.change_ball_speed (-1), lambda g: g.change_ball_speed (1)), tripple_points = (colors.DARKSEAGREEN4, lambda g: g.set_points_per_brick (3) , lambda g: g.set_points_per_brick (1)), extra_life = (couleurs.GOLD1, lambda g: g.add_life (), lambda g: aucune))

Lorsque les briques sont créées, un changement leur est attribué pour qu’un des effets spéciaux soit créé. Voici le code:

def create_bricks (self): w = c.brick_width h = c.brick_height brick_count = c.screen_width // (w + 1) offset_x = (c.screen_width - brick_count * (w + 1)) // 2 bricks = [] pour ligne dans la plage (c.row_count): pour col dans la plage (brick_count): effect = None brick_color = c.brick_color index = random.randint (0, 10) si index < len(special_effects): x = list(special_effects.values())[index] brick_color = x[0] effect = x[1:] brick = Brick(offset_x + col * (w + 1), c.offset_y + row * (h + 1), w, h, brick_color, effect) bricks.append(brick) self.objects.append(brick) self.bricks = bricks 

La classe Brick a un champ d'effet qui est généralement Aucun, mais peut obtenir (30% de chance) l'un des effets spéciaux définis ci-dessus. Notez que ce code ignore quels effets sont disponibles. Il obtient simplement l'effet et la couleur de la brique et les assigne si nécessaire. 

Dans cette version de Breakout, je déclenche des effets uniquement lorsqu'une brique est touchée, mais vous pouvez imaginer d'autres scénarios pouvant déclencher des événements. L'effet précédent est réinitialisé (s'il y en avait un), puis le nouvel effet est lancé. La fonction de réinitialisation et l’heure de début de l’effet sont mémorisées pour plus tard..

si brick.special_effect n'est pas None: # Réinitialise l'effet précédent s'il en existe un si self.reset_effect n'est pas None: self.reset_effect (self) # Effet spécial déclencheur self.effect_start_time = datetime.now () brick.special_effect [0] (self) # Définition de la fonction d’effet de réinitialisation actuelle self.reset_effect = brick.special_effect [1]

Si aucun nouvel effet n'a été déclenché, nous devons toujours réinitialiser l'événement en cours à son expiration. Cela se passe dans le mettre à jour() méthode. Dans chaque image, la fonction de réinitialisation de l’effet actuel a été attribuée à la reset_effect champ. Si le temps écoulé depuis le début de l’effet en cours a dépassé la durée de l’effet, le reset_effect () la fonction est appelée et la reset_effect le champ est défini sur Aucun (ce qui signifie qu'il n'y a pas d'effet actif pour le moment).

# Réinitialise l'effet spécial si nécessaire si self.reset_effect: elapsed = datetime.now () - self.effect_start_time si écoulé> = timedelta (secondes = c.effect_duration): self.reset_effect (self) self.reset_effect = None 

Agrandissement de la pagaie

L'effet pagaie longue agit en gonflant la pagaie de 50%. Sa fonction de réinitialisation le redimensionne à la normale. La couleur de la brique est orange:

long_paddle = (colors.ORANGE, lambda g: g.paddle.bounds.inflate_ip (largeur de c.paddle // 2, 0), lambda g: g.paddle.bounds.inflate_ip (-c.paddle_width // 2, 0)),

Ralentir la balle

Un autre effet qui aide à poursuivre la balle est l’effet balle lente, qui ralentit simplement la vitesse de la balle d’une unité. La couleur de la brique est Aquamarine.

slow_ball = (couleurs.AQUAMARINE2, lambda g: g.change_ball_speed (-1), lambda g: g.change_ball_speed (1)), 

Plus de points

Si vous voulez de gros chiffres, vous aimerez l'effet de triple point qui vous donne trois points pour chaque brique que vous frappez au lieu du point standard. La couleur de la brique est vert foncé.

tripple_points = (couleurs.DARKSEAGREEN4, lambda g: g.set_points_per_brick (3), lambda g: g.set_points_per_brick (1)),

Vies supplémentaires

Enfin, l'effet des vies supplémentaires est très utile. Cela vous donne juste une vie supplémentaire. Aucune réinitialisation n'est vraiment nécessaire. La couleur de la brique est or.

extra_life = (couleurs.GOLD1, lambda g: g.add_life (), lambda g: aucune))

Caractéristiques futures

Il y a plusieurs directions naturelles pour prolonger l'évasion. Si vous souhaitez essayer d'ajouter d'autres fonctionnalités, voici quelques idées..

Prenez-le au prochain niveau

Pour que Breakout soit un jeu sérieux, il faut des niveaux. Jouer sur un seul écran ne suffit pas. Au début de chaque niveau, vous réinitialiserez l'écran, mais garderez le score et vivra tel quel. Pour rendre le jeu plus difficile, vous pouvez augmenter légèrement la vitesse de la balle à chaque niveau ou ajouter une autre couche de briques.

Deuxième balle

Ajouter une seconde balle en tant qu'effet temporaire est voué à créer beaucoup de chaos. La partie délicate à traiter ici est de traiter les deux balles de la même manière, quel que soit le modèle original. Quand une balle est partie, le jeu continue avec la balle simple qui a été laissée. Aucune vie n'est perdue.

Score élevé persistant

Lorsque vous avez des niveaux de difficulté croissante, le score élevé devient un prix convoité. Vous pouvez conserver le meilleur score dans un fichier pour qu'il persiste entre les parties. Quand un joueur bat le meilleur score, vous pouvez ajouter un petit pizazz ou le laisser écrire son nom (traditionnellement trois personnages).

Bombes et Power-Ups

Dans la mise en œuvre actuelle, tous les effets spéciaux sont liés aux briques, mais vous pouvez ajouter des effets (bons et mauvais) qui tombent du ciel et le joueur doit les récupérer ou les éviter..

Conclusion

Développer Breakout avec Python 3 et Pygame a été une expérience enrichissante. C'est une combinaison très puissante pour les jeux 2D (et les jeux 3D également). Si vous aimez Python et que vous voulez créer vos propres jeux, vous ne pouvez pas vous tromper avec Pygame. 

J'ai bien l'intention de faire plus de jeux avec Python et Pygame.

Enfin, rappelez-vous que nous avons beaucoup de contenu Python disponible à la vente et à étudier sur le marché Envato..