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
| from Tkinter import *
from math import sin, cos, pi
from random import randrange
class Canon:
""" Petit canon graphique """
def __init__(self, boss, id, x, y, sens, coul):
self.boss = boss #ref.du canevas
self.appli = boss.master #ref. de la fenêtre d'application
self.id = id #identifiant du canon (chaîne)
self.coul = coul #couleur associée au canon
self.x1, self.y1 = x, y #axe de rotation du canon
self.sens = sens #sens de tir(-1:gauche, +1:droite)
self.lbu = 30 #longueur de la buse
self.angle = 0 #hausse par défaut (angle de tir)
# retrouver la largeur et la hauteur du canevas:
self.xMax = int(boss.cget('width'))
self.yMax = int(boss.cget('height'))
# dessiner la buse du canon (horizontale) :
self.x2, self.y2 = x + self.lbu * sens, y
self.buse = boss.create_line(self.x1, self.y1,self.x2, self.y2, width =10)
# dessiner le corps du canon (cercle de couleur) :
self.rc = 15 #rayon du cercle
self.corps = boss.create_oval(x -self.rc, y -self.rc, x +self.rc,
y +self.rc, fill =coul)
# pré-dessiner un obus caché (point en dehors du canevas) :
self.obus = boss.create_oval(-10, -10, -10, -10, fill='red')
self.anim = False #indicateurs d'animation
self.expo = False # et d'explosion
def orienter(self, angle):
"régler la hausse du canon"
# rem: le paramètre <angle> est reçu en tant que chaîne.
# il faut donc le traduire en réel, puis le convertir en radians :
self.angle = float(angle)*pi/180
# rem: utiliser la méthode coords de préférence avec des entiers :
self.x2 = int(self.x1 + self.lbu * cos(self.angle) * self.sens)
self.y2 = int(self.y1 - self.lbu * sin(self.angle))
self.boss.coords(self.buse, self.x1, self.y1, self.x2, self.y2)
def deplacer(self, x, y):
"amener le canon dans une nouvelle position x, y"
dx, dy = x -self.x1, y -self.y1 #valeur du déplacement
self.boss.move(self.buse, dx, dy)
self.boss.move(self.corps, dx, dy)
self.x1 += dx
self.y1 += dy
self.x2 += dx
self.y2 += dy
def feu(self):
"tir d'un obus - seulement si le précédent à fini son vol"
if not (self.anim or self.explo):
self.anim = True
self.explo = True
#récupérer la description de tous les canons présents :
self.guns = self.appli.dictionnaireCanons()
#position de départ de l'obus (c'est la bouche du canon) :
self.boss.coords(self.obus, self.x2 -3, self.y2 -3,self.x2 +3, self.y2 +3)
v = 17 #vitesse initiale
#composantes verticale et horizontale de cette vitesse:
self.vy = -v *sin(self.angle)
self.vx = v *cos(self.angle) *self.sens
self.animer_obus()
return True # =>signaler que le coup est parti
else:
return False # => le coup n'a pas pu être tiré
def animer_obus(self):
"animer l'obus (trajectoire balistique)"
if self.anim:
self.boss.move(self.obus, int(self.vx), int(self.vy))
c = self.boss.coords(self.obus) #coord. résultantes
xo, yo = c[0] +3, c[1] +3 #coord. du centre de l'obus
self.test_obstacle(xo, yo) #a-t-on atteint un obstacle?
self.vy += .4 #accélération verticale
self.boss.after(20, self.animer_obus)
else:
#animation terminée - cacher l'obus et déplacer les canons :
self.fin_animation()
def test_obstacle(self, xo, yo):
"évaluer si l'obus a atteint une cible ou les limites du jeu"
if yo >self.yMax or xo <0 or xo >self.xMax:
self.anim =False
return
#analyser le dictionnaire des canons pour voir si les coordonnées
#de l'un d'entre eux sont proches de celle de l'obus:
for id in self.guns: #id = clef dans dictionnaire
gun = self.guns[id] #valeur correspondante
if xo < gun.x1 +self.rc and xo > gun.x1 -self.rc \
and yo < gun.y1 +self.rc and y0 > gun.y1 -self.rc:
self.anim =False
#dessiner l'explosion de l'obus (cercle jaune):
self.explo = self.boss.create_oval(xo -12, yo -12,
xo +12, yo +12, fill='yellow', width =0)
self.hit =id #référence de la cible touchée
self.boss.after(150, self.fin_explosion)
break
def fin_explosion(self):
"effacer l'explosion, ré-initialiser l'obus, gérer le score"
self.boss.delete(self.explo) #effacer l'explosion
self.explo =False #autoriser un nouveau tir
#signaliser le succès à la fenêtre maîtresse:
self.appli.goal(self.id, self.hit)
def fin_animation(self):
"action à accomplir lorsque l'obus a terminé sa trajectoire"
self.appli.disperser() #déplacer les canons
# cacher l'obus (en l'expédiant hors du canevas):
self.boss.coords(self.obus, -10, -10, -10, -10)
class Pupitre (Frame):
"""Pupitre de pointage associé à un canon"""
def __init__(self, boss, canon):
Frame.__init__(self, bd =3, relief =GROOVE)
self.score =0
self.appli =boss #ref. de l'application
self.canon = canon #ref.du canon associé
#Système de réglage de l'angle de tir:
self.regl =Scale(self, from_=75, to =-15, troughcolor=canon.coul,
command =self.orienter)
self.regl.set(45) #angle initial de tir
self.regl.pack(side =LEFT)
# Etiquette d'iddentification du canon :
Label(self, text =canon.id).pack(side =TOP, anchor =W, pady =5)
# Bouton de tir:
self.btir =Button(self, text ='Feu !', command =self.tirer)
self.btir.pack(side =BOTTOM, padx =5, pady =5)
Label(self, text ="points").pack()
self.points =Label(self, text=' 0 ',bg ='white')
self.points.pack()
#positionner à gauche ou à droite suivant le sens du canon :
if canon.sens == -1:
self.pack(padx =5, side =RIGHT)
else:
self.pack(padx =5, pady =5, side =LEFT)
def tirer(self):
"déclencher le tir du canon associé"
self.canon.feu()
def orienter(self, angle):
"ajuster la hausse du canon associé"
self.canon.orienter(angle)
def attribuerPoint(self, p):
"incrémenter ou décrémenter le score, de <p> points"
self.score += p
self.points.config(text = ' %s ' % self.score)
class Application(Frame):
'''Fenêtre principale de l'application'''
def __init__(self):
Frame.__init__(self)
self.master.title('>>>>> Boum ! Boum ! <<<<<')
self.pack()
self.jeu = Canvas(self, width =400, height =250, bg ='ivory',
bd =3, relief =SUNKEN)
self.jeu.pack(padx =8, pady =8, side =TOP)
self.guns ={} #dictionnaire des canons présents
self.pupi ={} #dictionnaire des pupitres présents
#instanciation de 2 'objets canon (+1, -1 = sens oposés) :
self.guns["Dramdun"] = Canon(self.jeu, "Dramdun", 30, 200, 1, "red")
self.guns["linux"] = Canon(self.jeu, "linux", 370, 200, -1, "blue")
#instanciation de 2 pupitres de pointage associés à ces canons :
self.pupi["Dramdun"] = Pupitre(self, self.guns["Dramdun"])
self.pupi["linux"] = Pupitre(self, self.guns["linux"])
def disperser(self):
"déplacer aléatoirementles canons"
for id in self.guns:
gun = self.guns[id]
#positionner à gauche ou à droite, suivant sens du canon :
if gun.sens == -1:
x = randrange(320, 380)
else:
x = randrange(20, 80)
#déplacement proprement dit:
gun.deplacer(x, randrange(150, 240))
def goal(self, i, j):
"le canon <i> signale qu'il a atteint l'adversaire <j>"
if i != j:
self.pupi[i].attribuerPoint(1)
else:
self.pupi[i].attribuerPoint(-1)
def dictionnaireCanons(self):
"renvoyer le dictionnaire décrivant les canons présents"
return self.guns
if __name__ == '__main__':
Application().mainloop() |
Partager