Projet 0  : Découverte

Découverte de l'utilisation du module pgzrun

Pour ce projet, vous aurez au préalable :

  • installé le module pgzero dans Thonny

  • créé un dossier : projet0

  • ce dossier contient deux sous-dossiers (images et sounds) et un fichier projet0.py créé avec thonny

  • téléchargé le pack d'images [zip][1] qui contient des images pour notre projet que vous décompresserez.

Récupérez dans le pack d'images, l'image p3_front.png se trouvant dans le dossier alien3 du dossier player et mettez-là dans le dossier images de votre projet

Le programme de base

Le programme de base

Le programme suivant affiche notre alien dans une fenêtre de 800 x 600 pixels

Remarque :

Le code est commenté ( le texte se trouvant après un # est du commentaire)

1
import pgzrun # on importe le module pgzrun
2
3
WIDTH = 800 # variable qui définit la largeur de la fenêtre
4
HEIGHT = 600 # pour la hauteur de la fenêtre
5
alien = Actor('p3_front.png') # création de l'objet alien
6
alien.x = 100 # abscisse de la position de l'alien
7
alien.y = 56 # ordonnée de l'alien
8
9
def draw(): # fonction qui s'exécute 60 fois par seconde
10
    alien.draw() # on affiche l'alien
11
12
pgzrun.go() # exécution ( doit toujours se trouver en dernière ligne du programme ) 

RemarqueConstantes et variables globales

  • Il est d'usage d'écrire les constantes en majuscules et les variables en minuscule. Cependant, Python ne fera pas de différence entre les deux (dans certains langages, il existe un type de variables constantes).

    Remarquez que WIDTH et HEIGHT sont des noms reconnus par Pygame Zero, ce ne serait pas le cas de LARGEUR et HAUTEUR...

  • Les variables définies en dehors des fonctions sont dîtes globales. Leur utilisation doit être limitée mais dans les projets un peu complexes elles évitent de devoir passer ces valeurs en paramètre de chaque fonction. Un cas de figure fréquent est celui des constantes, qui par définition, n'ont pas à être modifiées par les fonctions !

Mouvement de l'alien

On va faire en sorte que l'alien se déplace dans la fenêtre en utilisant les flèches du clavier

Ajoutez cette fonction et terminez les commentaires

1
def mouvement_alien():
2
    if keyboard.left: # si on appuie sur la flêche gauche du clavier
3
        alien.x = alien.x - 5 # on recule de 5 pixels
4
    if keyboard.right:
5
        alien.x = alien.x + 5
6
    if keyboard.up:
7
        alien.y = alien.y - 5
8
    if keyboard.down:
9
        alien.y = alien.y + 5

Puis ajoutez la fonction update() qui comme son nom l'indique sert à mettre à jour les positions de l'alien

1
def update():
2
    mouvement_alien()

MéthodeNotre alien laisse des traces...

Pour éviter cela , il suffit d'effacer l'écran à chaque tour de la fonction draw()

Complétez la fonction draw()

1
def draw(): # fonction qui s'exécute 60 fois par seconde
2
    screen.clear() # on efface l'écran
3
    alien.draw() # on affiche l'alien

MéthodeNotre alien sort de l'écran...

Pour que l'alien ne puisse pas sortir de l'écran on va compléter la fonction mouvement_alien() en précisant que si on arrive sur un bord alors on ne peux pas le traverser.

Remarques :

Les coordonnées de l'alien (alien.x et alien.y ) sont celles du centre de l'image.

Les instructions alien.width et alien.height donnent accès aux dimensions de l'image.

donc :

  • Si alien.x est inférieur à alien.width/2 alors l'image est sur le bord gauche , il suffit alors de repositionner l'alien.x à alien.width/2 ( il ne bouge plus)

  • Si alien.x est supérieur à WIDTH - alien.width/2 alors l'image est sur le bord droit, il suffit alors de repositionner l'alien.x à WIDTH - alien.width/2 ( il ne bouge plus)

  • de même pour les bords supérieur et inférieur

Voilà le code à mettre dans la fonction mouvement_alien()

1
# ne pas sortir de la fenêtre
2
    if alien.x < alien.width/2:
3
        alien.x = alien.width/2
4
    if alien.x > WIDTH -  alien.width/2:
5
        alien.x = WIDTH -  alien.width/2
6
        
7
    if alien.y < alien.height/2:
8
        alien.y = alien.height/2
9
    if alien.y > HEIGHT -  alien.height/2:
10
        alien.y = HEIGHT -  alien.height/2

Ajoutons des gemmes à attraper

Méthodefaisons simple...

Dans le pack images récupérez une image de gemme, par exemple gemgreen.png et placez-là dans votre dossier images.

Nous allons faire en sorte que la gemme apparaisse depuis le bord supérieur de manière aléatoire et tombe vers le bas pour réapparaître depuis le bord supérieur dès qu'elle a franchit le bord inférieur.

En python, on utilise le module random pour pouvoir utiliser la méthode random.randint(a,b) qui permet de choisir aléatoirement un entier entre a et b.

Voici les lignes de codes à rajouter dans notre programme

1
import pgzrun # on importe le module pgzrun
2
import random # on importe le module random
3
1
alien.y = 56 # ordonnée de l'alien
2
3
gem = Actor('gemgreen.png') # création de l'objet gem
4
gem.x = random.randint(20,780) 
5
gem.y = 0
1
def mouvement_gemme(): # fonction pour le mouvement de gem
2
    gem.y = gem.y + 4
3
    if gem.y > 600: # si gem sort de l'écran
4
        gem.x = random.randint(20,780)
5
        gem.y = 0
1
def update():
2
    mouvement_alien() # mise à jour de alien
3
    mouvement_gemme() # mise à jour de gem
4
5
def draw(): # fonction qui s'exécute 60 fois par seconde
6
    screen.clear() # on efface l'écran
7
    alien.draw() # on affiche l'alien
8
    gem.draw() # on affiche la gemme

Gestion des collisions

Avec le module pgzrun, la gestion des collisions se fait avec la méthode :

  • if gem.colliderect(ship): ou if ship.colliderect(gem): (les deux ont le même effet)

Donc s'il y a collision, on fait repartir la gemme depuis une position aléatoire du bord supérieur.

Modifiez la fonction mouvement_gemme() comme suit :

1
def mouvement_gemme(): # fonction pour le mouvement de gem
2
    gem.y = gem.y + 4
3
    if gem.y > 600:
4
        gem.x = random.randint(20,780)
5
        gem.y = 0
6
    if gem.colliderect(alien): # collision
7
        gem.x = random.randint(20,780)
8
        gem.y = 0

Ajoutons un score et un Game Over

  • Dans un premier temps il faut créer une variable globale score et l'initialiser à 0

  • Puis on incrémente de 1 cette variable à chaque fois qu'une collision est détectée : score = score + 1

  • Et on affiche le score dans la fenêtre : screen.draw.text('Score: ' + str(score), (15,10), color=(255,255,255), fontsize=30) (à écrire dans la fonction draw() )

Cette dernière instruction dit : on affiche le texte score suivit du score aux coordonnées (15,10) en blanc avec une taille de police de 30/

L'instruction str(score) permet de transformer en chaîne de caractère le score .

Méthodeles variables score et game_over sont globales...

la variable score est définie en début de programme et est par ce fait globale, si on souhaite la modifier dans la fonction mouvement_gemme(), il faut le préciser, en rajoutant l'instruction global score dans cette fonction.

voici les modification à apporter à notre programme :

1
score = 0 # création de la variable score
2
3
def mouvement_gemme(): # fonction pour le mouvement de gem
4
    global score # on précise que score va être modifiée dans la fonction
5
    gem.y = gem.y + 4
6
    if gem.y > 600:
7
        gem.x = random.randint(20,780)
8
        gem.y = 0
9
    if gem.colliderect(alien): # collision
10
        gem.x = random.randint(20,780)
11
        gem.y = 0
12
        score = score + 1 # incrémentation du score
1
def draw(): # fonction qui s'exécute 60 fois par seconde
2
    screen.clear() # on efface l'écran
3
    alien.draw() # on affiche l'alien
4
    gem.draw() # on affiche la gemme
5
    screen.draw.text('Score: ' + str(score), (15,10), color=(255,255,255), fontsize=30) # affichage du score

Game Over....

On doit pouvoir perdre dans un jeu...

Disons que si on laisse passer une gemme alors on a perdu...

On commence par créer une variable game_over initialisée à False ( game_over est donc une variable booléenne globale qui ne peut avoir que deux valeur True ou False ).

Si on souhaite la modifier dans la fonction mouvement_gemme(), comme pour la variable score il faudra le préciser

L'idée est donc la suivante :

si game_over vaut False, le jeu continue sinon il s'arrête et on affiche GAME OVER et le score

Voici les modifications à apporter

1
score = 0
2
game_over = False
3
4
def mouvement_gemme(): # fonction pour le mouvement de gem
5
    global score,game_over
6
    gem.y = gem.y + 4
7
    if gem.y > 600:
8
        game_over = True
9
    if gem.colliderect(alien): # collision
10
        gem.x = random.randint(20,780)
11
        gem.y = 0
12
        score = score + 1
1
def draw(): # fonction qui s'exécute 60 fois par seconde
2
    screen.clear() # on efface l'écran
3
    if game_over == False:
4
        alien.draw() # on affiche l'alien
5
        gem.draw() # on affiche la gemme
6
        screen.draw.text('Score: ' + str(score), (15,10), color=(255,255,255), fontsize=30)
7
    else:
8
        screen.draw.text('Game Over', (360, 300), color=(255,255,255), fontsize=60)
9
        screen.draw.text('Final Score: ' + str(score), (360, 350), color=(255,255,255), fontsize=60)
ComplémentAjoutons un sons lors des collisions

Dans le dossier sounds ajouter le son contenu dans ce fichier [zip]que vous aurez au préalable téléchargé de décompressé

puis modifiez le programme comme suit :

1
def mouvement_gemme(): # fonction pour le mouvement de gem
2
    global score,game_over
3
    gem.y = gem.y + 4
4
    if gem.y > 600:
5
        game_over = True
6
    if gem.colliderect(alien): # collision
7
        gem.x = random.randint(20,780)
8
        gem.y = 0
9
        score = score + 1
10
        sounds.boing.play() # jouer le son

Vous trouverez sur internet des sons gratuit et libre de droit( par exemple lesanotheque.org )

Notez que l'on peut charger des sons au format .wav et .ogg

  • Le format .wav est adapté aux petit effet sonores

  • Le format .ogg est un format compressé qui convient mieux à de la musique

De plus si notre son se nomme boing :

  • sounds.boing.play() : joue le son

  • sounds.boing.play(n) : joue le son n fois

  • sounds.boing.play(-1) : joue le son indéfiniment

  • sounds.boing.stop() : stoppe le son

ComplémentRendre le jeu plus difficile...

On peut modifier la vitesse des gemmes en fonction du score, en remplaçant

  • gem.y = gem.y + 4

par

  • gem.y = gem.y + 4 + score / 5

ComplémentEt....
  • On peut ajouter d'autres gemmes de couleurs différentes qui rapporte plus de points

  • On peut créer un système de vie ( le joueur à au début 5 vies...)

  • Laissez libre cours à votre imagination