Tuto 4 : gérer des collisions

Ajouter des ennemis

Les tirs sont destinés à abattre des ennemis, il faut donc d'abord les créer dans le jeu !

Les images sont affichées à l’écran à raison de 30 frames ( = images ) par seconde ( ceci est modifiable lors de la création de la fenêtre du jeu ).

L’attribut frame_count du module Pyxel comptabilise le nombre d’images affichées depuis le début du jeu.
Ainsi, pour créer un ennemi toutes les secondes par exemple, on vérifie que le nombres d’images est un multiple de 30 :


if pyxel.frame_count % 30 == 0:	# utilisation de l'opérateur modulo = reste de la division 
	....... # création d'un ennemi			
			
Tuto 4

La création elle-même des ennemis repose sur le même principe que celui des tirs ( utilisation d'une liste liste_ennemis ), mais on utilise la fonction randint() du module random pour les créer de façon aléatoire selon l’axe des x.

Cette création pourra se faire directement dans la fonction update().

Compléter le code du script précédent en y ajoutant la création aléatoire d'ennemis toutes les secondes :

  • un ennemi sera représenté par un carré de même taille, mais de couleur différente du vaisseau.
  • la position initiale d'un ennemi sera un x aléatoire pris entre 0 et 127 ( pensez à importer au préalable la fonction randint() du module random ! ), et un y égal à 0.
  • il faudra bien entendu écrire les fonctions ennemi_bouge() et ennemi_draw() qui géreront le déplacement des ennemis, et leur suppression de la liste liste_ennemis lorsqu'il arriveront en bas de la fenêtre.
  • on complétera les fonctions update() et draw() pour y inclure la création et la gestion du mouvement des ennemis.

Gestion des collisions tir/ennemi

Lorsqu'un des tirs touche un des ennemis, il faut faire disparaître les deux.

Tuto 1

Deux problèmes se posent donc :

Algorithme à suivre


pour chaque ennemi dans la liste des ennemis:
	pour chaque tir dans la liste des tirs:
		si ennemi et tir entrent en collision:
			les supprimer tous les deux de leur liste respective
			augmenter ( éventuellement ) le score
			

C'est donc deux boucles imbriquées de parcours de listes qu'il faudra utiliser.

Détection de la collision

Pour le cas de la collision d’un tir avec un ennemi, trois conditions sur les coordonnées du tir et de l'ennemi doivent être vérifiées simultanément :

  • la coordonnée ytir doit être inférieure ou égale à yennemi + 8
  • la coordonnée xtir doit être comprise entre xennemi et xennemi + 8
Collision tir/ennemi

La fonction update() avec le code correspondant à la détection d'une collision tir/ennemi :


def update():

    ....

    for ennemi in liste_ennemis:
        for tir in liste_tirs:
            xt = tir[0]
            yt = tir[1]
            xe = ennemi[0]
            ye = ennemi[1]
            if yt <= ye+8 and ( xt >= xe and xt <= xe + 8):
                liste_tirs.remove(tir)
                liste_ennemis.remove(ennemi)
                score = score + 1
			

Gestion des collisions vaisseau/ennemi

Dans ce cas, il suffit de parcourir la liste liste_ennemis, et de détecter la collision entre chacun de ses éléments et le vaisseau ( plus besoin de boucles imbriquées ).


pour chaque ennemi dans la liste des ennemis:
	si ennemi et vaisseau entrent en collision:
		supprimer l'ennemi de la liste des ennemis
		diminuer le nombre de vies de 1
			

Par contre, les conditions à vérifier lorsqu'il y a collisions sont un peu plus délicates, car plusieurs situations peuvent se présenter.

Ne considérons pour l'instant que les conditions à vérifier sur l'axe des x; les deux situations limites pour lesquelles il peut y avoir collision sont :

Collision vaisseau ennemi horizontal

Par un raisonnement similaire sur l'axe des y, on constaterait qu'il y a collision si : ye - 8 <= yv <= ye + 8

Il y a donc 4 conditions à vérifier simultanément pour détecter une collision entre le vaisseau et un ennemi.

Bien entendu, ces relations sont à adapter au cas où les deux acteurs n'ont pas la même taille...

Compléter la fonction update() du script pour gérer la collision entre un ennemi et le vaisseau.

On pourra éventuellement gérer un système de vies pour le vaisseau, décrémentées lors d'une collision avec un ennemi; dans la fonction draw(), on pourra alors n'afficher les acteurs que si le nombre de vies est supérieur à 0, et sinon, afficher "GAME OVER" et le score ( méthode pyxel.text() de Pyxel ).


def draw():

	pyxel.cls(0)
	
	if vies > 0:
		# on affiche les acteurs
		.......
		
	else:
		pyxel.text(50, 64, 'GAME OVER', 7) # affichage au milieu de la fenêtre						
			

Remarque : le jeu continue cependant à "tourner"; pour quitter complètement une application Pyxel, utiliser la méthode pyxel.quit().

Ajout des explosions

Raffinement supplémentaire : rajouter des explosions lors de la destruction d'un ennemi.

Ces explosions peuvent être simplement représentées par quelques cercles de rayon croissant ( 5 par exemple dont le rayon va de 1 à 5 pixels ) qui se "propagent" depuis l'ancienne position de l'ennemi.

Tuto 1

La gestion des explosions peut se faire sur le même principe que les tirs et les ennemis, à savoir utiliser une liste liste_explosions, dans laquelle on ajoutera/supprimera au besoin des éléments.

Cependant, en plus des coordonnées de "départ" de l'explosion ( qui seront bien entendu égales, lors de la création de l'explosion, au milieu de l'ancienne position de l'ennemi ), il faut prévoir un troisième élément, qui indiquera à quel "stade" l'explosion est, en stockant par exemple son rayon actuel; la valeur de cet élément sera incrémenté à chaque frame, et lorsqu'il sera devenu égal au rayon du plus grand cercle, l'explosion sera supprimée de la liste.


for ennemi in liste_ennemis:
    """ Test des collisions avec les tirs"""
    for tir in liste_tirs:
        x = tir[0]
        y = tir[1]
        xe = ennemi[0]
        ye = ennemi[1]
        if y <= ye+8 and ( x >= xe and x <= xe + 8):
            liste_tirs.remove(tir)
            liste_ennemis.remove(ennemi)
            liste_explosions.append([xe+4, ye+4, 1]) # ajout d'une explosion à la liste ( rayon initial = 1 pixel )
            score = score + 1

    """Tests des collisions avec le vaisseau"""
    if vaisseau_x < ennemi[0] + 8 and vaisseau_x > ennemi[0] - 8 and vaisseau_y < ennemi[1] + 8 and vaisseau_y > ennemi[1] - 8:
        liste_ennemis.remove(ennemi)
        liste_explosions.append([xe+4, ye+4, 1]) 	# ajout d'une explosion à la liste
        vies = vies - 1
			

Écrire les fonctions bouge_explosion(explosion) et affiche_explosion(explosion), qui seront appelées respectivement depuis les fonctions update() et draw() pour gérer les explosions.

La fonction bouge_explosion() gérera également le cas où l'explosion a atteint son "maximum" et où il faut la supprimer de la liste.

Vous trouverez ici le code complet de cette première partie du tutoriel.

Suivant