# -*- encoding:utf-8 -*-

# Jeu d'agilité: Version 2

from tkinter import *
from random import *

class Application(Tk):
    """ Définition de l'application principale tkinter permettant
    d'interagir avec l'utilisateur. Cette application contient un
    Canevas et quelques boutons"""

    flag = 0        # variable d'état indiquant si la partie a commencé

    def __init__(self):
        """ Construction de l'interface graphique en précisant les
        dimensions du canevas"""
        
        Tk.__init__(self)               # appel au constructeur de la classe parente
        self.title("Jeu d'agilité")     # hérite de la méthode <title> de la classe parente

        # initialisation d'attributs d'instance configurant l'application:
        self.point = 0      # nombre de points gagnés
        self.clic = 0       # nombre de clics déjà réalisés
        self.essai = 15     # nombre d'essais restants
        
        # création du canevas dans l'application:
        self.can = Canvas(self, bg='dark grey',height=250, width=250)
        self.can.bind('<Button-1>', self.pointeur)
        self.can.grid(row = 1, column = 1, rowspan = 7, padx = 5, pady = 5)

        # création des boutons dans l'application:
        Button(self, text='Démarrer', width =8, command=self.start_it).grid(row = 1, column = 2)
        Button(self, text='Pause', width =8, command=self.stop_it).grid(row = 2, column = 2)
        Button(self,text='Quitter', width =8, command=self.terminate).grid(row = 3, column = 2)

        # création des boutons-radio:
        self.nbreBalles = IntVar()      # création de la variable tkinter
        self.nbreBalles.set(1)          # initialisation de la variable tkinter à 1 par défaut
        Label(self, text = 'Nombre de balles').grid(row = 4, column = 2)
        Radiobutton(self, text = '1', variable = self.nbreBalles, value = '1').grid(row = 5, column = 2)
        Radiobutton(self, text = '3', variable = self.nbreBalles, value = '3').grid(row = 6, column = 2)
        Radiobutton(self, text = '5', variable = self.nbreBalles, value = '5').grid(row = 7, column = 2)

        # création de l'étiquette de texte
        self.chaine = Label(self, text = "Ton score est de " + str(self.point) + "\n" + "Nombre d'essais restants: " + str(self.essai))
        self.chaine.grid(row = 8, columnspan = 2)

        # initialisation de la liste de balles situées dans le canevas
        self.balles = []

    def start_it(self):
        "Permet de lancer l'animation"
        if Application.flag == 0:           # lancement du jeu
            Application.flag = 1            # impossible de créer de nouvelles balles
            i = 1                           # création des balles
            while i <= self.nbreBalles.get():
                balle = Balle(self.can, x=randint(0,200), y=randint(0,200), rayon=15, dx=randint(-15, 15), dy=randint(-10, 10), color = Balle.coul[self.point%len(Balle.coul)])
                self.balles.append(balle)
                i += 1

        if Balle.flag == 0:             # animation des balles créées
            Balle.flag = 1
            for balle in self.balles:
                balle.move()

    def stop_it(self):
        "Permet de stopper l'animation"
        Balle.flag = 0

    def terminate(self):
        "Permet de fermer correctement l'application"
        self.quit()
        self.destroy()

    def pointeur(self, event):

        if Balle.flag > 0:
        
            if self.clic < self.essai:
                self.clic += 1
                x = event.x     # récupérer les coordonnées du point
                y = event.y     # sur lequel l'utilisateur à cliquer
                for balle in self.balles:
                    if balle.x-balle.rayon < x < balle.x + balle.rayon and balle.y-balle.rayon < y < balle.y + balle.rayon:
                        self.point += 1
                        balle.set_time(3*balle.time//4)
                        balle.set_radius(0.9*balle.rayon)
                        balle.set_color(Balle.coul[self.point%len(Balle.coul)])
                        self.chaine.configure(text = "Ton score est de " + str(self.point) + "\n" + "Nombre d'essais restants: " + str(self.essai-self.clic))
                    else:
                        self.chaine.configure(text = "Ton score est de " + str(self.point) + "\n" + "Nombre d'essais restants: " + str(self.essai-self.clic))

            else:
                self.chaine.configure(text = "TERMINE !! \n" + "Ton score est de " + str(self.point) + " point(s).")
                Balle.flag = 0     
        
        
class Balle(object):
    """Définition d'une balle animée dans un canevas"""

    coul =['red', 'blue', 'yellow', 'green', 'black']      # couleurs de la balle
    flag = 0    # variable d'état indiquant si les objets de cette classe sont en mouvemenet

    def __init__(self, can, x = 0, y = 0, rayon = 15, dx = 1, dy = 1, time = 100, color = None):
        self.can = can      # référence au canevas dans lequel la balle doit s'animer

        # attribut de position et de déplacement:
        self.x, self.y = x, y
        self.dx, self.dy = dx, dy

        # autres attributs d'instance:
        self.rayon = rayon
        self.time = time        # intervalle de temps entre chaque déplacement
        self.color = color
        self.canref = self.can.create_oval(self.x-self.rayon, self.y-self.rayon, self.x+self.rayon, self.y+self.rayon, width=2, fill=self.color)

    def move(self):
        "Déplacement de la balle selon les directions proposées par ses attributs de déplacement"

        self.x, self.y = self.x + self.dx, self.y + self.dy
        
        if self.x > 250-self.rayon:
            self.x, self.dx = 250-self.rayon, -self.dx
        if self.y > 250-self.rayon:
            self.y, self.dy = 250-self.rayon, -self.dy
        if self.x < 5:
            self.x, self.dx = 5, -self.dx
        if self.y < 5:
            self.y, self.dy = 5, -self.dy
        self.can.coords(self.canref, self.x-self.rayon, self.y-self.rayon, self.x + self.rayon, self.y+self.rayon)
        if Balle.flag > 0:
            self.can.after(self.time, self.move)

    # Définition de méthodes-modifieurs:
    """En POO, les attributs ne doivent pas être modifiés directement
    de l'extérieur mais à partir de méthode située dans l'interface.
    Cette démarche permet de protéger le code d'éventuelles erreurs."""

    def set_color(self, newColor):
        "Permet de changer la couleur de la balle"
        self.color = newColor
        self.can.itemconfigure(self.canref, fill = self.color)

    def set_time(self, newTime):
        "Permet de changer le temps de rafraichissement de la balle"
        self.time = newTime

    def set_radius(self, newRadius):
        "Permet de changer le rayon de la balle"
        self.rayon = newRadius

    
#========== Programme principal =============

app = Application()

# démarrage du réceptionnaire d'évènements (boucle principale) :
app.mainloop()
