Définit les informations sur le document
Dans ce tutoriel nous allons voir: Principes fondamentaux du jeu, but du jeu et aspects non couverts dans ce jeu, dessiner le joueur et ennemies, déplacement du joueur et des ennemies.
Ce tutoriel vous apprendra à créer des jeux en utilisant Python et la bibliothèque PyGame. À la fin de ce cours, vous serez capable de :
Ce tutoriel suppose que vous avez une connaissance de base de la programmation Python, y compris :
PyGame est une bibliothèque Python qui permet de créer des jeux vidéo. Elle est portable sur différentes plates-formes et appareils, ce qui signifie qu'un jeu créé avec PyGame peut être exécuté sur un PC, un Mac ou un appareil mobile.
Pour atteindre cette portabilité, PyGame utilise des abstractions pour différentes réalités matérielles. Ces abstractions permettent de cacher les détails spécifiques de chaque plate-forme ou appareil, afin que le développeur puisse se concentrer sur la création du jeu.
La bibliothèque PyGame est composée de plusieurs modules, chacun fournissant un accès abstrait à un aspect du matériel. Par exemple, le module display fournit un accès à l'écran, le module joystick fournit un accès aux manettes de jeu, et le module music fournit un accès aux fichiers audio.
Lorsque vous commencez un programme PyGame, vous devez d'abord importer et initialiser la bibliothèque. Cela se fait en appelant la fonction pygame.init(). Cette fonction appelle les fonctions init() de tous les modules PyGame inclus.
Votre programme pygame de base permet de dessiner une forme directement sur la surface de l'écran, mais vous pouvez également travailler avec des images sur le disque. Le module image vous permet de charger et d'enregistrer des images dans une variété de formats populaires. Les images sont chargées dans des objets Surface, qui peuvent ensuite être manipulés et affichés de nombreuses façons.
Comme mentionné ci-dessus, les objets Surface sont représentés par des rectangles, comme beaucoup d'autres objets dans pygame, tels que les images et les fenêtres. Les rectangles sont tellement utilisés qu'il existe une classe Rect spéciale pour les gérer. Vous utiliserez les objets Rect et les images dans votre jeu pour dessiner les joueurs et les ennemis, et pour gérer les collisions entre eux.
Voilà, assez de théorie. Concevons et écrivons un jeu !
Avant d'entamer le codage, il est toujours judicieux d'établir un plan de conception. Comme il s'agit d'un jeu didactique, établissons les bases du jeu :
Un de mes professeurs avait l'habitude de dire lorsqu'il parlait de la conception de logiciels : "On ne sait ce qu'on doit faire que lorsque l'on prend conscience de ce qu'on ne doit pas faire." Gardant cela à l'esprit, voici quelques aspects qui ne seront pas couverts dans ce tutoriel :
Vous êtes libre d'expérimenter l'ajout de ces fonctionnalités ou d'autres à votre propre programme.
En avant !
Après avoir importé pygame, vous devrez également l'initialiser. Cela permet à pygame de connecter ses abstractions à votre matériel spécifique :
Exemple : Copier le code
# Importer le module pygame import pygame # Importer pygame.locals pour faciliter l'accès aux coordonnées clés # Mise à jour pour se conformer aux standards flake8 et black from pygame.locals import ( K_UP, K_DOWN, K_LEFT, K_RIGHT, K_ESCAPE, KEYDOWN, QUIT, ) # Initialiser pygame pygame.init()
La bibliothèque pygame définit beaucoup de choses en plus des modules et des classes. Elle définit aussi des constantes locales pour des choses comme les frappes de touches, les mouvements de souris et les attributs d'affichage. Vous faites référence à ces constantes en utilisant la syntaxe pygame.<CONSTANT>. En important des constantes spécifiques depuis pygame.locals, vous pouvez utiliser la syntaxe <CONSTANT> à la place. Cela vous permettra d'économiser quelques frappes et d'améliorer la lisibilité générale.
Il nous faut maintenant quelque chose pour dessiner ! Créez un écran qui servira de support (canevas) à l'ensemble du jeu :
Exemple : Copier le code
# Importer le module pygame import pygame # Importer pygame.locals pour un accès plus facile aux coordonnées clés # Mise à jour pour se conformer aux normes flake8 et black from pygame.locals import ( K_UP, K_DOWN, K_LEFT, K_RIGHT, K_ESCAPE, KEYDOWN, QUIT, ) # Initialiser pygame pygame.init() # Définir des constantes pour la largeur et la hauteur de l'écran SCREEN_WIDTH = 800 SCREEN_HEIGHT = 600 # Créer l'objet écran # La taille est déterminée par les constantes SCREEN_WIDTH et SCREEN_HEIGHT screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
Nous créons l'écran à utiliser en appelant pygame.display.set_mode() et en lui passant un tuple ou une liste avec la largeur et la hauteur désirées. Dans ce cas, la fenêtre est de 800x600, comme défini par les constantes SCREEN_WIDTH et SCREEN_HEIGHT. Cette fonction renvoie une surface qui représente les dimensions intérieures de la fenêtre. Il s'agit de la partie de la fenêtre que nous pouvons contrôler, tandis que le système d'exploitation contrôle les bords de la fenêtre et la barre de titre.
En exécutant ce programme maintenant, il est possible de voir une fenêtre s'afficher brièvement, puis disparaître immédiatement lorsque le programme se termine. Dans la section suivante, nous nous concentrerons sur la boucle principale du jeu afin de nous assurer que notre programme ne se termine que lorsqu'il reçoit les informations correctes.
Tous les jeux utilisent une boucle de jeu pour contrôler le déroulement de la partie. La boucle de jeu fait quatre choses très importantes :
La première chose que fait la boucle du jeu est de traiter les entrées de l'utilisateur pour permettre au joueur de se déplacer sur l'écran. Par conséquent, nous avons besoin d'un moyen de capturer et de traiter une variété d'entrées. ce que nous pouvons faire en appliquant le système d'événements de pygame.
Les pressions sur les touches, les mouvements de la souris et même les mouvements du joystick(manette de jeux) sont quelques-uns des moyens par lesquels un utilisateur peut fournir des données. Toutes les entrées de l'utilisateur entraînent la création d'un événement. Les événements peuvent se produire à tout moment et proviennent souvent (mais pas toujours) de l'extérieur du programme. Tous les événements de pygame sont placés dans la file d'attente des événements, à laquelle on peut accéder et que l'on peut manipuler. La gestion des événements est appelée "handling", et le code permettant de le faire est appelé "event handler" (gestionnaire d'événements).
Chaque événement dans pygame est associé à un type d'événement. Pour notre jeu, les types d'événements sur lesquels nous allons nous concentrer sont l'appui sur une touche et la fermeture d'une fenêtre. Les événements de pression de touche ont le type d'événement KEYDOWN, et l'événement de fermeture de fenêtre a le type QUIT. D'autres données peuvent être associées aux différents types d'événements. Par exemple, le type d'événement KEYDOWN possède également une variable appelée key pour indiquer quelle touche a été pressée.
Nous accédons à la liste de tous les événements actifs dans la file d'attente en appelant pygame.event.get(). Nous parcourons ensuite cette liste en boucle, nous vérifions chaque type d'événement et nous réagissons en conséquence :
Exemple : Copier le code
# Variable permettant de maintenir la boucle principale en cours d'exécution running = True # Boucle principale while running : # Regarde chaque événement dans la file d'attente for event in pygame.event.get() : # L'utilisateur a-t-il appuyé sur une touche ? if event.type == KEYDOWN : # Était-ce la touche Escape ? Si c'est le cas, arrêter la boucle. if event.key == K_ESCAPE : running = False # L'utilisateur a-t-il cliqué sur le bouton de fermeture de la fenêtre ? Si c'est le cas, arrêter la boucle. elif event.type == QUIT : running = False pygame.quit()
Examinons de plus près cette boucle de jeu :
En dehors de la boucle principale, il est important de fermer la fenêtre Pygame en appelant la fonction pygame.quit(). Cela libérera les ressources utilisées par Pygame.
Lorsque vous ajoutez ces lignes de code au code précédent et que vous l'exécutez, vous verrez une fenêtre avec un écran vide ou noir :
La fenêtre disparaîtra seulement lorsque vous appuierez sur la touche Esc ou lorsque vous déclencherez un événement QUIT en fermant la fenêtre.
Nous pouvons Dessiner à l'écran à l'aide de trois façons:
Rappelons qu'une Surface est un objet rectangulaire sur lequel vous pouvez dessiner, comme une feuille de papier vierge. L'objet écran est une Surface, et vous pouvez créer vos propres objets Surface séparément de l'écran d'affichage. Voyons comment cela fonctionne :
# Remplir l'écran de blanc screen.fill((255, 255, 255)) # Créer une surface et passer un tuple contenant sa longueur et sa largeur surf = pygame.Surface((50, 50)) # Donner une couleur à la surface pour la séparer de l'arrière-plan surf.fill((0, 0, 0)) rect = surf.get_rect()
Ce code remplit d'abord l'écran de blanc en utilisant la fonction pygame.display.fill(). La fonction prend en entrée un tuple de trois valeurs représentant les composantes rouge, verte et bleue de la couleur. Dans ce cas, les trois composantes sont égales à 255, ce qui correspond à la couleur blanche.
Ensuite, le code crée une surface de 50 pixels de large et 50 pixels de haut en utilisant la fonction pygame.Surface(). La fonction prend en entrée un tuple contenant la longueur et la largeur de la surface.
Enfin, le code donne une couleur noire à la surface en utilisant la fonction pygame.Surface.fill(). La fonction prend en entrée un tuple de trois valeurs représentant les composantes rouge, verte et bleue de la couleur. Dans ce cas, les trois composantes
sont égales à 0, ce qui correspond à la couleur noire.La variable rect contient les coordonnées et la taille de la surface. Elle peut être utilisée pour placer la surface sur l'écran.
Il ne suffit pas de créer une nouvelle surface pour la voir à l'écran. Pour ce faire, il est nécessaire de fusionner la surface avec une autre surface. Le terme blit signifie Block Transfer (transfert de bloc) et .blit() permet de copier le contenu d'une surface sur une autre. Vous ne pouvez utiliser la fonction .blit() que d'une surface à l'autre, mais comme l'écran n'est qu'une autre surface, ce n'est pas un problème. Voici comment dessiner un surf sur l'écran :
# Cette ligne dit "Dessine un objet surf sur l'écran au centre" screen.blit(surf, (SCREEN_WIDTH/2, SCREEN_HEIGHT/2)) pygame.display.flip()
L'appel .blit() prend deux arguments :
Les coordonnées (SCREEN_WIDTH/2, SCREEN_HEIGHT/2) indiquent à votre programme de placer le surf au centre exact de l'écran, mais ce n'est pas tout à fait le cas :
La raison pour laquelle l'image semble décentrée est que .blit() place le coin supérieur gauche de surf à l'endroit indiqué. Si vous souhaitez que l'image soit centrée, vous devez effectuer des calculs pour la décaler vers le haut et vers la gauche. Vous pouvez le faire en soustrayant la largeur et la hauteur de surf de la largeur et de la hauteur de l'écran, en divisant chacune de ces valeurs par 2 pour localiser le centre, puis en passant ces nombres comme arguments à screen.blit() :
Exemple : Copier le code
# Placer le centre du surf au centre de l'écran surf_center = ( (SCREEN_WIDTH-surf.get_width())/2, (SCREEN_HEIGHT-surf.get_height())/2 ) # Dessine le surf aux nouvelles coordonnées screen.blit(surf, surf_center) pygame.display.flip()
Notez l'appel à pygame.display.flip() après l'appel à blit(). Cela met à jour l'écran entier avec tout ce qui a été dessiné depuis le dernier retournement. Sans l'appel à .flip(), rien n'est affiché.
Dans la conception de notre jeu, le joueur commence à gauche et les obstacles arrivent par la droite. Nous pouvons représenter tous les obstacles par des objets Surface pour faciliter le dessin, mais comment savoir où les dessiner ? Comment savoir si un obstacle est entré en collision avec le joueur ? Que se passe-t-il lorsque l'obstacle s'envole de l'écran ? Que faire si vous voulez dessiner des images d'arrière-plan qui bougent également ? Et si vous voulez que vos images soient animées ? Les sprites permettent de gérer toutes ces situations et bien d'autres encore.
En termes de programmation, un sprite est une représentation en 2D de quelque chose à l'écran. Pygame fournit une classe Sprite, qui est conçue pour contenir une ou plusieurs représentations graphiques de n'importe quel objet de jeu que vous souhaitez afficher à l'écran. Pour l'utiliser, nous devons créer une nouvelle classe qui étend la classe Sprite. Cela nous permet d'utiliser ses méthodes intégrées.
Voici comment utiliser les objets Sprite dans le jeu en cours pour définir le joueur.
Exemple : Copier le code
# Définir un objet Player en étendant pygame.sprite.Sprite # La surface dessinée sur l'écran est maintenant un attribut de 'player' class Player(pygame.sprite.Sprite) : def __init__(self) : super(Player, self).__init__() self.surf = pygame.Surface((75, 25)) self.surf.fill((255, 255, 255)) self.rect = self.surf.get_rect() Nous définissons d'abord Player en étendant pygame.sprite.Sprite. Ensuite, .__init__() utilise .super() pour appeler la méthode .__init__() de Sprite. Pour plus d'informations sur la nécessité de cette méthode, vous pouvez lire Supercharge Your Classes With Python super().
Ensuite, nous définissons et initialisons .surf pour contenir l'image à afficher, qui est actuellement une boîte blanche. Nous définissons et initialisons également .rect, que nous utiliserons plus tard pour dessiner le lecteur. Pour utiliser cette nouvelle classe, nous devons créer un nouvel objet et modifier le code de dessin.
Voici l'ensemble du code: :
Exemple : Copier le code
# Importer le module pygame import pygame # Importer pygame.locals pour faciliter l'accès aux coordonnées clés # Mise à jour pour se conformer aux normes flake8 et black from pygame.locals import ( K_UP, K_DOWN, K_LEFT, K_RIGHT, K_ESCAPE, KEYDOWN, QUIT, ) # Définir des constantes pour la largeur et la hauteur de l'écran SCREEN_WIDTH = 400 SCREEN_HEIGHT = 300 # Définir un objet joueur en étendant pygame.sprite.Sprite # La surface dessinée sur l'écran est maintenant un attribut de 'player' class Player(pygame.sprite.Sprite) : def __init__(self) : super(Player, self).__init__() self.surf = pygame.Surface((75, 25)) self.surf.fill((255, 255, 255)) self.rect = self.surf.get_rect() # Initialiser pygame pygame.init() # Créer l'objet écran # La taille est déterminée par les constantes SCREEN_WIDTH et SCREEN_HEIGHT screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) # Instanciation du joueur. Pour l'instant, c'est juste un rectangle. player = Player() # Variable pour maintenir la boucle principale en cours d'exécution running = True # Boucle principale while running : # Boucle de recherche dans la file d'attente des événements for event in pygame.event.get() : # Vérifier la présence d'un événement KEYDOWN if event.type == KEYDOWN : # Était-ce la touche Escape ? Si c'est le cas, arrêter la boucle. if event.key == K_ESCAPE : running = False # Vérifier s'il y a un événement QUIT. Si c'est le cas, mettre running à false. elif event.type == QUIT : running = False # Remplir l'écran de noir screen.fill((0, 0, 0)) # Dessine le joueur sur l'écran screen.blit(player.surf, (SCREEN_WIDTH/2, SCREEN_HEIGHT/2)) # Mettre à jour l'affichage pygame.display.flip() pygame.quit()
Ce code donne :
Que pensez-vous qu'il se passerait si vous remplaciez la ligne 59 par screen.blit(player.surf, player.rect) ? Essayez pour voir.
Lorsque vous passez un Rect à .blit(), il utilise les coordonnées du coin supérieur gauche pour dessiner la surface. Nous l'utiliserons plus tard pour faire bouger le joueur !