« Pygame/Chimp - Ligne par ligne » : différence entre les versions
Contenu supprimé Contenu ajouté
Aucun résumé des modifications |
Traduction complète |
||
Ligne 1 :
{{Pygame
Traduit de l'anglais, original par ''Pete Shinners'' :<br/>
http://www.pygame.org/docs/tut/chimp/ChimpLineByLine.html
== Introduction ==
Dans les exemples de Pygame, il y a un petit exemple nommé ''chimp''. Cet exemple simule un singe à frapper qui bouge dans un petit écran avec des promesses de récompenses. Cet exemple est en lui-même vraiment simple, et réduit la recherche d'erreurs dans le code. Cet exemple de programme démontre les possibilités de Pygame, comme la création de fenêtres graphiques, le chargement de fichiers d'images et de sons, de rendu de texte TTF (police TrueType), et la gestion des évènements de bases et des mouvements de la souris.
Ce programme ainsi que les images sont disponibles dans les sources de Pygame. Pour la version 1.3 de Pygame, cet exemple a été complètement réécrit pour ajouter quelques fonctions et corriger quelques erreurs. Ceci fait que la taille de l'exemple a doublé par rapport à l'original, mais nous donne plus de matière à analyse, aussi bon que soit le code, je ne peux que vous recommander de le réutiliser pour vos propres projets.
Ce tutoriel analyse le code bloc par bloc, expliquant comment le code fonctionne. Il sera également mentionné la façon dont le code pourrait être amélioré et quel contrôle d'erreur peut nous venir en aide.
Ceci est un excellent tutoriel pour les personnes qui étudient pour la première fois du code Pygame. Une fois Pygame complètement installé, vous pourrez trouver et exécuter vous-même la démo de ''chimp'' dans le répertoire des exemple.
== Importer des modules ==
Voici le code qui importe tous les modules nécessaires dans notre programme. Il vérifie la disponibilité de certains des modules optionnels de Pygame.
<source lang="python">
import os, sys
import pygame
from pygame.locals import *
if not pygame.font: print 'Attention, polices désactivées'
if not pygame.mixer: print 'Attention, son désactivé'
</source>
D'abord, nous importons les modules standards de Python <tt>os</tt> et <tt>sys</tt>. Ceux-ci nous permettent de faire certaines choses comme créer des chemins de fichiers indépendants du système d'exploitation.
Dans la ligne suivante, nous importons l'ensemble des modules de Pygame. Quand Pygame est importé, tous les modules appartenant à Pygame sont importés. Certains modules sont optionnels, s'ils ne sont pas trouvés, leur valeur est définie à <tt>None</tt>.
Il existe un module Pygame spécial nommé <tt>locals</tt>. Ce module contient un sous-ensembles de Pygame. Les membres de ce module utilisent couramment des constantes et des fonctions qui ont prouvés leur utilité à être incorporé dans l'espace de nom global de votre programme. Ce module de locales inclut des fonctions comme <tt>Rect()</tt> pour un objet rectangle, et plusieurs constantes comme <tt>QUIT, HWSURFACE</tt> qui sont utilisées pour interagir avec le reste de Pygame. L'importation de ce module de locales dans l'espace de nom global est complètement optionnel. Si vous choisissez de ne pas l'importer, tous les membres des locales sont toujours disponibles dans le module <tt>pygame</tt>.
Enfin, nous avons décidé d'imprimer un joli message si les modules <tt>font</tt> ou <tt>sound</tt> ne sont pas disponibles dans Pygame.
== Chargement des Ressources ==
Ici nous avons deux fonctions que nous pouvons utiliser pour charger des images et des sons. Nous examinerons chaque fonction individuellement dans cette section.
<source lang="python">
def load_image(name, colorkey=None):
fullname = os.path.join('data', name)
Ligne 44 ⟶ 46 :
image = pygame.image.load(fullname)
except pygame.error, message:
print
raise SystemExit, message
image = image.convert()
Ligne 52 ⟶ 54 :
image.set_colorkey(colorkey, RLEACCEL)
return image, image.get_rect()
</source>
Cette fonction prend le nom de l'image à charger. Elle prend également un argument optionnel qui peut être utilisé pour définir une couleur clé à l'image. Une couleur clé est utilisée dans les graphismes pour représenter une couleur de l'image qui devra être transparente.
La première chose que cette fonction fait, est de créer un chemin de fichier complet vers le fichier. Dans cet exemple, toutes les ressources sont situées dans le sous-répertoire <tt>data</tt>. En utilisant la fonction <tt>os.path.join()</tt>, un chemin sera créé qui fonctionnera quelque soit la plateforme sur laquelle est lancé le jeu.
Ensuite, nous chargeons l'image en utilisant la fonction <tt>pygame.image.load()</tt>. Nous enveloppons cette fonction dans un bloc de <tt>try/except</tt>, ainsi s'il y a un problème lors du chargement de l'image, nous pouvons quitter élégamment. Après que l'image soit chargée, nous faisons un appel important à la fonction <tt>convert()</tt>. Ceci crée une nouvelle copie de la Surface et la convertit dans un format et une profondeur de couleurs qui correspondent à l'affichage en cours. Ceci signifie que le blitage de l'image sur l'écran sera aussi rapide que possible.
Enfin, nous définissons la couleur clé de l'image. Si l'utilisateur fournit un argument pour la couleur clé, nous utiliserons cette valeur de couleur clé pour l'image. Ceci devrait être habituellement une valeur RGB, comme (255, 255, 255) pour le blanc. Vous pouvez également passer la valeur <tt>-1</tt> comme couleur clé. Dans ce cas, la fonction examinera la couleur en haut à gauche de l'image, et utilisera cette couleur comme couleur clé.
<source lang="python">
def load_sound(name):
class NoneSound:
Ligne 72 ⟶ 74 :
sound = pygame.mixer.Sound(fullname)
except pygame.error, message:
print '
raise SystemExit, message
return sound
</source>
Vient ensuite la fonction de chargement de fichier son. La première chose que cette fonction fait est de contrôler si le module <tt>pygame.mixer</tt> a été importé correctement. Si non, elle retourne une petite instance de classe qui possède une méthode de lecture factice. Ceci agira comme un objet Son normal pour ce jeu qui tournera sans contrôle d'erreur supplémentaire.
Cette fonction est similaire à la fonction de chargement d'image, mais gère des problèmes différents. En premier lieu nous créons un chemin complet vers le fichier son, et chargeons ce fichier son à travers un bloc <tt>try/except</tt>, qui nous retourne alors l'objet Son chargé.
== Classes d'objet du Jeu ==
<source lang="python">
class Fist(pygame.sprite.Sprite):
"""
def __init__(self):
pygame.sprite.Sprite.__init__(self) #
self.image, self.rect = load_image('fist.bmp', -1)
self.punching = 0
def update(self):
"
pos = pygame.mouse.get_pos()
self.rect.midtop = pos
Ligne 100 ⟶ 103 :
def punch(self, target):
"
if not self.punching:
self.punching = 1
Ligne 107 ⟶ 110 :
def unpunch(self):
"
self.punching = 0
</source>
Ici nous créons
<source lang="python">
class Chimp(pygame.sprite.Sprite):
"""
le singe quand
def __init__(self):
pygame.sprite.Sprite.__init__(self) #
self.image, self.rect = load_image('chimp.bmp', -1)
screen = pygame.display.get_surface()
Ligne 130 ⟶ 134 :
def update(self):
"
if self.dizzy:
self._spin()
Ligne 137 ⟶ 141 :
def _walk(self):
"
newpos = self.rect.move((self.move, 0))
if not self.area.contains(newpos):
Ligne 148 ⟶ 152 :
def _spin(self):
"
center = self.rect.center
self.dizzy += 12
Ligne 160 ⟶ 164 :
def punched(self):
"
if not self.dizzy:
self.dizzy = 1
self.original = self.image
</source>
La classe Chimp fait un peu plus de travail que celle du poing, mais rien de complexe. Cette classe déplacera le chimpanzé de gauche à droite sur l'écran. Quand le singe sera frappé, il tournoiera sur lui-même dans un superbe effet. Cette classe est dérivée de la classe de base Sprite, et est initialisée de la même façon que celle du poing. Pendant l'initialisation, la classe définit l'attribut <tt>area</tt> comme dimension de l'affichage.
La méthode <tt>_spin()</tt> est appelée quand le singe est ''étourdi'' (<tt>dizzy</tt>). L'attribut <tt>dizzy</tt> est utilisé pour enregistrer le nombre de rotation actuel. Quand le singe a entièrement tournoyé sur lui-même (360 degrés), il réinitialise l'image du singe à sa version droite originale. Avant d'appeler la fonction <tt>transform.rotate()</tt>, vous verrez que le code crée une référence locale à la fonction nommée <tt>rotate()</tt>. Il n'y a pas lieu de la faire pour cet exemple, nous l'avons uniquement fait ici pour conserver une longueur raisonnable à la ligne suivante. A noter qu'en appelant la fonction <tt>rotate()</tt>, nous faisons toujours tounoyer l'image originale du singe. Pendant la rotation, il y a une légère perte de qualité. Effectuer une rotation de façon répétitive sur la même image entraîne au fur et à mesure une dégradation de l'image. Quand une image tourne sur elle-même, la dimension de cette image sera modifiée. Ceci est dû au fait que les coins de l'image sortent de la dimension originale pendant la rotation, et augmente alors les dimensions de l'image. Nous nous assurons que le centre de la nouvelle image correspond au centre de l'ancienne image, de cette façon elle tournoie sans se déplacer.
== Tout initialiser ==
Avant d'aller plus loin avec Pygame, nous devons nous assurer que tous ces modules sont initialisés. Dans ce cas nous ouvrirons une simple fenêtre graphique. Maintenant nous sommes dans la fonction principale du programme, laquelle exécute tout.
<source lang="python">
pygame.init()
screen = pygame.display.set_mode((468, 60))
pygame.display.set_caption('Monkey Fever')
pygame.mouse.set_visible(0)
</source>
La première ligne d'initialisation de Pygame nous épargne un peu de travail. Elle contrôle les modules Pygame importés et tente d'initialiser chacun d'entre eux. Il est possible de vérifier si des modules n'ont pas échoué pendant l'initialisation, mais nous ne nous tracasserons pas avec ça. Il est ainsi possible d'effectuer un contrôle plus fin et d'initialiser chaque module spécifique à la main. Ce type de contrôle n'est généralement pas indispensable, mais il est disponible si besoin.
Ensuite, nous définissons le mode d'affichage. A noter que le module <tt>pygame.display</tt> est utilisé pour contrôler tous les paramètres d'affichage. Dans cet exemple, nous demandons une simple fenêtre. Il existe un tutoriel complet sur le paramétrage du mode graphique, mais nous n'en avons pas réellement besoin, Pygame effectue déjà un bon travail pour nous en obtenant quelque chose qui fonctionne. Pygame trouve la meilleure profondeur de couleur sans que nous lui en fournissons une.
Enfin nous définissons le titre de la fenêtre et désactivons le curseur de la souris de notre fenêtre. Très simple à faire, et maintenant nous avons une petite fenêre noire prête à recevoir nos requêtes. En fait le curseur est par défaut visible, ainsi il n'y a pas réellement besoin de définir son état tant que nous ne voulons pas le cacher.
== Créer l'arrière-plan ==
Notre programme affichera un message textuel en arrière-plan. Il serait bon pour nous de créer une simple surface pour représenter l'arrière-plan et l'utiliser à chaque fois. La première étape sera de créer cette surface.
<source lang="python">
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((250, 250, 250))
</source>
Ceci crée pour nous une nouvelle surface qui est de la même taille que la fenêtre d'affichage. A noter l'appel supplémentaire <tt>convert()</tt> après la création de la surface. La méthode <tt>convert()</tt> sans argument s'assure que notre arrière-plan est du même format que la fenêtre d'affichage, ce qui nous donnera des résultats plus rapide.
Nous remplissons alors entièrement l'arrière-plan avec une couleur blanchâtre. La méthode <tt>fill()</tt> prend un triplet RGB en argument de couleur.
== Appliquer le texte sur l'arrière-plan et le centrer ==
Maintenant que nous avons une surface d'arrière-plan, apppliquons-lui un rendu de texte. Nous le ferons uniquement si nous voyons que le module <tt>pygame.font</tt> a été importé correctement. Si non, nous passons cette section.
<source lang="python">
if pygame.font:
font = pygame.font.Font(None, 36)
Ligne 215 ⟶ 221 :
textpos = text.get_rect(centerx=background.get_width()/2)
background.blit(text, textpos)
</source>
Comme vous le
La police est créée avec le constructeur <tt>Font()</tt> du module <tt>font</tt>. En fait, nous passons le nom du fichier de police truetype à cette fonction, mais nous pouvons aussi passer <tt>None</tt> et utiliser la police par défaut. Le constructeur <tt>Font()</tt> nécessite de connaître la taille de la police que nous désirons créer.
Nous faisons alors un rendu de cette police dans la nouvelle surface. La fonction <tt>render()</tt> crée une nouvelle surface d'une taille appropriée à notre texte. Dans cet exemple, nous dirons aussi à la fonction <tt>render()</tt> de créer un texte anti-aliasé (pour obtenir un effet lissé) et d'utiliser une couleur gris sombre.
Ensuite nous avons besoin de trouver le centre du texte sur l'affichage. Nous créons un objet <tt>Rect</tt> qui nous permet de l'assigner facilement au centre de l'écran.
Enfin, nous ''blitons'' le texte sur l'image d'arrière-plan.
== Afficher l'arrière-plan une fois les paramètres définis ==
Nous avons encore une fenêtre noire sur l'écran. Affichons notre arrière-plan pendant que nous attendons de charger les autres ressources.
<source lang="python">
screen.blit(background, (0, 0))
pygame.display.flip()
</source>
Ceci ''blitera'' notre arrière-plan complet sur la fenêtre d'affichage. Le ''blit'' est lui-même trivial, mais qu'en est-il de la routine <tt>flip()</tt> ?
Dans Pygame, les changements de la surface d'affichage ne sont pas immédiatement visible. Normalement, un affichage doit être mis à jour dans les zones qui ont changé pour les rendre visibles à l'utilisateur. Avec l'affichage par double-tampon (double buffer), l'affichage doit être interverti pour rendre les changements visibles. Dans cet exemple, la fonction <tt>flip()</tt> fonctionne parfaitement parce qu'elle manipule la zone entière de la fenêtre et gère les surfaces en simple et double tampon.
== Préparer les objets du jeu ==
Ici nous créons tous les objets dont le jeu aura besoin.
<source lang="python">
whiff_sound = load_sound('whiff.wav')
punch_sound = load_sound('punch.wav')
Ligne 251 ⟶ 257 :
allsprites = pygame.sprite.RenderPlain((fist, chimp))
clock = pygame.time.Clock()
</source>
D'abord nous chargeons
L'objet <tt>clock</tt> que nous créons, sera utilisé pour contrôler le taux d'images par seconde de notre jeu. Nous l'utiliserons dans la boucle principale de notre jeu pour s'assurer qu'il ne fonctionne pas trop vite.
== La boucle principale ==
Rien de spécial ici, simplement une boucle infinie.
<source lang="python">
while 1:
clock.tick(60)
</source>
Tous les jeux exécute ce type de boucle. L'ordre des choses est de vérifier l'état de l'ordinateur et des entrées utilisateur, déplacer et actualiser l'état de tous les objets, et ensuite de les dessiner sur l'écran. Vous verrez que cet exemple n'est pas différent.
Nous faisons ainsi appel à notre objet <tt>clock</tt> qui s'assurera que notre jeu ne dépasse pas les 60 images par seconde.
== Gérer tous les évènements d'entrée ==
C'est un exemple extrêmement simple sur le fonctionnement de la pile d'évènement.
<source lang="python">
for event in pygame.event.get():
if event.type == QUIT:
Ligne 283 ⟶ 290 :
elif event.type == MOUSEBUTTONDOWN:
if fist.punch(chimp):
punch_sound.play() #
chimp.punched()
else:
whiff_sound.play() #
elif event.type == MOUSEBUTTONUP:
fist.unpunch()
</source>
D'abord, nous prenons tous les évènements disponibles de Pygame et faisons une boucle pour chacun d'eux. Les deux premiers testent si l'utilisateur a quitté notre jeu ou a appuyé sur la touche <tt>Echap</tt>. Dans ces cas, nous retournons simplement dans la fonction principale et le programme se termine proprement.
Ensuite, nous vérifions si le bouton de la souris a été enfoncé ou relaché. Si le bouton est enfoncé, nous demandons à l'objet poing si il est entré en collision avec le chimpanzé. Nous jouons l'effet sonore approprié, et si le singe est frappé, nous lui demandons de tournoyer (en appelant sa méthode <tt>punched()</tt>.
== Actualiser les Sprites ==
<source lang="python">
allsprites.update()
</source>
Les groupes de sprites possèdent une méthode <tt>update()</tt>, qui appelle la méthode <tt>update()</tt> de tous les sprites qu'ils contiennent. Chacun des objets se déplacera, en fonction de l'état dans lequel ils sont. C'est ici que le chimpanzé se déplacera d'un pas d'un côté à l'autre, ou tournoiera un peu plus loin s'il a récemment été frappé.
== Dessiner la scène entière ==
Maintenant que tous les objets sont à la bonne place, il est temps de les dessiner.
<source lang="python">
screen.blit(background, (0, 0))
allsprites.draw(screen)
pygame.display.flip()
</source>
Le premier appel à <tt>blit()</tt> dessinera l'arrière-plan sur la totalité de la fenêtre. Ceci effacera tout ce que nous avons vu de la scène précédente (peu efficace, mais suffisant pour ce jeu). Ensuite nous appelons la méthode <tt>draw()</tt> du conteneur de sprites. Depuis que ce conteneur de sprites est réellement une instance de groupe de sprite ''DrawPlain'', il sait comment dessiner nos sprites. Enfin grâce à la méthode <tt>flip()</tt>, nous affichons le contenu du tampon de Pygame à l'écran. Tout ce que nous avons dessiné apparaît en une seule fois.
== Game Over ==
L'utilisateur a quitté, c'est l'heure du nettoyage.
Le nettoyage d'un jeu dans Pygame est extrêmement simple. En fait depuis que toutes les variables sont automatiquement détruites, nous n'avons pas réellement besoin de faire quoi que ce soit.
|