Bonsoir à tous!
Voilà je suis en terminal S et je fais ISN. Notre projet (un labyrinthe plongé dans la quasi obscurité en 2D vue de haut) est à rendre pour très bientôt. D'ailleurs on l'a quasi terminé^^ mais il nous manque deux choses importantes (je vous conseille de lancer le code en supprimant les lignes 480 et 481 car vous n'avez l'image en question pour vous rendre compte de la chose). Les piège jaunes cause un défaite. Les pièges noir cause un retour du joueur à ses coordonnées initiales et les bonus rouge agrandissent le périmètre de vision du personnage pour une certaine durée(durée encore non codée et déterminée). Sauf que pour que le joueur n'abuse pas de ce bonus(en restant dessus ou en passant plusieurs fois dessus), il faut le supprimer. Et lorsque dans la fonction avance je dit que si le joueur entre en collision avec le bonus, ça retire le tuple correspondant à ce bonus de la liste coordonnees_bonus... Et à vrai on est totalement largué... Surtout que le projet est à rendre dans moins d'une semaine. Quand on aura réglé ce problème faudra aussi que crée un compte à rebours (là aussi je sens que va y avoir des problèmes).


Merci d'avance pour votre aide qui ne pourra que nous faire avancer

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
#!/usr/bin/env python3
# -*- coding: utf-8 -*- 
#les deux lignes précédentes permettent de faire fonctionner le programme sur n'importe quel ordis
from tkinter import* #on importe le module tkinter
from math import*#on importe le module math
                                                                      ################################
                                                                      ################################
                                                                      #### FONCTIONS DU PROGRAMME ####
                                                                      ################################
                                                                      ################################
 
 
def command_button_1_for_defaite():
    #Cette fonction définie la commande pour le boutton "oui" de fenetre_defaite. Ainsi en cliquant sur "oui", on ferme la fenêtre de dialogue et le joueur reprend ses coordonnées initiales
 
    fenetre_defaite.destroy()#appliqué à une fenêtre, la méthode destroy() permet de fermer cette dernière.
    joueur['x'], joueur['y'] = x_joueur_initial, y_joueur_initial
 
def command_button_1_for_victoire():
    fenetre_victoire.destroy()
    joueur['x'], joueur['y'] = x_joueur_initial, y_joueur_initial
 
def command_button_2():
    #Cette fonction définie la commande pour le boutton "non" de fenetre_defaite. Ainsi en cliquant sur "non", on ferme la fenêtre de jeu (fen) ce qui ferme aussi la fenêtre défaite
    fenetre_game.destroy()
 
def apparition_fenetre_defaite():
    #Cette fonction est appelée lorsque le joueur entre en collision avec un piege_2. Elle fait apparaître une fenêtre avec un message indiquant la défaite et proposant de recommencer ou de quitter le jeu
 
    global fenetre_defaite
 
    fenetre_defaite = Toplevel()#la fenetre de type Toplevel est comparable à une fenêtre pop-up qui va bloquer les actions sur les fenêtre en arrière plan. 
    fenetre_defaite.grab_set
    #on définie ici les dimensions de cette fenetre et son cadrage au centre de l'écran. 
    width_fenetre_defaite = 400
    height_fenetre_defaite = 100
    position_x_fenetre_defaite = (width_screen-width_fenetre_defaite)/2
    position_y_fenetre_defaite = (height_screen-hauteur_barre_menu-height_fenetre_defaite)/2
    fenetre_defaite.geometry('%dx%d+%d+%d' %(width_fenetre_defaite, height_fenetre_defaite, position_x_fenetre_defaite, position_y_fenetre_defaite))
 
    text_defaite = Label(fenetre_defaite, text = "Vous avez perdu!! Voulez-vous recommencer?")#on insère le texte caractéristique d'une défaite dans fenetre_defaite.
    text_defaite.pack(side = TOP)
 
    #on définie ici les bouttons de la fenetre_defaite et leurs actions respectives(actions décrites par les fonctions précisées plus haut)
    BUTTON_1 = Button(fenetre_defaite, text="Oui", command=command_button_1_for_defaite)
    BUTTON_1.pack(side = BOTTOM)
    BUTTON_2 = Button(fenetre_defaite, text="Non", command=command_button_2)
    BUTTON_2.pack(side = BOTTOM)
 
    fenetre_defaite.focus_set()#designe la fenêtre qui a le focus
    fenetre_defaite.mainloop()
 
def apparition_fenetre_victoire():
 
    global fenetre_victoire
    fenetre_victoire = Toplevel()
    fenetre_victoire.grab_set()
 
    #on définie ici les dimensions de cette fenetre et son cadrage au centre de l'écran. 
    width_fenetre_victoire = 420
    height_fenetre_victoire = 100
    position_x_fenetre_victoire = (width_screen-width_fenetre_victoire)/2
    position_y_fenetre_victoire = (height_screen-hauteur_barre_menu-height_fenetre_victoire)/2
    fenetre_victoire.geometry('%dx%d+%d+%d' %(width_fenetre_victoire, height_fenetre_victoire, position_x_fenetre_victoire, position_y_fenetre_victoire))
 
    text_victoire = Label(fenetre_victoire, text="Bravo! Vous avez trouvé la sortie du labyrinthe! Voulez-vous recommencer?")
    text_victoire.pack()
 
    #on définie ici les bouttons de la fenetre_defaite et leurs actions respectives(actions décrites par les fonctions précisées plus haut)
    BUTTON_1 = Button(fenetre_victoire, text="Oui", command=command_button_1_for_victoire)
    BUTTON_1.pack(side = BOTTOM)
    BUTTON_2 = Button(fenetre_victoire, text="Non", command=command_button_2)
    BUTTON_2.pack(side = BOTTOM)
 
def collision(entite_1, entite_2): #la fonction collision vérifie la collision qu'entre 2 entités que l'on spécifira plus bas dans le programme (entite_1 et entite_2
                                    #sont des paramètres comparables à hb et gd de la fonction avance)
 
    #Vérifie s'il y a une collision entre 2 entités.
 
    if entite_1['x'] >= entite_2['x'] + entite_2['longueur'] or \
        entite_1['x'] + entite_1['longueur'] <= entite_2['x'] or \
        entite_1['y'] >= entite_2['y'] + entite_2['hauteur'] or \
        entite_1['y'] + entite_1['hauteur'] <= entite_2['y']:
        return False #pour tous les domaines de coordonnées décrits dans le if: la collision est fausse et la fonction retourne un False
    return True #pour le reste des coordonnées, la collision est vrai (la fonction retourne alors True)
 
 
def avance(gd,hb):   #en paramètre: gd=deplacement sur l'axe des abscisses , et hb= deplacmeent sur l'axe des ordonnées
 
        joueur = acteurs['joueur']#ici on dit que les coordonnées du joueur coorespondent au x, y, longueur, hauteur compilés dans le dictionnaire acteurs['joueur']
        x1, y1 = joueur['x'], joueur['y']
 
        joueur['x'], joueur['y']= x1 + gd, y1 + hb #on définit les déplacements horizontaux et verticaux du joueur
 
 
 
        # On vérifie pour chaque obstacle si le joueur entre en collision
        for obstacle in acteurs['obstacles']:#ici on dit que obstacle correspond à chaque tuple contenu dans une liste acteurs['obstacles']>>ces tuples contenant les coordonnées 
                                             #x, y, longueur, hauteur des murs du labyrinthe
 
            if collision (acteurs['joueur'], obstacle) == True: #on remplace respectivement entite_1 et entite_2 par acteurs['joueur'] et obstacle
                joueur['x'], joueur['y'] = x1, y1#on décrit ici le comportement du perso à la rencontre avec un mur: ses coordonnées x et y ne changent pas 
                # Puisqu'on trouve une collision, on revient à notre position précédente>>donc en fait on fait du surplace
                break #et puisque l'on a trouvé une collision, on peut cesser d'en chercher d'autre.      
 
        # On vérifie pour chaque piege_1 si le joueur entre en collision
        for piege_type_1 in acteurs['piege_1']:#ici on dit que piege_type_1 correspond à chaque tuple contenu dans une liste acteurs['piege_1']>>ces tuples contenant les coordonnées 
                                               #x, y, longueur, hauteur des piege_tryagain
 
            if collision (acteurs['joueur'], piege_type_1)==True:
                joueur['x'], joueur['y'] = x_joueur_initial, y_joueur_initial#on décrit ici le comportement du perso à la rencontre avec un mur: ses coordonnées x et y ne changent pas 
                # Puisqu'on trouve une collision entre le joueur et un piege_1, on revient à notre position de départ ( de coordonnées x_initial, y_initial globalisée dans le programme principal)
                break#et puisque l'on a trouvé une collision, on peut cesser d'en chercher d'autre.
 
        for piege_type_2 in acteurs['piege_2']:#ici on dit que piege_type_2 correspond à chaque tuple contenu dans une liste acteurs['piege_2']>>ces tuples contenant les coordonnées 
                                               #x, y, longueur, hauteur des piege_gameover          
          if collision (acteurs['joueur'], piege_type_2) == True:
              apparition_fenetre_defaite()#on décrit la conséquence d'une collision entre le joueur et un piege_2: la fonction apparition_fenetre_defaite() se réalise
              break#et puisque l'on a trouvé une collision, on peut cesser d'en chercher d'autre.
 
        for sphere_bonus in acteurs['Bonus']:#ici on dit que sphere_bonus correspond à chaque tuple contenu dans une liste acteurs['bonus']>>ces tuples contenant les coordonnées 
                                               #x, y, longueur, hauteur des no_zonesombres
 
          if collision (acteurs['joueur'], sphere_bonus) == False:
              polygons = creer_zones_ombre(joueur['x'] + joueur['longueur']/2, joueur['y'] + joueur['hauteur']/2, RAYON_normal, width_screen, height_screen)
              #si il n'y a pas de collision entre le joueur et le bonus, le rayon du "cercle de lumière" prend la valeur de RAYON_normal défini dans le programme principal.
          else:
              #si il y a collision entre le joueur et le bonus, le rayon du "cercle de lumière" prend la valeur de RAYON_anormal défini dans le programme principal.
              polygons = creer_zones_ombre(joueur['x'] + joueur['longueur']/2, joueur['y'] + joueur['hauteur']/2, RAYON_anormal, width_screen, height_screen)
 
              break#et puisque l'on a trouvé une collision, on peut cesser d'en chercher d'autre.
 
        world.coords(joueur['identifiant'], joueur['x'], joueur['y'], joueur['x'] + joueur['longueur'], joueur['y'] + joueur['hauteur'])#ceci est nécessaire pour changer les coordonnées d'un objet.
                                                                                                                                        #Pour modifier les coordonnées d'un élément dans le canvas, on dit:
                                                                                                                                        #world.coords(élément, x0, y0, x1, y1
        if joueur['y'] <= 0:
          apparition_fenetre_victoire()
 
 
 
        for zone_ombre, polygon in zip (acteurs['zonesombre'], polygons):#on ne peut pas écrire "for zone_ombre and polygon in (acteurs['zonesombre'], polygons)" car le and n'est pas autorisé dans la description d'une boucle for
                                                                         #Zip permet de remplacer ce and. 
 
            world.coords(zone_ombre['identifiant'], *decomposition(polygon))#je met à jour les coordonnées des zones d'ombres pour qu'elles puissent bouger.
 
            ###########
            #ATTENTION# : worlds.coords n'accepte que des arguments les un derrière les autres(donc pas de tuples ou de liste dans world.coords>>or polygon contient des tuples). Or notre fontion decomposition(coords)
            ########### se charge ici de séparer les arguments x,y contenu dans polygon... sauf qu'elle les compile dans une liste (result)>et world.coords ne gère pas non plus les liste!
            ########### Pour se débarasser de la liste et ne garder que les arguments x et y, on ajoute une * avant le decomposition(coords)
 
 
#Après avoir défnit l'action de déplacement, les quatres fonctions ci-dessous définissent le changement de coordonnées pour chaque orientation de déplacement (haut, bas, droite et gauche)
 
def depl_gauche():
    avance(-10,0)
 
def depl_droite():
    avance(10,0)
 
def depl_bas():
    avance(0,10)
 
def depl_haut():
    avance(0,-10)
 
 
 
def clavier (event):
    if joueur['y']>=0:
 
        touche = event.keysym #on dit au programme qu'on va utiliser les touches du clavier dans le jeu
 
        #Cette fonction assigne des touches à des actions de délacement. On fait correspondre chaque touche à aux fonctions de déplacement définies précédement
 
        #on assigne à chaque déplacement une ou des touche(s) spécifique(s)
        if touche in ("Up", "z"):
            depl_haut()
        elif touche in ("Down", 's'):
            depl_bas()
        elif touche in ("Right", 'd'):
            depl_droite()
        elif touche in ("Left", 'q'):
            depl_gauche()
 
 
def create_obstacle():
 
    #Cette fonction dessine les murs du labyrinthe sur la canvas (ce sont des rectangle rouge)
 
    obstacles = acteurs['obstacles'] = [] # Une liste qui contiendra des dictionnaires (contenant les coordonnées de mur)
 
    # Liste des coordonnées de mur dans l'ordre x, y, longueur, hauteur 
    coordonnees = [(15,1005,10000,1000),(99,995,10000,10000),(0,0,15,10000),(0,0,1815,15),(1905,0,15,10000),(99,902,561,19),(0,868,46,23),(99,794,561,21),
                   (645,815,15,87),(454,815,112,37),(403,891,13,14),(191,864,146,41),(99,344,20,190),(99,625,20,169),(70,227,125,24),(15,322,104,22),(180,552,20,166),
                   (180,696,188,22),(344,480,25,238),(174,247,21,251),(174,480,181,24),(0,130,428,23),(145,86,29,44),(145,0,29,34),(403,130,25,144), (191,371,175,22),
                   (236,426,114,15),(342,325,24,68),(366,325,230,38),(596,65,32,266), (437,363,159,54),(417,458,31,103),(431,541,181,20),(594,541,18,86),(438,610,174,17),
                   (438,627,26,88),(438,703,221,24),(479,632,135,61),(631,472,28,255),(513,472,146,22),(204,240,30,126),(305,240,30,126),(248,240,43,44),(234,290,71,22),
                   (234,350,71,16),(695,0,22,189),(717,75,48,86),(721,20,44,48),(817,0,33,26),(817,66,33,42),(817,66,87,25),(904,0,33,188),(817,155,33,85),(682,240,276,19),
                   (682,240,35,177),(596,325,86,92),(241,26,163,60),(596,325,86,92),(660,826,124,19),(784,794,25,128),(785,683,14,50),(785,729,173,14),(940,697,18,46),
                   (880,618,19,96),(785,683,79,17),(845,592,19,108),(880,618,19,96),(880,618,261,17), (942,552,52,66),(994,552,17,30),(942,513,16,48),(824,545,108,37),
                   (785,513,173,22),(785,513,22,96),(807,592,57,17),(1120,582,21,36),(1069,552,111,30),(1157,515,23,67),(880,697,78,17),(785,314,24,146),(822,360,98,55),
                   (785,314,173,20),(937,240,21,94),(682,240,35,85),(785,438,173,22),(937,383,21,77),(958,383,52,19),(1069,349,88,66),(1157,382,52,78),(785,794,392,16),
                   (1156,753,21,57),(1188,777,19,57),(1207,777,268,19),(1454,613,21,183),(1056,905,246,17),(1286,851,16,71),(995,977,86,19),(1383,922,101,18),(1462,940,22,56),
                   (785,905,173,17),(814,827,119,71),(939,819,19,103),(950,819,257,15),(1286,851,272,17),(1541,851,17,145),(1541,613,17,152),(1558,613,70,18),(1564,638,54,121),
                   (1625,613,17,383),(1069,334,88,81),(1021,729,65,14),(1071,680,15,63),(1157,240,20,94),(914,165,188,23),(1051,59,106,64),(1157,105,20,83),(1310,56,45,120),
                   (1355,66,28,100),(1300,188,14,102),(1314,278,114,12),(1314,188,114,13),(1416,188,12,102),(1324,211,20,58),(1354,211,21,58),(1385,211,20,58),(1404,115,24,73),
                   (1428,115,130,21),(1536,115,22,239),(1276,338,282,16),(1276,338,16,77),(1310,623,70,106),(1380,623,24,81),(1541,529,17,84),(1541,529,86,17),(1607,415,20,131),
                   (1517,415,51,70),(1276,415,24,124),(1300,415,93,104),(1404,11,218,45),(1663,7,31,333),(1622,310,72,30),(1699,832,27,106),(1726,878,116,21,),
                   (1870,978,40,40),(1820,724,22,175),(1726,724,116,20),(1699,548,27,223),(1693,310,20,249),(1799,0,16,68),(1746,52,69,16),(1746,52,17,175),(1746,211,69,16),
                   (1799,211,16,48),(1799,211,16,48),(1393,415,81,20),(1454,415,20,124),(1820,331,200,26),(1820,331,22,338),(1388,712,16,17)]
 
    for x, y, longueur, hauteur in coordonnees:
        mur = {'x': x, 'y': y, 'longueur': longueur, 'hauteur': hauteur}
 
        mur['identifiant'] = world.create_rectangle(x, y,
                                              x + longueur,
                                              y + hauteur,
                                              width=0,
                                              fill='red')#on définit ce qu'est un mur: un rectangle (de coordonnées x, y, x + longueur et y + hauteur)
 
        obstacles.append(mur)#nécessaire pour envoyer les coordonnées du mur dans les dictionnaires de acteurs['obstacles'].
 
 
 
def create_piege_1():
 
    #Cette fonction dessine les piege_1 (cercle noir) sur le canvas
 
    piege_1= acteurs['piege_1'] = [] # Une liste qui contiendra des dictionnaires(contenant les coordonnées de piege_tryagain)
 
    # Liste des coordonnées des piege_tryagain dans l'ordre x, y, longeur, hauteur
    coordonnees_piege_1 = [(498,866,30,30),(1330,915,30,30),(1020,554,30,30),(1405,443,30,30),(900,270,30,30),(780,28,30,30),(1850,108,30,30),(1745,753,30,30)]
 
    for x, y, longueur, hauteur in coordonnees_piege_1:#dans coordonnees_piege_1, on assigne le premier chiffre de chaque tuple à x, le deuxième à y...
        piege_tryagain = {'x': x, 'y': y, 'longueur': longueur, 'hauteur': hauteur}
 
        piege_tryagain ['identifiant'] = world.create_oval(x,y,
                                                     x+longueur,
                                                     y+hauteur,
                                                     width=0,
                                                     fill='black')#on définit ce qu'est un piege_1: un rond (de coordonnées x, y, x+30 et y+30)
 
        piege_1.append(piege_tryagain)#nécessaire pour envoyer les coordonnées du piege_tryagain soient dans les dictionnaires des acteurs['piege_1'].
 
def create_piege_2():
 
    #Cette fonction dessine les piege_2 (cercle jaune) sur le canvas
 
    piege_2 = acteurs['piege_2'] = [] # Une liste qui contiendra des dictionnaires(contenant les coordonnées de piege_gameover)
 
    # Liste des coordonnées des piege_gameover dans l'ordre x, y, longeur, hauteur
    coordonnees_piege_2 = [(34,52,30,30),(40,373,30,30),(255,644,30,30),(708,956,30,30),(680,630,30,30),(1034,694,30,30),(1220,23,30,30),(1584,959,30,30),(1862,367,30,30),
                            (1712,84,30,30)]
 
    for x, y, longueur, hauteur in coordonnees_piege_2:#dans coordonnees_piege_2, on assigne le premier chiffre de chaque tuple à x, le deuxième à y...
        piege_gameover = {'x': x, 'y': y, 'longueur': longueur, 'hauteur': hauteur}
 
        piege_gameover ['identifiant'] = world.create_oval(x,y,
                                                     x+longueur,
                                                     y+hauteur,
                                                     width=0,
                                                     fill='yellow')#on définit ce qu'est un piege_2: un rond (de coordonnées x, y, x+30 et y+30)
 
        piege_2.append(piege_gameover)#nécessaire pour envoyer les coordonnées du piege_gameover soient dans les dictionnaires des acteurs['piege_2'].
 
 
def create_Bonus():
 
    #Cette fonction dessine les Bonus (cercle ) sur le canvas
 
    Bonus = acteurs['Bonus'] = [] # Une liste qui contiendra des dictionnaires(contenant les coordonnées de no_zonesombres)
 
    # Liste des coordonnées des no_zonesombres dans l'ordre x, y, longeur, hauteur
    coordonnees_bonus = [(142,45,30,30),(1020,475,30,30),(1465,149,30,30)]
 
 
    for x, y, longueur, hauteur in coordonnees_bonus:#dans coordonnees_bonus, on assigne le premier chiffre de chaque tuple à x, le deuxième à y...
        no_zonesombres = {'x': x, 'y': y, 'longueur': longueur, 'hauteur': hauteur}
 
        no_zonesombres ['identifiant'] = world.create_oval(x,y,
                                                     x+longueur,
                                                     y+hauteur,
                                                     width=0,
                                                     fill='red')#on définit ce qu'est un Bonus: un rond (de coordonnées x, y, x+30 et y+30)
 
        Bonus.append(no_zonesombres)#nécessaire pour envoyer les coordonnées de no_zonesombres soient dans les dictionnaires des acteurs['bonus'].
 
 
 
 
                                                      ######################################################################
                                                      #Ci-dessous, les fonctions propres à la définition des zones d'ombres#
                                                      ######################################################################
 
 
def get_first_quadrant_poly_coord(nbre_cotes, RAYON, x0, y0):#on met en paramètre le nomre de côté de notre polygone, le RAYON voulu du cercle, x0 et y0 qui DEFINIRONT 
                                                             #(ils le font pas tout de suite vu qu'ils sont en ARGUMENTS mais ils le feront plus bas) le centre du perso et donc du cercle "lumineux"
 
    #Cette fonction sert à récupérer les coordonnées des points situés à distance "RAYON" du centre du perso
 
    points = []#on crée une liste qui récupérera les coordonnées de toous les points du premier cadran. 
    angles = []#on crée une liste angles qui contiendra les différents angles auxquels se trouvent les points du cadran
    for i in range(nbre_cotes // 4 + 1): #nombre de point par cadran = nombre de côtés divisé par 4 (on divise le polygone en 4) + 1
        angles.append(i * (360 / nbre_cotes))#on place dans la liste angle les postion en degrès des points du polygone 
    for angle in angles:#pour chaque donnée compris dans la liste angles, tu fais: ...
 
        '''ici on calcule, à l'aide x0, y0, angle et RAYON, les postions x, y des points du premier cadran à distance RAYON du centre'''
 
        x = x0 + RAYON * cos(radians(angle))
        y = y0 - RAYON * sin(radians(angle))#on met un - car l'axe des ordonnées est orienté vers le bas
        points.append( (x, y) )#on entre des tuples contenant dans l'ordre x et y dans la liste points.
    return points #on dit ici que la fonction doit nous retourner la liste points (cette liste contient dès lors, des tuples (x,y) pour chaque point du premier cadran à distance RAYON du centre )
 
def calculate_external_poly(points, largeur_canevas, hauteur_canevas):
 
    #Cette fonction vient compléter la précédente: elle permet de définir les coordonnées des autres points du premier cadran du polygone. En tout, 3 autres points permettront
    #de compléter la définition du premier cadran du polygone
 
    x0, y0 = points[0]#on dit ici que x0 et y0 correspondent au x et y contenu dans le premier tuple de la liste points. ATTENTION: ils sont à ne pas confondre au x0, y0 de la fonction précédente
    x_dernier, y_dernier = points[-1]#on dit que x_dernier et y_dernier correspondent au x et y du dernier tuple contenu dans la liste points
    point_droite = (x0 + largeur_canevas, y0)#on défini le premier point externe: celui qui est en bas à droite
    point_haut = (x_dernier, y_dernier - hauteur_canevas)#on défini le deuxième point externe: celui qui est en haut à gauche
    point_haut_droite = (x0 + largeur_canevas, y_dernier - hauteur_canevas)#on défini le troisième point externe: celui qui est en haut à droite
    points.extend([point_haut, point_haut_droite, point_droite])#on ajoute à la liste points les tuples (x,y) pour les trois autres points du cadran. IMPORTANCE de l'ordre dans lequel on
                                                                #on les ajoute: on appelle les points dans l'ordre de traçage de la figure (même principe qu'en math lorsqu'on nomme une figure)
    return points
 
def vertical_symetry(points, x_axis): #en paramètre: les coordonnées x et y des points définissant les polygones et x_axis qui est l'abscisse de l'axe verticale de symétrie. 
 
    #cette fonction définit le fonctionnement de la symétrie axiale par rapport à un axe vertical
 
    transformed_points_verticale = []#on crée une liste qui va contenir les coorodnnées de points ayant subi la symétrie verticale
    for point in points:#pour chaque tuple contenu dans la liste points, tu fais: ...
        x, y = point #point est un tuple contenant deux chiffres. A ces deux chiffres on fait correspondre des noms de variables: x pour le premier et y pour le deuxième 
        transformed_points_verticale.append((x_axis - (x - x_axis), y)) #on dit de mettre dans la liste transformed_points_verticale, les coordonnées présentes ci-contre entre parenthèses. 
    return transformed_points_verticale #on dit à cette fonction de nous retourner la liste transformed_points_verticale qui contient les tuples (x,y) ayant subi la symétrie verticale
 
def horizontal_symetry(points, y_axis):#en paramètre: les coordonnées x et y des points définissant les polygones et y_axis qui est l'ordonnée de l'axe horizontale de symétrie.
 
    #Cette fonction définit le fonctionnement de la symétrie axiale par rapport à un axe vertical
 
    transformed_points_horizontal = []#on crée une liste qui va contenir les coorodnnées de points ayant subi la symétrie horizontale
    for point in points:#pour chaque tuple contenu dans la liste points, tu fais: ...
        x, y = point#on dit que point est un tuple contenu dans la liste points. 
        transformed_points_horizontal.append((x, y_axis - (y - y_axis)))#on dit de mettre dans la liste transformed_points_horizontal, les coordonnées présentes ci-contre entre parenthèses. 
    return transformed_points_horizontal  #on dit à cette fonction de nous retourner la liste transformed_points_horizontal qui contient les tuples (x,y) ayant subi la symétrie horizontale
 
def decomposition(coords):#en paramètre, nous remplacerons coords par polygon qui est une liste (contenant des tuple codant un cadran), contenu dans la liste polygons
                          #le but de la fonction ci-dessous est de séparé chaque x et y de chaque tuple
 
    #Cette fonction est PRIMORDIALE au fonction des zones d'ombres>> voir la note l59 pour world.coords
 
    result = []#on crée une liste result
    for x, y in coords:#(pour chaque x et y car cette fonction ne nous intéresse que pour polygon qui ne contient que des x et des y)>>N.B: par exemple cette fonction ne fonctionnerait pas
                       #pour la liste acteurs['obstacles']
        result.append(x)#dans result tu insères les x
        result.append(y)#dans result, tu insères les y
    return result#on demande à ce que cette fonction me retourne la liste result qui contient tous mes x et y>> on a donc result=[x,y,x,y,x,y...]
 
        #N.B: on pourrait écrire aussi la fonction précédente de cette manière: return [item for coord in coords for item in coord]
 
 
def creer_zones_ombre(center_x, center_y, RAYON, largeur_canevas, hauteur_canevas):#en paramètres: x_center et y_center sont les coordonnées du centre du perso
 
    coords_poly = get_first_quadrant_poly_coord(NOMBRE_COTE, RAYON, center_x, center_y)
    coords_poly_external = calculate_external_poly(coords_poly, largeur_canevas, hauteur_canevas)#en connaissant le contenu de coords_poly, je calcule calculate_external_poly et je l'intègre dans coords_poly_external
    polygons = [coords_poly_external]#on met coords_poly_external (une liste de tuple définissant tous les points du premier cadran) dans une liste car on veut que ça soit ranger 
                                     #par cadran (une liste pour un cadran)
    horizontal_symetry_poly = horizontal_symetry(coords_poly_external, center_y)#j'applique la symétrie horizontale aux points définis dans coords_poly_external et je dis que cette symétrie
                                                                                #se fait par rapoort à un axe y tel que y soit l'ordonnée du centre du joueur
    polygons.append(horizontal_symetry_poly)#j'intègre la liste horizontal_symetry_poly(définissant tous les points du cadran inférieur gauche) à polygons
 
    vertical_symetry_poly = vertical_symetry(coords_poly_external, center_x)#j'applique la symétrie verticale aux points définis dans coords_poly_external et je dis que cette symétrie
                                                                                #se fait par rapoort à un axe x tel que x soit l'abscisse du centre du joueur
    polygons.append(vertical_symetry_poly)#j'intègre la liste vertical_symetry_poly(définissant tous les points du cadran superieur gauche) à polygons
 
    horizontal_vertical_symetry_poly = horizontal_symetry(vertical_symetry_poly, center_y)#j'applique la symétrie horizontale aux points définis dans vertical_symetry_poly et je dis que cette symétrie
                                                                                          #se fait par rapoort à un axe y tel que y soit l'ordonnée du centre du joueur
    polygons.append(horizontal_vertical_symetry_poly)#j'intègre la liste horizontal_vertical_symetry_poly(définissant tous les points du cadran inférieur gauche) à polygons
 
    return polygons#on demande à la fonction de retourner la liste polygons qui contient maintenant 4 listes (chacune définissant un cadran)
 
 
                                                                ##############################################################
                                                                #Fin des fonctions propres à la définition des zones d'ombres#
                                                                ##############################################################
 
 
def JOUER ():
 
    #Cette fonction défini ce qui se passe lorsqu'on clique sur jouer dans fenetre_accueil
 
    global acteurs,x_joueur_initial,y_joueur_initial,joueur,NOMBRE_COTE,RAYON_normal,RAYON_anormal,polygons,world,width_screen,height_screen, fenetre_game #ces variables sont utilisées dans d'autres fonctions, d'où le bseoin de les globaliser
 
    fenetre_accueil.destroy()#cliquer sur jouer dans fentre_accueil revient à fermer celle-ci
 
    fenetre_game = Tk()#cliquer sur jouer ouvre fenetre_game
 
    #on définit ici le cadrage de fenetre_game au centre de l'écran. 
    width_fenetre_game = width_screen
    height_fenetre_game = height_screen - hauteur_barre_menu
    position_x_fenetre_game = -10
    position_y_fenetre_game = height_screen-height_fenetre_game-hauteur_barre_menu
    fenetre_game.geometry('%dx%d+%d+%d' %(width_fenetre_game, height_fenetre_game, position_x_fenetre_game, position_y_fenetre_game))#cette ligne permet de centrer la fenêtre du jeu de manière optimale
    #N.B: '%dx%d+%d+%d' % est là pour dire que les variables entre parenthèses prennent (dans l'ordre), la place des %d entre guillemets. (car la methode geometry ne fonctionne que par '%dx%d+%d+%d)
 
    world = Canvas(fenetre_game, height=height_fenetre_game, width=width_fenetre_game, bg='white')#on crée un canvas dans fenetre_game
    world.pack(side=LEFT)#on insère ce canvas world dans fenetre_game
 
 
    acteurs = {} # Dictionnaire contenant tous les acteurs du monde (joueur, murs)
    x_joueur_initial, y_joueur_initial = 35, 974 #importance de mettre les coordonnées initiale du perso dans la fontion jouer afin de les utiliser dans les fonctions(ces variables étant globalisées
                                                 #au début de cette fonction)
 
    joueur = acteurs['joueur'] = {'x': x_joueur_initial, 'y': y_joueur_initial, 'longueur': 30, 'hauteur': 30} #on définit les coordonnées que prend le perso au début du jeu
 
    acteurs['joueur']['identifiant'] = world.create_oval(joueur['x'],
                                                   joueur['y'],
                                                   joueur['x'] + joueur['longueur'],
                                                   joueur['y'] + joueur['hauteur'],
                                                   width=0, fill='blue')#on crée notre perso
 
    create_obstacle()#on appelle la fonction créant les obstacles
    create_piege_1()#on appelle la fonction créant les piege_1
    create_piege_2()#on appelle la fonction créant les piege_2
    create_Bonus()#on appelle la fonction créant les bonus
 
 
        ############################################################
        #definition des zones d'ombres dans le programme principale#
        ############################################################
 
    NOMBRE_COTE = 200
    RAYON_normal = 200
    RAYON_anormal = 3000
 
    polygons = creer_zones_ombre(joueur['x'] + joueur['longueur']/2, joueur['y'] + joueur['hauteur']/2, RAYON_normal or RAYON_anormal, width_fenetre_game, height_fenetre_game)#on définit ici les paramètres de la fct 
                                                                                                                                            #creer_zones_ombres
                                                                                                                                            #polygons vaut donc ici une liste contenant 4 liste propres à chaque cadran et spécifique 
                                                                                                                                            #des paramètres rentrés dans cree_zones_ombre
 
    acteurs['zonesombre'] = []#on crée une liste
 
    for polygon in polygons:#on dit ici que polygon est une liste (correspondant à 1 cadran) contenu dans polygons
        zone_ombre = {'points': polygon}#zone_ombre est donc un dictionnaire (comme joueur) contenant 4 listes de coordonnées correspondant aux 4 cadrans
        zone_ombre['identifiant'] = world.create_polygon(polygon, fill = 'black')#on crée la zone d'ombre en créant les 4 cadrans séparément
        acteurs['zonesombre'].append(zone_ombre)#dans la liste acteurs['zonesombre'], je place le dictionnaire zone_ombre qui contient les 4 listes contenant les tuples pour chaque cadran. 
 
 
        ######################################################################
        #fin de la definition des zones d'ombres dans le programme principale#
        ######################################################################
 
    world.focus_set()#designe la fenêtre qui a le focus
    world.bind("<Key>", clavier)#dit au programme qu'il doit être attentif au interaction clavier.
    fenetre_game.mainloop()
 
                                                                    #############################
                                                                    #############################
                                                                    ###  PROGRAMME PRINCIPALE ###
                                                                    #############################
                                                                    #############################
fenetre_accueil=Tk()#on crée la fenetre d'accueil
fenetre_accueil.title('LOST')#on assigne un titre à cette fenêtre
 
# Image de fond
photo = PhotoImage(file="LOST.png")#on assigne à la varibale photo, un fichier png contenu dans le dossier du jeu
 
# Création d'un widget Canvas (zone graphique)+cadrage de fenetre_acceuil au centre de l'écran
width_fenetre_accueil = 500
height_fenetre_accueil = 465
width_screen = fenetre_accueil.winfo_screenwidth()
height_screen = fenetre_accueil.winfo_screenheight()#width_screen=la width_fenetre_accueil de l'écran et height_screen= la height_fenetre_accueil de l'écran
hauteur_barre_menu = 70
position_x_fenetre_accueil = (width_screen - width_fenetre_accueil)/2
position_y_fenetre_accueil = (height_screen - hauteur_barre_menu - height_fenetre_accueil)/2
fenetre_accueil.geometry('%dx%d+%d+%d' %(width_fenetre_accueil, height_fenetre_accueil, position_x_fenetre_accueil, position_y_fenetre_accueil))
 
Can_fenetre_accueil = Canvas(fenetre_accueil, width = width_fenetre_accueil, height =height_fenetre_accueil)#on crée un canvas pour fenetre_accueil
item = Can_fenetre_accueil.create_image(0,0,anchor=NW, image=photo)#on assigne la photo au canvas que l'on a créée. 
Can_fenetre_accueil.place(x=0,y=0)
 
 
 
#on crée les bouttons à insérés dans fenetre_accueil
BoutonJouer = Button(fenetre_accueil, text ='JOUER', command = JOUER)
BoutonJouer.place(x=150, y=430)#la methode place() permet ici de placer le boutons selon des coordonnées x, y
BoutonQuitter = Button(fenetre_accueil, text ='QUITTER', command = fenetre_accueil.destroy)
BoutonQuitter.place(x=290, y=430)