« Pygame/Concevoir des jeux avec Pygame » : différence entre les versions

Aucun résumé des modifications
(✓)
 
{{Pygame}}
 
{{À faire|traduire ''blitt''}}
 
== Introduction ==
background.blit(text, textpos)
 
# BlitterTransférer le tout dans la fenêtre
screen.blit(background, (0, 0))
pygame.display.flip()
En ce qui concerne le texte, nous avons besoin de plus d'un objet. D'abord nous créons un objet <code>font</code>, qui définira quelle police nous utiliserons, ainsi que sa taille. Ensuite nous créons un objet <code>text</code>, en utilisant la méthode de rendu de notre objet <code>font</code> et en lui fournissant trois arguments : le texte à faire le rendu, qui sera ou non anti-crénelé (1=oui, 0= non), ainsi que la couleur du texte (toujours dans un format RGB). Ensuite nous créons un troisième objet texte qui fournira le rectangle du texte. La manière la plus simple à comprendre est de s'imaginer en train de dessiner un rectangle qui englobera tout le texte. Vous pourrez alors utiliser ce rectangle afin d'obtenir ou de définir la position du texte sur la fenêtre d'affichage. Ainsi dans cet exemple nous avons le rectangle, et définissons ses attributs <code>centerx</code> et <code>centery</code> pour correspondre aux <code>centerx</code> et <code>centery</code> de l'arrière-plan, alors le texte aura le même centre que l'arrière-plan. Dans cet exemple, le texte sera centré sur les axes <code>x</code> et <code>y</code> de la fenêtre d'affichage.
 
=== BlittingTransfert pour afficher ===
 
Maintenant que nous avons créé les objets de notre jeu, nous avons besoin d'en faire le rendu.
Maintenant que nous avons créé les objets de notre jeu, nous avons besoin d'en faire le rendu. Si nous ne le faisons pas et que nous exécutons le programme, nous ne verrons qu'une fenêtre blanche, et nos objets resteront invisibles. Le terme employé pour faire un rendu des objets est le ''blitting'' (que nous franciserons par ''blit''), qui correspond à la copie de pixels d'un objet source vers un objet de destination. Ainsi pour faire une rendu de l'objet <code>background</code>, vous le blitez<!-- aah !--> sur l'objet <code>screen</code>. Dans cet exemple, pour faire les choses simples, nous blitons le texte sur l'arrière-plan (donc l'arrière-plan possède une copie du texte sur lui), et ensuite nous blitons l'arrière-plan sur l'écran.
Si nous ne le faisons pas et que nous exécutons le programme, nous ne verrons qu'une fenêtre blanche, et nos objets resteront invisibles.
Le terme employé pour faire un rendu des objets est le ''blitting'' (''blit'' contraction du nom de la fonction BitBlT signifiant Transfert d'un bloc de bits), qui correspond à la copie de pixels d'un objet source vers un objet de destination.
Ainsi pour faire une rendu de l'objet <code>background</code>, vous le transférez sur l'objet <code>screen</code>.
Dans cet exemple, pour faire les choses simples, nous transférons le texte sur l'arrière-plan (donc l'arrière-plan possède une copie du texte sur lui), et ensuite nous transférons l'arrière-plan sur l'écran.
 
Le transfert est une des opérations les plus lentes dans un jeu, vous devez donc faire attention à ne pas trop faire de transferts sur l'écran pour chaque image.
Le blit est une des opérations les plus lentes dans un jeu, vous devez donc faire attention à ne pas trop faire de blit sur l'écran pour chaque image. Par exemple, si vous avez une image d'arrière-plan, et une balle se déplaçant à travers l'écran, alors vous pouvez bliter l'arrière-plan en entier et ensuite la balle, tout ceci à chaque image, ce qui recouvrira la position précédente de la balle et fera un rendu de la nouvelle balle, mais ce sera plutôt lent. Une meilleure solution consiste à bliter une partie de l'arrière-plan sur la zone occupée par la balle à l'image précédente, qui peut être trouvée grâce au <code>rect</code> de la balle précédente, et ensuite bliter la nouvelle balle, ce qui aura pour effet de bliter seulement deux petites zones.
Par exemple, si vous avez une image d'arrière-plan, et une balle se déplaçant à travers l'écran, alors vous pouvez transférer l'arrière-plan en entier et ensuite la balle, tout ceci à chaque image, ce qui recouvrira la position précédente de la balle et fera un rendu de la nouvelle balle, mais ce sera plutôt lent.
Une meilleure solution consiste à transférer une partie de l'arrière-plan sur la zone occupée par la balle à l'image précédente, qui peut être trouvée grâce au <code>rect</code> de la balle précédente, et ensuite afficher la nouvelle balle, ce qui aura pour effet de transférer seulement deux petites zones.
 
=== La boucle d'évènement ===
 
Une fois que vous avez défini le jeu, vous avez besoin de le mettre dans une boucle qui s'exécutera en continu jusqu'à ce que l'utilisateur signale qu'il veuille quitter. Vous démarrerez donc une boucle ouverte, et à chaque itération de la boucle, qui sera chaque image du jeu, vous actualiserez le jeu. La première chose à contrôler pour chaque évènement, est de savoir si l'utilisateur à enfoncé une touche du clavier, cliqué un bouton de la souris, déplacé le joystick, redimensionné la fenêtre, ou tenté de la fermer. Dans ce cas, nous voudrons simplement examiner si l'utilisateur a essayé de fermer la fenêtre, auquel cas le jeu engendrera un <code>return</code>, ce qui terminera la boucle <code>while</code>. Alors nous aurons simplement besoin de re-blitertransférer l'arrière-plan, et faire un ''flip'' (actualisation de l'affichage par changement de la zone mémoire affichée) de l'écran pour que chaque chose soit redessinée. D'accord, étant donné que rien ne se passe ou se déplace dans cet exemple, nous n'avons aucunement besoin de re-blitertransférer l'arrière-plan à chaque itération, mais je le met parce que si certaines choses se déplacent à travers l'écran, vous aurez besoin de faire tous vos blitstransferts ici.
 
=== Ta-da ! ===
</syntaxhighlight>
 
Ici nous avons créé une fonction de chargement d'image plus sophistiquée que celle fournie par Pygame : <code>image.load()</code>. À noter que la première ligne de la fonction débute par un ''docstring'' (chainechaîne de caractère de documentation) qui décrit ce que fait la fonction et quel objet elle retourne. La fonction suppose que toutes vos images soient dans un répertoire appelé <code>data</code>, et donc utilisera le nom de fichier et créera le chemin complet (par exemple <code>data/ball.png</code>), en utilisant le module <code>os</code> pour s'assurer de la compatibilité entre plateforme différente (Linux, MacOS, Windows, ...). Ensuite elle essaye de charger l'image, et de convertir les régions alpha (ce qui vous permettra d'utiliser la transparence), et le cas échéant retourne une erreur ''lisible par un être humain'' si elle rencontre un problème. Finalement elle retourne un objet image, ainsi que son <code>rect</code>.
 
Vous pouvez créer des fonctions similaires pour le chargement de n'importe quelle autre ressource, tel que le chargement des sons. Vous pouvez aussi créer des classes de gestion de ressources, pour vous donner plus de flexibilité avec des ressources plus complexes. Par exemple, vous pouvez créer une classe <code>Music</code>, avec une fonction <code>__init__()</code> qui charge le son (peut-être en empruntant la fonction <code>load_sound()</code>), une méthode pour mettre en pause la musique, une méthode pour la redémarrer. Une autre classe de gestion de ressources utile peut être créée pour les connexions réseau. Des fonctions pour ouvrir des [[Apprendre à programmer avec Python/Communications à travers un réseau|sockets]], passer des données avec une sécurité appropriée et muni d'un contrôle d'erreur, fermer des sockets, [http://jargonf.org/wiki/finger finger] des adresses, ainsi que d'autres tâches concernant le réseau, pourront rendre l'écriture d'un jeu avec des capacités réseau moins pénible.
</syntaxhighlight>
 
Ce n'est bien sûr qu'un exemple très simple, et vous aurez besoin d'y insérer tout le code nécessaire, en lieu et place des commentaires entre crochets. Mais vous devez connaître l'idée de base. Vous créez une classe, dans laquelle vous insérez toutes les fonctions d'une balle, en y incluant <code>__init__()</code>, qui créera tous les attributs d'une balle, et <code>update()</code>, qui déplacera la balle dans sa nouvelle position, avant de la blitertransférer à l'écran dans cette position.
 
Vous avez la possibilité de créer d'autres classes pour tous les autres objets de jeu, et vous pourrez ensuite créer des instances pour chaque, et ainsi les gérer facilement à partir de la fonction <code>main</code> et/ou de la boucle du programme principal. Contrastez ceci avec le fait d'initialiser la balle dans la fonction <code>main</code>, et alors vous obtiendrez quantité de fonctions sans classes pour manipuler cet objet balle, et vous comprendrez heureusement pourquoi l'utilisation des classes est un avantage : cela vous permet de mettre tout le code de chaque objet à un seule endroit. Ceci rend l'utilisation des objets plus simple, et l'ajout de nouveaux objets et leur manipulation plus flexible. Au lieu d'ajouter plus de code pour chaque nouvel objet balle, vous pouvez simplement créer de nouvelles instances pour chaque nouvel objet balle. Magique !
 
=== Une simple classe balle ===
==== Diversion 1 : Sprites ====
 
L'autre raison à la création d'une classe pour chaque objet est les sprites. Chaque image dont vous ferez le rendu dans votre jeu sera un objet sprite, et pour commencer : la classe de chaque objet devra hériter de la classe <code>Sprite</code>. L'héritage de classe est une fonctionnalité géniale de Python. À partir de maintenant la classe <code>Ball</code> possède toutes les méthodes de la classe <code>Sprite</code>, n'importe quelle instance d'objet de la classe <code>Sprite</code> sera enregistrée comme étant un sprite par Pygame. Tant que le texte et l'arrière-plan ne se déplacent pas, caça reste correctecorrect de blitertransférer l'objet sur l'arrière-plan, Pygame manipule les objets sprite d'une manière différente que vous verrez lorsque nous examinerons le code du programme en entier.
 
En résumé, vous créez un objet <code>Ball</code> et un objet <code>Sprite</code> pour cette balle, et ensuite vous appelez la méthode <code>update()</code>sur l'objet <code>Sprite</code>, ce qui actualisera le sprite. Les sprites vous fournissent une manière sophistiquée de déterminer si deux objets sont en collision. Normalement vous pouvez simplement contrôler dans la boucle principale si leur rectangle se chevauchent, mais ca implique beaucoup de code qui sera inutile puisque la classe <code>Sprite</code> vous fournit spécialement les deux méthodes <code>spritecollide()</code> et <code>groupcollide()</code>.
=== Une simple classe Bat ===
 
Le principe derrière la classe Bat est similaire à la classe Ball. Vous avez besoin d'une méthode <code>__init__()</code> pour initialiser la raquette (vous pourrez donc créer des instances d'objet pour chaque raquette), d'une méthode <code>update()</code> pour appliquer les changements sur la raquette avant de la blittertransférer à l'écran, et diverses autres méthodes qui définiront ce que fait cette classe. Voici un échantillon du code :
 
<syntaxhighlight lang="python">
|}
 
C'est ce qui se passe ici si la personne qui contrôle la raquette enfonce la touche qui fait se déplacer la raquette vers le haut. À chaque itération de la boucle principale du jeu (à chaque image), si la touche est maintenue enfoncée, alors l'attribut <code>state</code> de cet objet raquette sera paramétré à "moving", et la méthode <code>moveup()</code> sera appelée, causant la réduction de la position Y de la raquette d'une valeur correspondant à l'attribut <code>speed</code> (dans cet exemple 10). En d'autre mots, tant que la touche reste enfoncée, la raquette se déplacera à l'écran de 10 pixels par image. L'attribut <code>state</code> n'est pas utilisé ici, mais c'est très utile de le connaître si vous désirez appliquer des effets à la balle, ou si vous utilisez une sortie pour le débugagedébogage.
 
==== Diversion 3 : évènements Pygame ====