Aller au contenu

Décompte de victoire

On va mettre en place un compte à rebours jusqu'à la victoire du joueur.

Simulation

Dans la simulation, on va rajouter un attribut decompte_victoire. La valeur initiale de la durée avant une victoire (en secondes) sera pour le moment sous forme d'une constante.

DECOMPTE_VICTOIRE = 5.0
class Simulation:

    def __init__(self, personnage):
        self.personnage = personnage
        self.projectiles = [
            Projectile(Vector2(200, 300), Vector2(1.0, 1.0)),
            Projectile(Vector2(400, 120), Vector2(1.0, 0)),
            Projectile(Vector2(800, 600), Vector2(-1.1, -0.3)),
            Projectile(Vector2(200, 600), Vector2(0.2, -0.1)),
        ]
        self.collision = False
        self.decompte_victoire = DECOMPTE_VICTOIRE

On écrit maintenant une fonction de simulation responsable du décompte. Si le temps restant devient négatif, on le bloque à zéro.

def decompter_victoire(etat, t):
    etat.simulation.decompte_victoire -= t
    if etat.simulation.decompte_victoire < 0:
        etat.simulation.decompte_victoire = 0.0

On l'ajoute à la simulation.

def avancer_simulation(etat, t):
    deplacer_personnage(etat, t)
    limiter_deplacement_personnage(etat)
    deplacer_projectiles(etat, t)
    faire_rebondir_projectiles(etat)
    detecter_collisions(etat)
    decompter_victoire(etat, t) 

Boucle principale

Dans la boucle principale, on rajoute une condition pour arrêter la simulation, et on affiche le message de victoire ou de défaite.

while not etat.controles.quitter:

    if etat.controles.recommencer:
        reinitialiser_controles(etat)
        reinitialiser_simulation(etat)
        reinitialiser_rendu(etat)

    t = clock.tick(FPS)/1000

    traiter_controles(etat, t)

    if etat.simulation.collision:
        print("Défaite !")
    elif etat.simulation.decompte_victoire == 0.0:
        print("Victoire !")
    else:
        avancer_simulation(etat, t)

    afficher_rendu(etat, t)

Si on execute le jeu, et qu'on arrive à survivre assez longtemps, on pourra voir la victoire s'afficher en console. Au contraire, si on a une collision avant, on verra la défaite.

Le code complet de l'étape se trouve dans le dépliant ci-dessous :

Code Complet
import pygame
from pygame.math import Vector2

####################
####   CONFIG   ####
####################

## Général 

FPS = 60

LARGEUR_FENETRE = 1280
HAUTEUR_FENETRE = 720

## Controles

TOUCHE_QUITTER = pygame.K_ESCAPE
TOUCHE_HAUT = pygame.K_UP  
TOUCHE_BAS = pygame.K_DOWN 
TOUCHE_DROITE = pygame.K_RIGHT 
TOUCHE_GAUCHE = pygame.K_LEFT
TOUCHE_RECOMMENCER = pygame.K_r

## Simulation

VITESSE_PERSONNAGE = 300
TAILLE_PERSONNAGE = 10
TAILLE_PROJECTILES = 10
VITESSE_PROJECTILES = 200
DECOMPTE_VICTOIRE = 5.0

## Rendu

COULEUR_ARRIERE_PLAN = (0, 0, 0)
COULEUR_PERSONNAGE = (255, 146, 205)
COULEUR_PROJECTILES = (146, 255, 205)

####################
####  GENERAL   ####
####################

class GameState :

    def __init__(self):
        self.controles = None # on met a None parce que ces attributs seront initialisés plus tard
        self.simulation = None
        self.rendu = None

####################
#### CONTROLEUR ####
####################

class Controles :
    def __init__(self):
        self.quitter = False
        self.direction = Vector2(0,0)
        self.recommencer = False

def initialiser_controles(etat):
    etat.controles = Controles()

def reinitialiser_controles(etat):
    etat.controles = Controles()

def traiter_controles(etat, t):

    for e in pygame.event.get():
            if e.type == pygame.KEYDOWN: 
                if e.key == TOUCHE_QUITTER:
                    etat.controles.quitter = True
                if e.key == TOUCHE_RECOMMENCER:
                    etat.controles.recommencer = True

    direction = Vector2(0, 0)

    clavier = pygame.key.get_pressed()
    if clavier[TOUCHE_HAUT]:
        direction.y += 1.0
    if clavier[TOUCHE_BAS]:
        direction.y -= 1.0
    if clavier[TOUCHE_DROITE]:
        direction.x += 1.0
    if clavier[TOUCHE_GAUCHE]:
        direction.x -= 1.0

    if direction.length() != 0:
        direction.normalize_ip()

    etat.controles.direction = direction

####################
#### SIMULATION ####
####################

class Personnage:

    def __init__(self, position):
        self.position = position

class Projectile:

    def __init__(self, position, direction):
        self.position = position
        self.direction = direction
        if self.direction.length != 0:
            self.direction.normalize_ip()

class Simulation:

    def __init__(self, personnage):
        self.personnage = personnage
        self.projectiles = [
            Projectile(Vector2(200, 300), Vector2(1.0, 1.0)),
            Projectile(Vector2(400, 120), Vector2(1.0, 0)),
            Projectile(Vector2(800, 600), Vector2(-1.1, -0.3)),
            Projectile(Vector2(200, 600), Vector2(0.2, -0.1)),
        ]
        self.collision = False
        self.decompte_victoire = DECOMPTE_VICTOIRE


def initialiser_simulation(etat):
    pos = Vector2(LARGEUR_FENETRE/2, HAUTEUR_FENETRE/2)
    p = Personnage(pos)
    etat.simulation = Simulation(p)

def reinitialiser_simulation(etat):
    initialiser_simulation(etat)

def intersection(c1, r1, c2, r2):
    return c1.distance_to(c2) <= r1 + r2

def detecter_collisions(etat):
    perso = etat.simulation.personnage
    for p in etat.simulation.projectiles:
        if intersection(perso.position, TAILLE_PERSONNAGE, p.position, TAILLE_PROJECTILES):
            etat.simulation.collision = True

def deplacer_personnage(etat, t):
    direction = etat.controles.direction
    etat.simulation.personnage.position += direction * VITESSE_PERSONNAGE * t

def limiter_deplacement_personnage(etat):
    p = etat.simulation.personnage
    if p.position.x < TAILLE_PERSONNAGE:
        p.position.x = TAILLE_PERSONNAGE
    if p.position.x > LARGEUR_FENETRE - TAILLE_PERSONNAGE:
        p.position.x = LARGEUR_FENETRE - TAILLE_PERSONNAGE
    if p.position.y < TAILLE_PERSONNAGE:
        p.position.y = TAILLE_PERSONNAGE
    if p.position.y > HAUTEUR_FENETRE - TAILLE_PERSONNAGE:
        p.position.y = HAUTEUR_FENETRE - TAILLE_PERSONNAGE

def deplacer_projectiles(etat, t):
    for p in etat.simulation.projectiles:
        p.position += p.direction * VITESSE_PROJECTILES * t

def faire_rebondir_projectiles(etat):
    for p in etat.simulation.projectiles:
        if p.position.x < TAILLE_PROJECTILES:
            p.position.x = TAILLE_PROJECTILES
            p.direction.x *= -1
        if p.position.x > LARGEUR_FENETRE - TAILLE_PROJECTILES:
            p.position.x = LARGEUR_FENETRE - TAILLE_PROJECTILES
            p.direction.x *= -1
        if p.position.y < TAILLE_PROJECTILES:
            p.position.y = TAILLE_PROJECTILES
            p.direction.y *= -1
        if p.position.y > HAUTEUR_FENETRE - TAILLE_PROJECTILES:
            p.position.y = HAUTEUR_FENETRE - TAILLE_PROJECTILES
            p.direction.y *= -1

def decompter_victoire(etat, t):
    etat.simulation.decompte_victoire -= t
    if etat.simulation.decompte_victoire < 0:
        etat.simulation.decompte_victoire = 0.0

def avancer_simulation(etat, t):
    deplacer_personnage(etat, t)
    limiter_deplacement_personnage(etat)
    deplacer_projectiles(etat, t)
    faire_rebondir_projectiles(etat)
    detecter_collisions(etat)
    decompter_victoire(etat, t) 

####################
####   RENDU    ####
####################

class Rendu:
    def __init__(self, ecran):
        self.ecran = ecran

def ref_sve(v):
    return Vector2(v.x, HAUTEUR_FENETRE - v.y)

def initialiser_rendu(etat, ecran):
    etat.rendu = Rendu(ecran)

def reinitialiser_rendu(etat):
    ecran = etat.rendu.ecran
    etat.rendu = Rendu(ecran)

def rendre_personnage(etat):
    ecran = etat.rendu.ecran
    position = etat.simulation.personnage.position
    pygame.draw.circle(ecran, COULEUR_PERSONNAGE, ref_sve(position), TAILLE_PERSONNAGE)

def rendre_projectiles(etat):
    ecran = etat.rendu.ecran
    for p in etat.simulation.projectiles:
        position = p.position
        pygame.draw.circle(ecran, COULEUR_PROJECTILES, ref_sve(position), TAILLE_PROJECTILES)

def afficher_rendu(etat, t):
    ecran = etat.rendu.ecran
    ecran.fill(COULEUR_ARRIERE_PLAN)

    rendre_projectiles(etat)

    rendre_personnage(etat)

    pygame.display.flip() 

####################
####    MAIN    ####
####################

def main():

    pygame.init()

    etat = GameState()

    fenetre = pygame.display.set_mode([LARGEUR_FENETRE, HAUTEUR_FENETRE])

    initialiser_controles(etat)
    initialiser_simulation(etat)
    initialiser_rendu(etat, fenetre)

    clock = pygame.time.Clock()

    while not etat.controles.quitter:

        if etat.controles.recommencer:
            reinitialiser_controles(etat)
            reinitialiser_simulation(etat)
            reinitialiser_rendu(etat)

        t = clock.tick(FPS)/1000

        traiter_controles(etat, t)

        if etat.simulation.collision:
            print("Défaite !")
        elif etat.simulation.decompte_victoire == 0.0:
            print("Victoire !")
        else:
            avancer_simulation(etat, t)

        afficher_rendu(etat, t)

    pygame.quit()

if __name__ == "__main__":
    main()