Mini-Projets en POO
Vous avez terminé le TP "Champagne !" ?. Très bien ! Vous savez maintenant ( presque ) tout sur la POO...
Vous avez encore du temps ? Ok, voici deux autres projets possibles...
La fontaine colorée
Des balles colorées jaillissent du bas de la fenêtre avec une vitesse plus ou moins grande, décrivent ensuite une trajectoire parabolique avant de retomber au sol.
Sans entrer dans les explications, la grosse différence est que la composante verticale de la vitesse vy
doit évoluer au cours du temps, selon l'équation : vy = vy + 10*dt
, où dt
représente la durée entre deux positions successives d'une balle.
On peut prendre dt égale à la durée entre deux frames de la boucle d'animation; cette valeur est par défaut de 60 ms ( 60e-3
s ).
N'hésitez pas cependant à modifier ce paramètre pour rendre l'animation plus fluide.
La composante horizontale vx
ne change elle jamais ( pour les personnes concernées, vous verrez en SPC pourquoi, et aussi d'où sort le "10"...).
Compléter le code ci-dessous pour réaliser cette animation :
SOLUTION
Rebonds
Et un p'tit dernier pour la route : les classiques balles rebondissantes. Adaptez le code précédent pour créer cette animation :
Compléter le script ci-dessous pour réaliser cette animation.
Quelques conseils pour la gestion des rebonds
Un premier conseil : confiez la gestion des rebonds à une autre méthode ( testRebond()
par exemple... ) de la classe Balle
, méthode que vous appellerez à la suite des deux autres dans la boucle d'animation anim()
.
Cette méthode gérera aussi le cas où il faut réinitialiser les attributs de la balle ( lorsqu'elle sort sur les côtés de l'écran ).
Un rebond doit être déclenché au moment où une balle atteint le bas de la fenêtre; à ce moment les balles se déplaçant horizontalement de manière uniforme, c'est donc uniquement la valeur de vy
qu'il
faudra réinitialiser ( vx
elle ne change pas...).
Cette modification devra "inverser" le sens de déplacement, mais aussi tenir compte de l'amortissement; pour cela, vous pouvez simplement multiplier à ce moment la valeur de la vitesse verticale vy
de la balle lors de son "impact" au "sol" par un coefficient inférieur à 1 ( plus ce coefficient sera petit, plus le rebond sera "mou".).
SOLUTION
En conclusion...
J'ai bien travaillé...j'ai droit de jouer à ce petit jeu écrit en POO; utilisez la souris pour déplacer le vaisseau, et le clic gauche
pour abattre les ennemis. Vous n'avez que 5 vies !
from random import randint
import poorpyxel as pyxel
class Vaisseau:
def __init__(self, x, y):
self.x = x
self.y = y
def move(self):
"""déplacement avec les touches de direction"""
self.x, self.y = pyxel.mouse_x, pyxel.mouse_y
if pyxel.btn(pyxel.MOUSE_BUTTON_LEFT):
return self.x + 4, self.y - 2
return None
def draw(self):
pyxel.rect(self.x, self.y, 8, 8, 5)
class Tir:
def __init__(self, x, y):
self.x = x
self.y = y
self.alive = True
def is_alive(self):
return self.alive
def move(self):
if self.y > 0:
self.y = self.y - 2
else:
self.alive = False
def draw(self):
pyxel.rect(self.x, self.y, 1, 4, 10)
class Ennemi:
def __init__(self, x, y):
self.x = x
self.y = y
self.alive = True
def is_alive(self):
return self.alive
def move(self):
if self.y < 128:
self.y = self.y + 2
else:
self.alive = False
def draw(self):
pyxel.rect(self.x, self.y, 8, 8, 8)
class Explosion:
def __init__(self, x, y, r):
self.x = x
self.y = y
self.r = r
self.alive = True
def is_alive(self):
return self.alive
def move(self):
if self.r<5: # si le rayon de l'explosion ( 3ème élement ) n'a pas atteint 5 unités,
self.r = self.r + 1 # alors on augmente ce rayon,
else:
self.alive = False
def draw(self):
pyxel.circb(self.x, self.y, self.r, 8 + (self.r)%5)
class Jeu:
def __init__(self, h, l, titre):
pyxel.init(h, l)
self.vaisseau = Vaisseau(60, 60)
self.liste_tirs = []
self.liste_ennemis = []
self.liste_explosions = []
self.score = 0
self.vies = 5
# Lancement du jeu
pyxel.run(self.update, self.draw)
def update(self):
v = self.vaisseau.move()
if v is not None:
self.liste_tirs.append(Tir(v[0], v[1]))
if pyxel.frame_count % 30 == 0:
self.liste_ennemis.append(Ennemi(randint(0, 120), 0))
for ennemi in self.liste_ennemis:
ennemi.move()
if not ennemi.is_alive():
self.score -= 1
self.liste_ennemis.remove(ennemi)
for tir in self.liste_tirs:
tir.move()
if not tir.is_alive():
self.liste_tirs.remove(tir)
for ennemi in self.liste_ennemis:
for tir in self.liste_tirs:
xt = tir.x
yt = tir.y
xe = ennemi.x
ye = ennemi.y
if yt <= ye+8 and ( xt >= xe and xt <= xe + 8):
self.liste_tirs.remove(tir)
self.liste_ennemis.remove(ennemi)
self.liste_explosions.append(Explosion(xe+4, ye+4, 1)) # ajout d'une explosion à la liste
self.score = self.score + 1
for ennemi in self.liste_ennemis:
xv = self.vaisseau.x
yv = self.vaisseau.y
xe = ennemi.x
ye = ennemi.y
if xv <= xe + 8 and xv > xe - 8 and yv <= ye + 8 and yv > ye - 8:
self.liste_ennemis.remove(ennemi)
self.liste_explosions.append(Explosion(xe+4, ye+4, 1)) # ajout d'une explosion à la liste
self.vies = self.vies - 1
for explosion in self.liste_explosions:
explosion.move()
if not explosion.is_alive():
self.liste_explosions.remove(explosion)
def draw(self):
pyxel.cls(0)
if self.vies > 0:
self.vaisseau.draw()
for tir in self.liste_tirs:
tir.draw()
for ennemi in self.liste_ennemis:
ennemi.draw()
for explosion in self.liste_explosions:
explosion.draw()
pyxel.text(1, 1, str(self.score), 15)
pyxel.text(pyxel.width-5, 1, str(self.vies), 15)
else:
pyxel.text(pyxel.width//2-len('GAME OVER')*4//2, pyxel.height//2, 'GAME OVER', 15)
#pyxel.stop()
########################
# PROGRAMME PRINCIPAL #
########################
Jeu(128, 128, "Super Jeu")