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

Souvenez-vous que la tâche première de ces fonctions/classes est de s'assurer qu'avec le temps, l'écriture des classes d'objet, et de la boucle principale, il n'y ait presque plus rien à faire. L'héritage de classes peut rendre ces classes de bases utiles. Ne vous emballez pas, des fonctions qui ne seront utilisées que par une classe devront être écrites dans cette classe, et non pas dans une fonction globale.
 
== Classes d'objet de jeu ==
==Game object classes==
 
Une fois les modules chargées et les fonctions de gestion de ressources écrites, vous aimeriez écrire certains objets du jeu. La manière de le faire est très simple, bien qu'elle semble complexe au début. Vous devez écrire une classe pour chaque type d'objet du jeu, et ensuite vous pourrez créer une instance de ces classes pour chaque objet. Vous pourrez ensuite utiliser les méthodes de ces classes pour manipuler les objets, les déplacer et leur donner des capacités d'interaction. Votre jeu ressemblera donc à ceci (pseudo-code) :
===A simple ball class===
 
<source lang="python">
====Diversion 1: Sprites====
#!/usr/bin/python
==== Diversion 2: Vector physics====
# coding: utf-8
 
[Charger vos modules ici]
 
[Fonctions de gestion des ressources ici]
 
class Ball:
[fonctions de la balle (méthodes) ici]
[par exemple, une fonction qui calcule une nouvelle position]
[et une fonction pour vérifier si elle touche les bords]
 
def main:
[initier l'environnement du jeu ici]
 
[créer un nouvel objet, instance de la classe Ball]
ball = Ball()
 
while 1:
[Vérifier les entrées utilisateur]
 
[appel de la méthode update() de la balle]
ball.update()
</source>
 
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 <tt>__init__()</tt>, qui créera tous les attributs d'une balle, et <tt>update()</tt>, qui déplacera la balle dans sa nouvelle position, avant de la bliter à 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 <tt>main</tt> et/ou de la boucle du programme principal. Contrastez ceci avec le fait d'initialiser la balle dans la fonction <tt>main</tt>, 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!
 
===A Une simple ballclasse balle class===
 
Voici une classe simple incluant les fonctions nécessaires pour la création d'un objet balle qui se déplacera sur l'écran si la fonction <tt>update()</tt> est appelée :
 
<source lang="python">
class Ball(pygame.sprite.Sprite):
"""Une balle qui se déplace sur lécran
Retourne: objet ball
Fonctions: update, calcNewPos
Attributs: area, vector"""
 
def __init__(self, vector):
pygame.sprite.Sprite.__init__(self)
self.image, self.rect = load_png('ball.png')
screen = pygame.display.get_surface()
self.area = screen.get_rect()
self.vector = vector
 
def update(self):
newPos = self.calcNewPos(self.rect,self.vector)
self.rect = newPos
 
def calcNewPos(self,rect,vector):
(angle,z) = vector
(dx,dy) = (z*math.cos(angle),z*math.sin(angle))
return rect.move(dx,dy)
</source>
 
Ici nous avons la classe <tt>Ball</tt>, avec une méthode <tt>__init__()</tt>, qui paramètre la balle, et une méthode <tt>update()</tt> qui change le rectangle de la balle pour une nouvelle position, et une méthode <tt>calcNewPos()</tt> pour calculer la nouvelle position de la balle basée sur sa position courante, et le vecteur par lequel elle se déplace. J'expliquerai la gestion de la physique dans un moment. La seule autre chose à noter est le ''docstring'', qui est un peu plus long cette fois, et explique les bases de la classe. Ces chaînes de caractères sont utiles non seulement pour vous-même et les autres programmeurs qui lisent votre code, mais aussi pour les outils qui [[w:Parseur|parsent]] votre code et le documentent. Elle ne feront pas la différence dans de petits programmes, mais dans les gros elles sont inestimables, c'est donc une bonne habitude à prendre.
 
==== 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 <tt>Sprite</tt>. L'héritage de classe est une fonctionnalité géniale de Python. A partir de maintenant la classe <tt>Ball</tt> possède toutes les méthodes de la classe <tt>Sprite</tt>, n'importe quelle instance d'objet de la classe <tt>Sprite</tt> sera enregistrée comme étant un sprite par Pygame. Tant que le texte et l'arrière-plan ne se déplacent pas, ca reste correcte de bliter 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 <tt>Ball</tt> et un objet <tt>Sprite</tt> pour cette balle, et ensuite vous appelez la méthode <tt>update()</tt>sur l'objet <tt>Sprite</tt>, 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 <tt>Sprite</tt> vous fournit spécialement les deux méthodes <tt>spritecollide()</tt> et <tt>groupcollide()</tt>.
 
==== Diversion 2 : VectorPhysique des vecteurs physics====
 
Les autres choses à connaître à propos de ce code, en dehors de la structure de la classe <tt>Ball</tt>, ce sont les physiques de vecteur, utilisées pour calculer le mouvement de la balle. Dans n'importe quel jeu impliquant un mouvement angulaire, vous devez être à l'aise en trigonométrie, je ferais juste une petite introduction sur ce que vous devez savoir, pour comprendre la méthode <tt>calcNewPos()</tt>.
 
Pour commencer, vous avez remarqué que la balle possède un attribut <tt>vector</tt>, qui est construit à partir de <tt>angle</tt> et de <tt>z</tt>. L'angle est mesuré en [[w:Radian|radians]] et vous donne la direction dans laquelle se dirige la balle. <tt>z</tt> correspond à la vitesse à laquelle la balle se déplace. Ainsi en utilisant ce vecteur, nous pouvons déterminer la direction et la vitesse de la balle, et donc de combien elle doit se déplacer sur les axes X et Y.
 
[[Image:Pygame-radians.png]]
 
Le diagramme ci-dessus illustre les bases mathématiques derrière les vecteurs. Dans la partie gauche du diagramme, vous pouvez voir le mouvement projeté de la balle, représenté par la ligne bleue. La longueur de cette ligne (z) représente sa vitesse et l'angle est la direction dans elle se déplace. L'angle 0 pour le mouvement de la balle sera toujours pris dans le sens positif de l'axe des X (vers la droite), et sera mesuré dans le sens des aiguilles d'une montre comme vu sur le diagramme.
 
A partir de l'angle et de la vitesse de la balle, nous pouvons maintenant définir de combien s'est déplacée la balle le long des axes X et Y. Nous en avons besoin car Pygame n'inclut pas les calcul de vecteurs, et nous pouvons seulement déplacer la balle en bougeant son rectangle le long des deux axes. Nous avons donc besoin de faire correspondre l'angle et la vitesse en mouvement sur les axes X (dx) et Y (dy). C'est une simple question de géométrie, et peut être obtenue grâce aux formules du diagramme.
 
Si vous avez étudié la trigonométrie élémentaire auparavant, rien ne sera nouveau pour vous. Mais au cas où vous l'auriez oubliée, voici quelques formules indispensables qui vous aideront à visualiser les angles (je trouve plus facile de visualiser les angles en degrés plutôt qu'en radians).
 
radians = degrés * pi / 180
 
degrés = radians * 180 / pi
 
== User-controllable objects==
54

modifications