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

Contenu supprimé Contenu ajouté
NewBorn (discussion | contributions)
NewBorn (discussion | contributions)
Ligne 257 :
:<math>\theta_{deg} = \theta_{rad} \cdot {180 \over \pi} \qquad et \qquad \theta_{rad} = \theta_{deg} \cdot {\pi \over 180}</math>
 
== Objets contrôlés par l'utilisateur ==
== User-controllable objects==
 
Pour l'instant, vous avez créé une fenêtre Pygame, et fait un rendu d'une balle qui se déplace sur l'écran. La prochaine étape est de créer quelques battes qui soient sous le contrôle de l'utilisateur. C'est potentiellement plus simple que la balle, car çà ne requiert aucune physique. Toutefois ceci ne se vérifie plus lorsque votre objet possède des déplacements plus complexe que haut et bas, par exemple dans un jeu de plateforme comme Mario, auquel cas vous aurez besoin de mettre en jeu de la physique. Les objets contrôlables sont simples à mettre en oeuvre, remerciez Pygame pour son système de file d'évènements, comme vous pourrez le voir.
===A simple bat class===
 
===Diversion 3:Une Pygamesimple classe Bat events===
 
Le principe derrière la classe Bat est similaire à la classe Ball. Vous avez besoin d'une méthode <tt>__init__()</tt> pour initialiser la batte (vous pourrez donc créer des instances d'objet pour chaque batte), d'une méthode <tt>update()</tt> pour appliquer les changements sur la batte avant de la blitter à l'écran, et diverses autres méthodes qui définiront ce que fait cette classe. Voici un échantillon du code :
 
<source lang="python">
class Bat(pygame.sprite.Sprite):
"""Batte mobile B) qui peut frapper la balle
Retourne: objet bat
Méthode: reinit, update, moveup, movedown
Attributs: which, speed"""
 
def __init__(self, side):
pygame.sprite.Sprite.__init__(self)
self.image, self.rect = load_png('bat.png')
screen = pygame.display.get_surface()
self.area = screen.get_rect()
self.side = side
self.speed = 10
self.state = "still"
self.reinit()
 
def reinit(self):
self.state = "still"
self.movepos = [0,0]
if self.side == "left":
self.rect.midleft = self.area.midleft
elif self.side == "right":
self.rect.midright = self.area.midright
 
def update(self):
newpos = self.rect.move(self.movepos)
if self.area.contains(newpos):
self.rect = newpos
pygame.event.pump()
 
def moveup(self):
self.movepos[1] = self.movepos[1] - (self.speed)
self.state = "moveup"
 
def movedown(self):
self.movepos[1] = self.movepos[1] + (self.speed)
self.state = "movedown"
</source>
 
Comme vous pouvez le voir, cette classe est très similaire à la classe Ball dans sa structure. Mais les différences se situent dans ce que font chaque fonction. Tout d'abord, il y a une méthode <tt>reinit()</tt> qui est utilisée lorsqu'un round est terminé : la batte retourne dans sa position de départ, et chacun de ses attributs à ses valeurs d'origine. Ensuite, la manière dont la batte bouge est un peu plus complexe que la balle, étant donné que ses mouvements sont simples (haut/bas) mais dépendent de ce que désire l'utilisateur, tandis que la balle conservera son mouvement à chaque image. Pour mettre en évidence la façon dont la batte bouge, il est pratique d'examiner ce petit diagramme pour voir la séquence des évènements :
 
{| border = "0"
|Le joueur enfonce la touche <math>\uparrow</math>
|<math>\Rightarrow</math>
|self.state = "moving"<br>self.moveup()
|<math>\Rightarrow</math>
|Le joueur relache la touche
|<math>\Rightarrow</math>
|self.state = "still"<br>self.movepos = [0,0]
|}
 
C'est ce qui se passe ici si la personne qui contrôle la batte enfonce la touche qui fait se déplacer la batte vers le haut. A chaque itération de la boucle principale du jeu (à chaque image), si la touche est maintenue enfoncée, alors l'attribut <tt>state</tt> de cet objet batte sera paramétré à "moving", et la méthode <tt>moveup()</tt> sera appelée, causant la réduction de la position Y de la batte d'une valeur correspondant à l'attribut <tt>speed</tt> (dans cet exemple 10). En d'autre mots, tant que la touche reste enfoncée, la batte se déplacera à l'écran de 10 pixels par image. L'attribut <tt>state</tt> 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ébugage.
 
==== Diversion 3 : évènements Pygame ====
 
Alors, comment allons nous savoir quand le joueur est entrain d'enfoncer la touche, ou la relâche ? Avec le système de file d'évènement de Pygame, pardi! C'est un système vraiment simple à utiliser et à comprendre, çà ne devrait pas être long :) Vous avez déjà observé la file d'évènement en action dans le programme Pygame de base, où elle était utilisée pour vérifier si l'utilisateur voulait quitter l'application. Le code pour déplacer la batte est aussi simple que çà :
 
<source lang="python">
for event in pygame.event.get():
if event.type == QUIT:
return
elif event.type == KEYDOWN:
if event.key == K_UP:
player.moveup()
if event.key == K_DOWN:
player.movedown()
elif event.type == KEYUP:
if event.key == K_UP or event.key == K_DOWN:
player.movepos = [0,0]
player.state = "still"
</source>
 
Ici nous supposons que vous avez déjà créé une instance de <tt>Bat</tt>, et appelé l'objet <tt>player</tt>. Vous pouvez observer la couche familière de la structure <tt>for</tt>, qui produit une itération à chaque évènement trouvé dans la file d'évènement de Pygame, eux-même retrouvés grâce à la fonction <tt>event.get()</tt>. L'utilisateur enfonce une touche, appuie sur le bouton de la souris, ou bouge le joystick, toutes ces actions seront placées dans la file d'évènement de Pygame, et conservées jusqu'à leur utilisation. Donc à chaque itération de la boucle de jeu principale, vous irez faire un tour dans ces évènements vérifier s'il y en a quelques uns que vous pouvez utiliser. La fonction <tt>event.pump()</tt> qui était dans la méthode <tt>Bat.update()</tt> est appelée à chaque itération pour ''pomper'' les vieux évènements et garder la file à jour.
 
D'abord nous vérifions si l'utilisateur veut quitter le programme, et si oui on quitte le programme. Ensuite nous vérifions si une touche est enfoncée, et si oui, nous vérifions si elle correspond à une des touches affectée au déplacement de la batte, si oui alors nous appelons la méthode de déplacement appropriée, et définissons l'état du joueur. A travers les états "moveup" et "movedown", modifiés par les méthodes <tt>moveup()</tt> et <tt>movedown()</tt>, nous produisons un code plus soigné et nous ne cassons pas l'''encapsulation'', ce qui signifie que vous assignez des attributs aux objets eux-mêmes, sans se référer au nom de l'instance de cet objet. Remarquez que nous avons 3 états : "still", "moveup" et "mouvedown". Encore une fois, ils deviennent utiles si vous voulez débugguer ou calculer un effet sur la balle. Nous vérifions aussi si une touche est "partie" (si elle n'est plus enfoncée), et alors si c'est la bonne touche, nous stoppons le déplacement de la batte.
 
== Putting it all together==