Favicon
NSI Terminale

Connexion élèves

Choisir le(s) module(s) à installer :

Correction : introduction à la POO

Une "bulle" qui monte...


import poorpyxel as ppx
from random import randint

ppx.init(150, 150)

def update():
    global x, y, vitesse
    # Déplacement de la bulle vers le haut en tenant compte de sa vitesse;
    # Quand la bulle arrive en haut de la fenêtre, on réinitialise ses caractéristiques.
    y = y - vitesse
    if y < 0:
        y = ppx.height
    
def draw():	
	# 1. Effacement global de la fenêtre :   
	ppx.cls(0)
	
	# 2. Dessin de la bulle dans la fenêtre :
	ppx.circ(x, y, rayon, couleur)
	
# initialisation des caractéristiques de la bulle
x = randint(10, 140)
y = ppx.height
couleur = randint(1, 15)
rayon = randint(2 ,5)
vitesse = randint(2, 10)	

ppx.run(update, draw)			
			

Deux choses pour gérer le mouvement de la bulle :

  1. à chaque "tour" de la boucle d'animation (= à chaque appel de la fonction update ), modifier l'ordonnée y de la bulle pour faire "monter" cette dernière : il faut donc décrémenter la variable y ( ligne 11 ).
  2. tester ( ligne 12 ) siy < 0, c'est à dire si la bulle "sort" de l'écran par le haut, et, dans ce cas, réinitialiser les caractéristiques la bulle.

Une remarque sur la condition à tester pour "savoir" si la bulle atteint le sommet : on ne peut pas utiliser une simple égalité, car, selon la valeur de la variable vitesse, la variable y n'obtiendra peut-être jamais la valeur 0; il faut donc tester une inégalité qui, elle, sera forcément vérifiée à un moment ou un autre, quelle que soit la valeur de vitesse.

Deux bulles...

Facile : on recopie les variables et les instructions pour gérer le mouvement de la bulle, et on les réutilise avec de nouveaux noms :


import poorpyxel as ppx
from random import randint

ppx.init(150, 150)

def update():
    global x, y, vitesse, x2, y2, vitesse2
    
    y = y - vitesse
    if y < 0:
        y = ppx.height
        
    y2 = y2 - vitesse2
    if y2 < 0:
        y2 = ppx.height
    
def draw():	
	ppx.cls(0)
	
	ppx.circ(x, y, rayon, couleur)
	ppx.circ(x2, y2, rayon2, couleur2)
	
# 1ère bulle
x = randint(10, 140)
y = ppx.height
couleur = randint(1, 15)
rayon = randint(2 ,5)
vitesse = randint(2, 10)

# 2ème bulle
x2 = randint(10, 140)
y2 = ppx.height
couleur2 = randint(1, 15)
rayon2 = randint(2 ,5)
vitesse2 = randint(2, 10)	

ppx.run(update, draw)
			
			

Trois, quatre,... bulles...

Argh....

Cette façon d'envisager le programme devient de plus en plus délicate à gérer :

  • le code devient parfaitement illisible.
  • on fait X fois pratiquement la même chose, X étant le nombre de bulles : le code est lourd, pas optimisé,
  • si on veut modifier par exemple l'intervalle dans lequel la taille d'une bulle doit se trouver, il faut le faire X fois dans le code pour chacune des bulles ! Le code n'est donc pas maintenable, donc pas fiable car entraînant une grande probabilité d'erreur, surtout si quelqu'un d'autre prenait votre relève et essayait de le développer ( bonne chance alors ! )

D'où la nécessité de passer, dans cette situation, à une autre façon de concevoir le programme, un autre paradigme de programmation, la Programmation Orientée Objet ( POO ).

Le "moule" : la classe Bulle


class Bulle:
    
	# constructeur
	def __init__(self,x, y, couleur, taille, vitesse):
		self.x = x
		self.y = y
		self.couleur = couleur
		self.rayon = rayon
		self.vitesse = vitesse

	def afficher(self):
		ppx.circ(self.x, self.y, self.taille, self.couleur)
        
	def monter(self):
	    self.y = self.y - self.vitesse	
			

Pour chaque méthode ou attribut d'un objet, il faut préfixer son nom par self.

Création d'un objet à partir d'une classe


import poorpyxel as ppx
from random import randint
...

class Bulle:
	...
	

def update():
	bulle.monter()
	
def draw():
    ppx.cls(0) # effacement de l'écran
    bulle.afficher() # affichage de la bulle
  
# instanciation d'un objet de type "Bulle"
x = randint(0, ppx.width)
y = ppx.height
couleur = randint(0, 15) 
rayon = randint(2, 10)
vitesse = randint(2, 10)
bulle = Bulle(x, y, couleur, rayon, vitesse) # arguments dans le même ordre que les paramètres du constructeur

ppx.run(update, draw)
			

Des objets dans une liste ??

Dans le programme principal, on crée une liste dont chaque élément sera un objet :

  
bulles = [] # tableau d'objets de type 'Bulle'

for i in range(50): # 50 bulles
    x = randint(0, ppx.width)
    y = ppx.height
    couleur = randint(1, 15) 
    rayon = randint(2, 5)
    vitesse = randint(2, 5)
    bulle = Bulle(x, y, couleur, rayon, vitesse)
    bulles.append(bulle)		
			

( on peut bien entendu créer le tableau bulles par compréhension.)

Dans les fonctions update et draw, on parcourt alors le tableau de ces objets, en appelant, pour chacun de ces éléments ( qui sont des objets de type Bulle ) leurs méthodes monter ou afficher :


def update():
    for bulle in bulles: # parcours par valeur du tableau des bulles
        bulle.monter()
        if bulle.y < 0: # si la bulle arrive en haut de l'écran,
            bulle.y = ppx.height # on réinitialise tous ses paramètres !
            bulle.x = randint(0, ppx.width)
            bulle.couleur = randint(1, 15)
            bulle.taille = randint(2, 5)
            bulle.vitesse = randint(2, 5)
        
def draw():
	ppx.cls(0)
	for bulle in bulles: 
		bulle.afficher()	
			

Le code complet du script est ici.

Les balles rebondissantes

La méthode importante est la méthode rebonds : elle prend comme paramètre un autre objet de type Balle :


class Balle:
	
	....
				
	def rebonds(self, autre_balle): # le constructeur prend comme paramètre un AUTRE objet de type 'Balle'
		dx = autre_balle.x - self.x
		dy = autre_balle.y - self.y
		distance = sqrt(dx**2 + dy**2)
		minDist = autre_balle.taille + self.taille
	
		if (distance < minDist):
			self.vx = -self.vx
			self.vy = -self.vy
			autre_balle.vx = -autre_balle.vx
			autre_balle.vy = -autre_balle.vy				
			

Et cette méthode doit être appelée dans la fonction update ( pour une seule des balles ) :


def update():
    # déplacement des balles
    balle1.move() 
    balle2.move()
    
    # gestion du rebond éventuel l'une sur l'autre
    balle1.rebonds(balle2)		
			

Le code complet du script est ici.

La fontaine colorée

Le code complet du script est ici.

Rebonds

Le code complet du script est ici.