Accueil > > > BILLARD FRANÇAIS
BILLARD FRANÇAIS
Information sur la source
Description
Trois boules : blanche, rouge et grise sur un tapis vert ... et deux joueurs. Après avoir placé les boules sur le billard et réglé la direction, la vitesse, l'effet et la hauteur de tir, le premier joueur pourra "continuer", "rejouer le coup" ou "passer la main", en fonction des résultats de son score. L'algorithme de choc passe par le calcul du recul des boules après intersection de leurs contours, pour revenir au strict contact, puis par la détermination des nouveaux vecteurs vitesses selon les lois de la mécanique des chocs inélastiques. Ce script devrait intéresser les débutants qui cherchent à mettre en oeuvre les interfaces graphiques Tkinter, avec les widgets Canvas, Button, Text, Scale et Label.
Source
- #! /usr/bin/env python
- # -*- coding: Latin-1 -*-
-
- # <<< Billard >>>
-
- # REMERCIEMENTS : ce projet est très largement inspiré des exemples fournis par Mr Gérard Swinnen dans la deuxième édition de son ouvrage intitulé "Apprendre à programmer avec Python".
-
-
- from Tkinter import *
- from math import *
-
- # CONVENTIONS
- # boule BLANCHE....(coordonnées:x1,y1):B1
- # boule ROUGE......(coordonnées:x2,y2):B2
- # boule GRISE......(coordonnées:x3,y3):B3
- # bille bleue......(coordonnées:x4,y4):b4(Réglage de l'effet latéral et de la hauteur de tir)
- # cercle blanc.....(coordonnées:x5,y5):b5(Réglage de l'orientation et de la vitesse de tir)
- # pupitre de simulation : indice "S"
-
- ########## Commande "préparer le jeu" ####################################
-
- def jouer():
- "Préparer le jeu"
- global flag,texte
- if flag==0:flag=1
- jouer;config_init() # mise en place de la configuration initiale (boules,flèches,réglages)
- can.bind("<Button-1>", mouseDown) # commandes avec le clic gauche de la souris
- can.bind("<Button1-Motion>", mouseMove)
- can.bind("<Button1-ButtonRelease>", mouseUp)
- T.pack(),J.pack_forget() # gestion des boutons de commande
- can.delete(texte)
-
- ########## Commandes de réglage du tir ###################################
-
- def mouseDown( event):
- "Opérations à effectuer quand le bouton gauche de la souris est enfoncé"
- global selObject,X,Y,x5,y5,v,o
- can.currObject=None
- X,Y=event.x,event.y # coordonnées du clic
- D1=hypot(X-x1-r,Y-y1-r) # distance entre le clic et le centre de B1
- D2=hypot(X-x2-r,Y-y2-r) # idem B2
- D3=hypot(X-x3-r,Y-y3-r) # idem B3
- D4=hypot(X-x4-R,Y-y4-R) # idem bille bleue
- D5=hypot(X-x5-R,Y-y5-R) # idem cercle blanc
- X5,Y5=x5-7L/8+R,y5-H-h/2+R
- H5=hypot(X5,Y5)
- if D1<r:selObject=b1 # sélection de B1 si le clic est à l'intérieur de B1
- if D2<r:selObject=b2 # idem B2
- if D3<r:selObject=b3 # idem B3
- if D4<R:selObject=b4 # idem bille bleue
- if D5<4*R:selObject=b5 # plage de sélection du cercle blanc: cercle de rayon 4R
- if selObject==b5: # procédure de réglage fin, par clic sussessifs à proximité
- dx,dy=(X-x5-R)/40,(Y-y5-R)/40 # pas = 1/40 ème de la distance du clic au centre du cercle
- x5,y5=x5+dx,y5+dy
- can.move(selObject,dx,dy) # déplacement du cercle blanc
- C5=can.coords(b5)
- x5,y5=C5[0],C5[1]
- o=-atan2(y5-H-h/2+R,x5-7*L/8+R) # récupération de l'angle de tir (o)
- wo=round(float(o*180/pi),1)
- can.orientation.config(text='%s'%wo) # valeur d'affichage de (o)
- v=1+14*hypot(x5+R-7*L/8-2*R*cos(o),y5+R-H-h/2+2*R*sin(o))/(3*h/8-3*R) # récupération de la vitessede tir (v)
- wv=round(float(v),1)
- can.vitesse.config(text='%s'%wv) # valeur d'affichage de (v)
- if B1==1:fl(flèche1,o,x1,y1)
- if B3==1:fl(flèche3,o,x3,y3)
- can.coords(curseur5,7*L/8+R*cos(o),H+h/2-R*sin(o),x5+R-R*cos(o),y5+R+R*sin(o))
- can.itemconfig(selObject,width=2) # le contour de l'objet sélectionné double d'épaisseur
-
- def mouseMove(event):
- "Opérations à effectuer quand la souris se déplace, bouton gauche enfoncé"
- global O,X,Y
- global x1,y1,x2,y2,x3,y3,x4,y4,x5,y5
- global e,ha,v,o,o4
- XX,YY=event.x,event.y
- dx,dy=XX-X,YY-Y
- if selObject==b1:
- if dx+x1>0 and dx+x1<L-2*r and dy+y1>0 and dy+y1<H-2*r:
- can.move(selObject,dx,dy);X,Y=XX,YY # déplacement de B1
- C1=can.coords(b1)
- x1,y1=C1[0],C1[1] # récupération des coordonnées du coin supérieur gauche
- if B1==1:fl(flèche1,pi,x1,y1) # déplacement de la flèche de B1
- if selObject==b2 :
- if dx+x2>0 and dx+x2<L-2*r and dy+y2>0 and dy+y2<H-2*r:
- can.move(selObject,dx,dy);X,Y=XX,YY # déplacement de B2
- C2=can.coords(b2)
- x2,y2=C2[0],C2[1]
- if selObject==b3 :
- if dx+x3>0 and dx+x3<L-2*r and dy+y3>0 and dy+y3<H-2*r:
- can.move(selObject,dx,dy);X,Y=XX,YY # déplacement de B3
- C3=can.coords(b3)
- x3,y3=C3[0],C3[1]
- if B3==1:fl(flèche3,pi,x3,y3) # déplacement de la flèche de B3
- if selObject==b4:
- DX4,DY4=dx+x4-L/8+R,dy+y4-H-h/2+R
- HD4=hypot(DX4,DY4)
- if HD4<R4-R:
- can.move(selObject,dx,dy);X,Y=XX,YY # déplacement de la bille bleue
- C4=can.coords(b4)
- x4,y4=C4[0],C4[1]
- o4=atan2(DY4,DX4)
- e=(x4-L/8+R)*2/(R4-R)*pi/180 # calcul de l'effet (-2<e<+2)
- we=round(float(e*180/pi),1);can.effet.config(text='%s'%we)
- ha=-2*(y4-H-h/2+R)/(R4-R) # calcul de la hauteur (-2<h<+2)
- wha=round(float(ha),1);can.hauteur.config(text='%s'%wha)
- can.coords(curseur4,L/8+R4*cos(o4),H+h/2+R4*sin(o4),L/8-R4*cos(o4),H+h/2-R4*sin(o4))
- if selObject==b5:
- DX5,DY5=dx+x5-7*L/8+R,dy+y5-H-h/2+R
- HD5=hypot(DX5,DY5)
- if HD5<3*h/8-R and HD5>2*R:
- can.move(selObject,dx,dy);X,Y=XX,YY # déplacement du cercle blanc dans l'espace d'orientation et de vitesse
- C5=can.coords(b5)
- x5,y5=C5[0],C5[1]
- o=-atan2(y5-H-h/2+R,x5-7*L/8+R) # récupération de l'angle de tir (o)
- wo=round(float(o*180/pi),1)
- can.orientation.config(text='%s'%wo)
- v=1+14*hypot(x5+R-7*L/8-2*R*cos(o),y5+R-H-h/2+2*R*sin(o))/(3*h/8-3*R)# récupération de la vitesse de tir (v)
- wv=round(float(v),1)
- can.vitesse.config(text='%s'%wv)
- can.coords(curseur5,7*L/8+R*cos(o),H+h/2-R*sin(o),x5+R-R*cos(o),y5+R+R*sin(o))
- if B1==1:fl(flèche1,o,x1,y1)
- if B3==1:fl(flèche3,o,x3,y3)
-
- def mouseUp(event):
- "Opérations à effectuer quand le bouton gauche de la souris est relâché"
- global selObject
- can.itemconfig(selObject,width=1) # le contour de l'objet sélectionné revient à son épaisseur initiale
- if selObject==b1:selObject=None
- if selObject==b2:selObject=None
- if selObject==b3:selObject=None
- if selObject==b4:selObject=None
- if selObject==b5:selObject=None
-
- ########## Commande "tirer" ##############################################
-
- def tirer():
- "tirer "
- global T1,T3,t1,t3,S1,S3,E1,E3,R1,R3,PM1,PM3
- global x1,y1,x3,y3,dx1,dy1,dx3,dy3
- global xx1,yy1,xx2,yy2,xx3,yy3
- global dxx1,dyy1,dxx2,dyy2,dxx3,dyy3
- global xx4,yy4,xx5,yy5
- global ee,hh,oo,vv,oo4
- if B1==1:
- T1=1;t1+=1 # indicateur et compteur de tir
- dx1,dy1=v*cos(o),-v*sin(o) # coordonnées du vecteur vitesse
- can.coords(flèche1,x1+r,y1+r,x1+r,y1+r) # origine de la flèche
- can.itemconfig(b4,fill='white',outline='white') # effacement de la bille bleue
- can.itemconfig(curseur4,fill='white') # effacement du diamètre de la bille bleue
- if B3==1:
- T3=1;t3+=1
- dx3,dy3=v*cos(o),-v*sin(o)
- can.coords(flèche3,x3+r,y3+r,x3+r,y3+r) # idem
- can.itemconfig(b4,fill='grey',outline='grey') # idem
- can.itemconfig(curseur4,fill='grey')
- xx1,yy1,xx2,yy2,xx3,yy3=x1,y1,x2,y2,x3,y3 # mémorisation de la position des trois boules
- dxx1,dyy1,dxx2,dyy2,dxx3,dyy3=dx1,dy1,dx2,dy2,dx3,dy3 # mémorisation de la vitesse des trois boules
- xx4,yy4,xx5,yy5=x4,y4,x5,y5 # mémorisation de la position de la bille et du cercle
- ee,hh,oo,vv,oo4=e,ha,o,v,o4 # mémorisation des réglages du tir
- S1,S3,E1,E3,R1,R3,PM1,PM3,CT1,CT3=0,0,0,0,0,0,0,0,0,0 # mise à zéro des indicateurs
- T.pack_forget();FI.pack() # gestion des boutons de commande
- can.itemconfig(texte1,fill="brown")
- can.delete(texte2);can.delete(texte3)
- can.itemconfig(b5,outline='dark green') # effacement du cercle blanc
- can.itemconfig(curseur5,fill='dark green') # effacement de la flèche
- move() # appel de la fonction "mouvement" des boules
-
- ###### Commandes "continuer/rejouer/passer la main/figer/relancer" #######
-
- def continuer():
- "continuer"
- global flag,CT1,CT3,B1,B3
- global x1,y1,x2,y2,x3,y3,x4,y4,x5,y5
- global e,ha,o,v,o4,o6
- if flag==0:flag=1
- e,ha,o,v,o4=0,0,pi,8,pi/2 # réglages de départ
- x4,y4,x5,y5=x4o,y4o,x5o,y5o # coordonnées de départ de la bille et du cercle
- effacer_simulation()
- continuer;config() # mise en place de la configuration
- if S1==1:CT1=1;B1,B3=1,0;fl(flèche1,o,x1,y1)
- if S3==1:CT3=1;B1,B3=0,1;fl(flèche3,o,x3,y3)
- T.pack();CT.pack_forget();RJ.pack_forget()
- effacer_texteR()
-
- def rejouer():
- "rejouer le coup"
- global flag,R1,R3,r1,r3
- global x1,y1,x2,y2,x3,y3
- global e,ha,o,v,o4
- if flag==0:flag=1
- e,ha,o,v,o4 =ee,hh,oo,vv,oo4 # récupération des réglages avant tir
- x1,y1,x2,y2,x3,y3=xx1,yy1,xx2,yy2,xx3,yy3 # récupération des positions avant tir des boules
- x4,y4,x5,y5=xx4,yy4,xx5,yy5 # récupération des positions avant tir de la bille et du cercle
- rejouer;config() # mise en place de la configuration
- if B1==1 :R1=1;fl(flèche1,o,x1,y1);r1+=1
- if B3==1 :R3=1;fl(flèche3,o,x3,y3);r3+=1
- T.pack();RJ.pack_forget();PM.pack_forget();CT.pack_forget()
- effacer_texteR()
-
- def passer():
- "passer la main"
- global flag,PM1,PM3,B1,B3
- global x1,y1,x2,y2,x3,y3,x4,y4,x5,y5
- global e,ha,o,v,o4
- if flag==0:flag=1
- e,ha,o,v,o4=0,0,pi,8,pi/2 # réglages de départ
- x4,y4,x5,y5=x4o,y4o,x5o,y5o # coordonnées de départ de la bille et du cercle
- effacer_simulation()
- passer;config() # mise en place de la configuration
- if E1==1:PM1=1;B1,B3=0,1;fl(flèche3,o,x3,y3) # changement de boule (B3 prend la main)
- if E3==1:PM3=1;B1,B3=1,0;fl(flèche1,o,x1,y1)
- if B3==1:can.itemconfig(REG4,fill='grey');can.itemconfig(REG5B,fill='grey')
- if B1==1:can.itemconfig(REG4,fill='white');can.itemconfig(REG5B,fill='white')
- T.pack();RJ.pack_forget();PM.pack_forget();CT.pack_forget()
- effacer_texteR()
-
- def stop():
- "Figer le jeu"
- global flag,figer
- figer=1;flag=0
- dxx1,dyy1,dxx2,dyy2,dxx3,dyy3=dx1,dy1,dx2,dy2,dx3,dy3 # mémorisation de la vitesse des trois boules
- RL.pack();FI.pack_forget()
-
- def go():
- "Relancer le jeu"
- global flag,figer
- flag=1;figer=0
- dx1,dy1,dx2,dy2,dx3,dy3=dxx1,dyy1,dxx2,dyy2,dxx3,dyy3 # récupération de la vitesse avant arrêt des trois boules
- FI.pack();RL.pack_forget();RJ.pack_forget();PM.pack_forget()
- move() # redémarrage du mouvement d'ensemble
-
- ########## Commande "score" ##############################################
-
- def score():
- "Détermination du score"
- global score1,score3,texte1S,texte1E,texte3S,texte3E,S1,S3,E1,E3
- if B1==1:
- if figer==1:RJ.pack_forget();PM.pack_forget()
- else:
- if point1==1:
- S1=1;score1+=1 # Constat de succès : le score de B1 augmente d'un point
- texte1S=can3.create_text(2*h/3,h/4,text='La BLANCHE continue\nou\nrejoue le coup',fill ="red",font ="Arial 8")
- CT.pack();RJ.pack();FI.pack_forget()
- if point1==0:
- E1=1;score1+=0 # Constat d'échec
- texte1E=can3.create_text(2*h/3,h/4,text='La BLANCHE rejoue le coup\nou\npasse la main',fill ="red",font ="Arial 8")
- RJ.pack();PM.pack();FI.pack_forget()
- if R1==1:score1+=-1
- can.score1.config(text='%s'%score1)
-
- if B3==1:
- if figer==1:RJ.pack_forget();PM.pack_forget()
- else:
- if point3==1:
- S3=1;score3+=1
- texte3S=can3.create_text(2*h/3,h/4,text='La GRISE continue\nou\nrejoue le coup',fill ="red",font ="Arial 8")
- CT.pack();RJ.pack();FI.pack_forget()
- if point3==0:
- E3=1;score3+=0
- texte3E=can3.create_text(2*h/3,h/4,text='La GRISE rejoue le coup\nou\npasse la main',fill ="red",font ="Arial 8")
- RJ.pack();PM.pack();FI.pack_forget()
- if R3==1:score3+=-1
- can.score3.config(text='%s'%score3)
-
-
- ########## Fonction "mouvement" ##########################################
-
- def move():
- "mouvement des trois boules au fur et à mesure des chocs"
- global flag
- global x1,y1,x2,y2,x3,y3
- global dx1,dy1,dx2,dy2,dx3,dy3
- global c12,c23,c31,point1,point3
- global T1,T3,RT1,RT3,RN1,RN3,rt
- global sim1,sim3
-
- x1,y1,x2,y2,x3,y3=x1+dx1,y1+dy1,x2+dx2,y2+dy2,x3+dx3,y3+dy3 # création du mouvement
- dx1,dy1,dx2,dy2,dx3,dy3=k*dx1,k*dy1,k*dx2,k*dy2,k*dx3,k*dy3 # freinage du tapis (k)
-
- if hypot(dx1,dy1)<s:dx1,dy1=0,0 # arrêt de B1 lorsque la vitesse de B1 devient trop faible (<s)
- if hypot(dx2,dy2)<s:dx2,dy2=0,0 # idem B2
- if hypot(dx3,dy3)<s:dx3,dy3=0,0 # idem B3
-
- X12,Y12,X23,Y23,X31,Y31=x2-x1,y2-y1,x3-x2,y3-y2,x1-x3,y1-y3
- Z12,Z23,Z31=hypot(X12,Y12),hypot(X23,Y23),hypot(X31,Y31)
- dx12,dy12,dx23,dy23,dx31,dy31=dx2-dx1,dy2-dy1,dx3-dx2,dy3-dy2,dx1-dx3,dy1-dy3
- dz12,dz23,dz31=hypot(dx12,dy12),hypot(dx23,dy23),hypot(dx31,dy31)
- k12,K12,k23,K23,k31,K31=dz12*dz12,X12*dx12+Y12*dy12,dz23*dz23,X23*dx23+Y23*dy23,dz31*dz31,X31*dx31+Y31*dy31
- u12,u23,u31=Z12-2*r,Z23-2*r,Z31-2*r
-
- # Choc de B1 sur B2 :
- if u12<=0: # la distance entre centres est <= à la somme des rayons
- # algorithme de recul des deux boules :
- c12+=1 # compteur de chocs B1/B2
- m12=(K12+sqrt(K12*K12-k12*(Z12*Z12-4*r*r)))/k12
- x1,y1,x2,y2=x1-m12*dx1,y1-m12*dy1,x2-m12*dx2,y2-m12*dy2 # recul des deux boules sur leurs directions initales
- # algorithme de modification des vecteurs vitesse après le choc:
- A12,B12,C12,D12=(X12*dx1+Y12*dy1)/Z12,(-Y12*dx1+X12*dy1)/Z12,(X12*dx2+Y12*dy2)/Z12,(-Y12*dx2+X12*dy2)/Z12
- dx1,dy1,dx2,dy2=(-Y12*B12+X12*C12)/Z12,(X12*B12+Y12*C12)/Z12,(-Y12*D12+X12*A12)/Z12,(X12*D12+Y12*A12)/Z12
- if T1==1 or T3==1 and RT1==0 and RN1 ==0:
- effet_choc(dx1,dy1,dx2,dy2)
- dx1,dy1,dx2,dy2=dxAE,dyAE,dxBE,dyBE # vitesse corrigée de l'effet
- if B1==1 or B3==1 and c12==1:
- hauteur(dxx1,dyy1,dxx2,dyy2) # vitesse corrigée de la hauteur de tir
- dx1,dy1,dx2,dy2=dx1+dxACR,dy1+dyACR,dx2+dxBCR,dy2+dyBCR
- # Choc de B2 sur B3 :
- if u23<=0:
- c23+=1 # compteur de chocs B2/B3
- m23=(K23+sqrt(K23*K23-k23*(Z23*Z23-4*r*r)))/k23
- x2,y2,x3,y3=x2-m23*dx2,y2-m23*dy2,x3-m23*dx3,y3-m23*dy3
- A23,B23,C23,D23=(X23*dx2+Y23*dy2)/Z23,(-Y23*dx2+X23*dy2)/Z23,(X23*dx3+Y23*dy3)/Z23,(-Y23*dx3+X23*dy3)/Z23
- effet_choc(dx2,dy2,dx3,dy3)
- dx2,dy2,dx3,dy3=dxAE,dyAE,dxBE,dyBE
- dx2,dy2,dx3,dy3=(-Y23*B23+X23*C23)/Z23,(X23*B23+Y23*C23)/Z23,(-Y23*D23+X23*A23)/Z23,(X23*D23+Y23*A23)/Z23
- if B3==1 and c23==1:
- hauteur(dxx3,dyy3,dxx2,dyy2)
- dx3,dy3,dx2,dy2=dx3+dxACR,dy3+dyACR,dx2+dxBCR,dy2+dyBCR
- # Choc de B3 sur B1 :
- if u31<=0:
- c31+=1 # compteur de chocs B3/B1
- m31=(K31+sqrt(K31*K31-k31*(Z31*Z31-4*r*r)))/k31
- x3,y3,x1,y1=x3-m31*dx3,y3-m31*dy3,x1-m31*dx1,y1-m31*dy1
- A31,B31,C31,D31=(X31*dx3+Y31*dy3)/Z31,(-Y31*dx3+X31*dy3)/Z31,(X31*dx1+Y31*dy1)/Z31,(-Y31*dx1+X31*dy1)/Z31
- dx3,dy3,dx1,dy1=(-Y31*B31+X31*C31)/Z31,(X31*B31+Y31*C31)/Z31,(-Y31*D31+X31*A31)/Z31,(X31*D31+Y31*A31)/Z31
- if T3==1 or T1==1 and RT3==0 and RN3==0:
- effet_choc(dx3,dy3,dx1,dy1)
- dx3,dy3,dx1,dy1=dxAE,dyAE,dxBE,dyBE
- if B3==1 or B3==1 and c31==1:
- hauteur(dxx3,dyy3,dxx1,dyy1)
- dx3,dy3,dx1,dy1=dx3+dxACR,dy3+dyACR,dx1+dxBCR,dy1+dyBCR
-
- if c12*c31>0:point1=1 # succès=1 point
- else:point1=0 # échec
- if c23*c31>0:point3=1
- else:point3=0
-
- if x1>L-2*r or x1<0 or y1>H-2*r or y1<0: # Rebonds de la BLANCHE sur les bandes:
- if T1==1 and c12==0 and c31==0:
- rebond_tir(x1,y1,dx1,dy1)
- x1,y1,dx1,dy1,RT1=xR,yR,dxR,dyR,RT
- else :
- rebond_normal(x1,y1,dx1,dy1)
- x1,y1,dx1,dy1,RN1=xR,yR,dxR,dyR,RN
- T1=0
- if x2>L-2*r or x2<0 or y2>H-2*r or y2<0: # Rebonds de la ROUGE sur les bandes:
- rebond_normal(x2,y2,dx2,dy2)
- x2,y2,dx2,dy2=xR,yR,dxR,dyR
- if x3>L-2*r or x3<0 or y3>H-2*r or y3<0: # Rebonds de la GRISE sur les bandes:
- if T3==1 and c31==0 and c23==0:
- rebond_tir(x3,y3,dx3,dy3)
- x3,y3,dx3,dy3,RT3=xR,yR,dxR,dyR,RT
- T3=0
- else:
- rebond_normal(x3,y3,dx3,dy3)
- x3,y3,dx3,dy3,RN3=xR,yR,dxR,dyR,RN
-
- Cboule(b1,x1,y1,r);Cboule(b2,x2,y2,r);Cboule(b3,x3,y3,r) # Nouvelles coordonnées de B1,B2,B3
- CbouleS(b1S,x1,y1,RS);CbouleS(b2S,x2,y2,RS);CbouleS(b3S,x3,y3,RS)
-
- if B1==1:sm(x1,y1,dx1,dy1);sim1=sim;can.itemconfig(sim1,fill='white')
- if B3==1:sm(x3,y3,dx3,dy3);sim3=sim;can.itemconfig(sim3,fill='grey')
-
- # Algorithmes à l'arrêt des trois boules
- if flag==0:
- c12+=-c12 # mise à zéro des compteurs de choc
- c23+=-c23
- c31+=-c31
- score() # appel de la commande "score"
- rt=0
- if flag>0:
- root.after(10,move) # déclenchement du mouvement des boules et des flèches
- if dx1==0 and dy1==0 and dx2==0 and dy2==0 and dx3==0 and dy3==0:flag=0 # arrêt complet
-
- ########## Procédures diverses ###########################################
-
- def config_init():
- "Mise en place de la configuration de départ (à partir des 'données initiales)"
- global B1,B3,b1,b2,b3,b4,b5,b1S,b2S,b3S
- B1,B3=1,0 # Sélection de la boule à tirer (B1)
- boule(x1,y1,r,color='white');b1=b # Mise en place de B1
- boule(x2,y2,r,color='red');b2=b # idem B2
- boule(x3,y3,r,color='grey');b3=b # idem B3
- bouleS(x1,y1,RS,color='white');b1S=bS # idem B1/Pupitre
- bouleS(x2,y2,RS,color='red');b2S=bS # idem B2/Pupitre
- bouleS(x3,y3,RS,color='grey');b3S=bS # idem B3/Pupitre
- boule(x4,y4,R,color='blue');b4=b # Mise en place de la bille bleue commandant "effet" et "hauteur"
- boule(x5,y5,R,color='dark green');b5=b # Mise en place du cercle des commandant "orientation" et "vitesse"
- can.itemconfig(b5,outline='white') # couleur blanche pour le contour
- can.itemconfig(curseur4,fill='blue') # couleur blanche pour le contour
- can.itemconfig(curseur5,fill='white') # couleur blanche pour le contour
-
- if B1==1:fl(flèche1,o,x1,y1) # Mise en place de la flèche liée à B1
- if B3==1:fl(flèche3,o,x3,y3) # Mise en place de la flèche liée à B3
-
- def config():
- "Mise en place de la configuration courante"
- Cboule(b1,x1,y1,r);Cboule(b2,x2,y2,r);Cboule(b3,x3,y3,r) # nouvelles coordonnées de B1,B2,B3
- CbouleS(b1S,x1,y1,RS);CbouleS(b2S,x2,y2,RS);CbouleS(b3S,x3,y3,RS)# idem B1,B2,B3 /Pupitre
- Cboule(b4,x4,y4,R);Cboule(b5,x5,y5,R) # idem bille bleue et cercle blanc
- can.itemconfig(b4,fill='blue',outline='blue')
- can.itemconfig(b5,outline='white')
- can.itemconfig(curseur4,fill='blue')
- can.itemconfig(curseur5,fill='white')
- if continuer or passer:
- wo=round(float(o*180/pi),1);can.orientation.config(text='%s'%wo)
- wv=round(float(v),1);can.vitesse.config(text='%s'%wv)
- we=round(float(e*180/pi),1);can.effet.config(text='%s'%we)
- wha=round(float(ha),1);can.hauteur.config(text='%s'%wha)
- can.coords(curseur4,L/8,H+h/2+R4,L/8,H+h/2-R4)
- can.coords(curseur5,7*L/8-R,H+h/2,7*L/8-3*h/16+R/2,H+h/2)
- if rejouer:
- can.coords(curseur4,L/8+R4*cos(o4),H+h/2+R4*sin(o4),L/8-R4*cos(o4),H+h/2-R4*sin(o4))
- can.coords(curseur5,7*L/8+R*cos(o),H+h/2-R*sin(o),x5+R-R*cos(o),y5+R+R*sin(o))
- can.itemconfig(texte1,fill="white")
-
- def effet_choc(dxA,dyA,dxB,dyB):
- "Correction au choc pour tenir compte de l'effet latéral"
- global dxAE,dyAE,dxBE,dyBE,e
- e=(x4-L/8+R)*2/(R4-R)*pi/180
- dxAE=dxA*cos(e)+dyA*sin(e)
- dyAE=-dxA*sin(e)+dyA*cos(e)
- dxBE=dxB*cos(e)+dyB*sin(e)
- dyBE=-dxB*sin(e)+dyB*cos(e)
- we=round(float(e*180/pi),1)
- can.effet.config(text='%s'%we)
-
- def hauteur(dxA,dyA,dxB,dyB):
- "Correction au choc pour tenir compte de la hauteur du coup"
- global dxACR,dyACR,dxBCR,dyBCR,ha
- ha=-2*(y4-H-h/2+R)/(R4-R)
- dxACR=dxA*ha/10
- dyACR=dyA*ha/10
- dxBCR=dxB*abs(ha/10)
- dyBCR=dyB*abs(ha/10)
- wha=round(float(ha),1)
- can.hauteur.config(text='%s'%wha)
-
- def rebond_tir(x,y,dx,dy):
- "Rebond sur les bandes pour le premier tir"
- global xR,yR,dxR,dyR,RT,rt
- RT=1;rt+=1
- if rt==1:m=(x4-L/8+R)*2/(R4-R)*(1+(v-1)/20)
- else:m=0
- if x>L-2*r: # bande droite
- dxs,dys=dx+abs(m),dy+m
- xR,yR,dxR,dyR=L-2*r,y,-dxs*hypot(dx,dy)/hypot(dxs,dys)*n,dys*hypot(dx,dy)/hypot(dxs,dys)*n
- if y>H-2*r: # bande inférieure
- dxs,dys=dx-m,dy+abs(m)
- xR,yR,dxR,dyR=x,H-2*r,dxs*hypot(dx,dy)/hypot(dxs,dys)*n,-dys*hypot(dx,dy)/hypot(dxs,dys)*n
- if x<0: # bande gauche
- dxs,dys=dx-abs(m),dy-m
- xR,yR,dxR,dyR=0,y,-dxs*hypot(dx,dy)/hypot(dxs,dys)*n,dys*hypot(dx,dy)/hypot(dxs,dys)*n
- if y<0: # bande supérieure
- dxs,dys=dx+m,dy+abs(m)
- xR,yR,dxR,dyR=x,0,dxs*hypot(dx,dy)/hypot(dxs,dys)*n,-dys*hypot(dx,dy)/hypot(dxs,dys)*n
-
- def rebond_normal(x,y,dx,dy):
- "Rebond sur les bandes pour les coups suivants"
- global xR,yR,dxR,dyR,RN
- RN=1
- if x>L-2*r:xR,yR,dxR,dyR=L-2*r,y,-dx*n,dy*n # bande droite
- if y>H-2*r:xR,yR,dxR,dyR=x,H-2*r,dx*n,-dy*n # bande inférieur
- if x<0:xR,yR,dxR,dyR=0,y,-dx*n,dy*n # bande gauche
- if y<0:xR,yR,dxR,dyR=x,0,dx*n,-dy*n # bande supérieure
-
- def fl(flèche,a,x,y):
- "calcul de la longueur et mise en place de la flèche de tir"
- global xf,yf,lf
- SG=pi-atan(float(y+r)/float(x+r)) # le coin supérieur gauche du billard est vu par la boule sous l'angle SG
- SD=atan(float(y+r)/float(L-x-r)) # le coin supérieur droit du billard est vu par la boule sous l'angle SD
- ID=atan(-float(H-y-r)/float(L-x-r)) # le coin inférieur droit du billard est vu par la boule sous l'angle ID
- IG=-pi-atan(-float(H-y-r)/float(x+r)) # le coin inférieur gauche du billard est vu par la boule sous l'angle IG
- if a==0:lf=L-x-r # limitation de lf par la bande droite (cas limite)
- if a==pi or a==-pi:lf=x+r # limitation de lf par la bande gauche (cas limite)
- if a<SG and a>SD:lf=(y+r)/sin(a) # limitation de lf par la bande supérieure
- if a<=SD and a>ID:lf=(L-x-r)/cos(a) # limitation de lf par la bande droite
- if a<=ID and a>IG:lf=-(H-y-r)/sin(a) # limitation de lf par la bande inférieure
- if a>=SG and a<pi:lf=-(x+r)/cos(a) # limitation de lf par la bande gauche
- if a<IG and a>-pi:lf=-(x+r)/cos(a)
- xf,yf=x+r+lf*cos(a),y+r-lf*sin(a) # extrémité de la flèche sur la bande
- can.coords(flèche,x+r,y+r,xf,yf) # la flèche accompagne la boule pendant le déplacement
- if B1==1:can.itemconfig(flèche,fill='white')
- if B3==1:can.itemconfig(flèche,fill='grey')
-
- def sm(x,y,dx,dy):
- "Simulation du parcours de la boule tirée"
- global sim
- sim=can.create_line(3*h*x/2/L+L/2-3*h/4+RS,3*h*y/4/H+H+h/8+RS,3*h*(x+dx)/2/L+L/2-3*h/4+RS,3*h*(y+dy)/4/H+H+h/8+RS)
-
- def effacer_simulation():
- "effacer la trajectoire de la boule"
- global b1S,b2S,b3S
- REG66=can.create_rectangle(L/2-3*h/4,H+h/8,L/2+3*h/4,H+7*h/8,width=2,fill='dark green')
- bouleS(x1,y1,RS,color='white');b1S=bS # remise en place de B1/Pupitre
- bouleS(x2,y2,RS,color='red');b2S=bS # idem B2/Pupitre
- bouleS(x3,y3,RS,color='grey');b3S=bS # idem B3/Pupitre
-
- def effacer_texteR():
- "Effacement des textes liés au résultat du tir"
- can3.delete(texte1S);can3.delete(texte1E);can3.delete(texte3S);can3.delete(texte3E)
-
- def boule(x,y,r,color):
- "Coordonnées de la boule"
- global b
- b=can.create_oval(x,y,x+2*r,y+2*r,width=1,fill=color)
-
- def Cboule(b,x,y,r):
- "Coordonnées de la boule"
- can.coords(b,x,y,x+2*r,y+2*r)
-
- def bouleS(x,y,r,color):
- "Coordonnées de la boule"
- global bS
- X,Y=3*h*x/2/L+L/2-3*h/4,3*h*y/4/H+H+h/8 # changement de système de coordonnées (billard vers simulation)
- bS=can.create_oval(X,Y,X+2*RS,Y+2*RS,width=1,fill=color)
-
- def CbouleS(bS,x,y,r):
- "Coordonnées de la boule"
- X,Y=3*h*x/2/L+L/2-3*h/4,3*h*y/4/H+H+h/8 # changement de système de coordonnées (billard vers simulation)
- can.coords(bS,X,Y,X+2*RS,Y+2*RS)
-
- def presentation():
- "Fenêtre-message contenant la description sommaire du principe du jeu"
- msg =Toplevel()
- Message(msg, bg ="dark green", fg ="white", width =450,font ="Arial 8",
- text =" PRESENTATION\n\n"\
- "Au lancement du jeu, trois boules (BLANCHE, ROUGE et GRISE), apparaissent.La BLANCHE commence.\n\n"\
- "La première étape, si l'on souhaite un jeu différent, consiste à déplacer les boules (abscisses et ordonnées), vers de nouvelles positions.\n\n"\
- "La seconde vise à choisir la direction, la vitesse,l'effet latéral et la hauteur de tir de la boule BLANCHE.\n"\
- "Une flèche de tir apparait, dont la longueur est ajustée aux dimensions du billard.\n\n"\
- "Les boules étant en place, la touche <Tir !> met en mouvement la boule BLANCHE dans la direction choisie.\n"\
- "Aux premiers chocs, les autres boules se mettent à leur tour en mouvement.\n"\
- "La vitesse des boules se réduit à chaque itération, pour simuler le freinage du tapis, ainsi qu'à chaque choc (y/c avec les bandes).\n\n"\
- "A l' arrêt des boules, le score de la boule BLANCHE est comptabilisé.\n"\
- "En cas de succès, la BLANCHE gagne un point.Elle peut alors <Continuer !> ou <Rejouer le coup !> (pour améliorer les positions finales).\n"\
- "En cas d' échec, elle peut aussi rejouer le coup,et, sinon, <Passer la main !> à la GRISE.\n\n"\
- "La touche <Figer !> permet d'interrompre le mouvement à tout moment, et la touche <Relancer !> de le redémarrer.\n\n\n"\
- "ALGORITHME\n\n"\
- "Lorsque la boule BLANCHE approche, par exemple, de la boule GRISE, l'algorithme compare la distance entre leurs centres à la somme de leurs rayons.\n"\
- "Quand l'écart devient négatif, il y a intersection des deux contours.\n\n"\
- "L'algorithme calcule alors le recul en position des deux boules sur leurs directions initiales et en proportion de leurs vitesses, pour revenir au strict contact.\n\n"\
- "La sortie du choc, en direction et en vitesse, se fait ensuite selon les lois de la mécanique des chocs inélastiques entre solides.\n"\
- "Elle prend en compte (de façon très simplifiée) l'effet latéral et la hauteur de tir imprimés au moment du tir.\n\n"\
- "Un coefficient (n) de réduction de la vitesse intervient à chaque choc, y/c avec les bandes.\n"
- "Un ralentissement (k) a lieu également à chaque itération.\n").pack(padx =10, pady =10)
-
- def processus():
- ""
- msg =Toplevel()
- Message(msg, bg ="dark green", fg ="white", width =450,font ="Arial 8",
- text="PROCESSUS à suivre\n\n"\
- "1. Cliquer sur <Préparer le jeu !>\n\n"\
- "2. Régler vitesse et orientation\n"\
- "en déplaçant le cercle blanc\n"\
- "(réglage fin par clics successifs)\n\n"\
- "3. Régler effet latéral et hauteur\n"\
- "en déplaçant la bille bleue\n\n"\
- "4. Appuyer sur la touche <Tirer !>\n\n"\
- "5. En cas de succès, <Continuer !>\n"\
- "ou <Rejouer !> : pour améliorer\n\n"\
- "6. Si échec, <Passer la main !>\n"\
- "ou <Rejouer !>: pour réessayer\n\n"\
- "7. Possibilité de <Figer !> le mouvement\n"\
- "puis de <Relancer !>\n\n\n"\
- "Echelle du jeu:\n"\
- "Elle est peut être modifiée en\n"\
- "intervenant dans le menu <Règle du jeu>.\n"\
- "Valeurs possibles: de 0.5 à 1.0\n"\
- "(valeur actuelle=0.5)\n").pack(padx =10, pady =10)
-
- def aPropos():
- "Fenêtre-message indiquant l'auteur"
- msg =Toplevel()
- Message(msg, width =200, aspect =100, justify =CENTER,
- text ="Billard français \n\nHCD, Octobre 2005.\n"\
- "Python version 2.4.2\nTk version 8.4").pack(padx =10, pady =10)
-
- def scale(E):
- "Changement d'échelle"
- global L,H,h,r,rr,R,R4,R6,RS
- global x1,y1,x2,y2,x3,y3
- global x4o,y4o,x5o,y5o,x4,y4,x5,y5
- E=float(E)
- L,H,h,r,rr,R,R4,R6,RS=E*L,E*H,E*h,E*r,E*rr,E*R,E*R4,E*R6,E*RS
- x1,y1,x2,y2,x3,y3=E*x1,E*y1,E*x2,E*y2,E*x3,E*y3
- can.config(height=H+h,width=L)
- can2.config(width=h)
- can3.config(height=h/3,width=h)
- x4o,y4o,x5o,y5o=E*x4o,E*y4o,E*x5o,E*y5o
- x4,y4,x5,y5=E*x4,E*y4,E*x5,E*y5
- can.coords(Pupitre,E*4,H,L,H+h)
- can.coords(texte,E*L/2,E*L/3)
- can.coords(t1,L/8,H+h-E*10)
- can.coords(t2,L/2,H+h-E*10)
- can.coords(t3,7*L/8,H+h-E*10)
- can.coords(texte1,L/2,H+E*7.5)
- can.coords(texte2,L/8,H+E*7.5)
- can.coords(texte3,7*L/8,H+E*7.5)
- can.coords(REG4,L/8-R4,H+h/2-R4,L/8+R4,H+h/2+R4)
- can.coords(curseur4,L/8,H+h/2+R4,L/8,H+h/2-R4)
- can.coords(REG6,L/2-3*h/4,H+h/8,L/2+3*h/4,H+7*h/8)
- can.coords(REG5,7*L/8-R6,H+h/2-R6,7*L/8+R6,H+h/2+R6)
- can.coords(REG5B,7*L/8-R,H+h/2-R,7*L/8+R,H+h/2+R)
- can.coords(curseur5,7*L/8-R,H+h/2,7*L/8-3*h/16+R/2,H+h/2)
- can.coords(pA,L/4-rr,H/2-rr,L/4+rr,H/2+rr)
- can.coords(pB,L/2-rr,H/2-rr,L/2+rr,H/2+rr)
- can.coords(pC,3*L/4-rr,H/2-rr,3*L/4+rr,H/2+rr)
- can.coords(pD,3*L/4-rr,H/3-rr,3*L/4+rr,H/3+rr)
- can.coords(pE,3*L/4-rr,2*H/3-rr,3*L/4+rr,2*H/3+rr)
- can3.coords(texte1S,2*h/3,h/4)
- can3.coords(texte1E,2*h/3,h/4)
- can3.coords(texte3S,2*h/3,h/4)
- can3.coords(texte3E,2*h/3,h/4)
- EE=1.0
-
- def echelle():
- "Choix de l'échelle"
- éch=Toplevel()
- curE=Scale(éch,length=200,label="Echelle du jeu",orient=HORIZONTAL,from_=0.95,to=1.05,resolution=0.05,command=scale)
- curE.set(1.0) # position initiale du curseur
- curE.pack()
-
- ######## Programme principal ############################################
-
- # Création du widget principal :
- root = Tk()
- root.title('>>>>>>> BILLARD <<<<<<<')
-
- # données initiales:
- flag=0 # compteur
-
- # Billard
-
- L=600 # longueur du billard
- H=L/2 # largeur du billard
- r,rr=10,1 # rayons des boules et des marques du tapis
- k,s=0.996,0.5 # coefficient de freinage du tapis, vitesse d'arrêt du mouvement
- n=0.8 # coefficient de réduction de la vitesse lors d'un choc
- x1,y1,x2,y2,x3,y3=3*L/4-r,H/2-r,L/2-r,H/2-r,L/4-r,H/2-r # coordonnées courantes des boules
- dx1,dy1,dx2,dy2,dx3,dy3=0,0,0,0,0,0 # composantes courantes des vecteurs vitesse des boules
- c12,c23,c31=0,0,0 # compteurs de choc
- point1,point3,score1,score3=0,0,0,0 # compteurs de point et de score
- R1,R3,T1,T3,PM1,PM3,CT1,CT3=0,0,0,0,0,0,0,0 # indicateurs (rejouer,tirer,passer la main,continuer)
- RN1,RN3,RT1,RT3=0,0,0,0 # indicateurs de rebond sur les bandes et après choc
- j,j1,j3,t1,t3,r1,r3,rt,t=0,0,0,0,0,0,0,0,0 # compteurs de lancements de jeux et de tirs
- texte1E,texte1S,texte3E,texte3S=0,0,0,0
- S1,S3,E1,E3=0,0,0,0 # résultats (S=succès,E=échec)
- e,ha,o,v,o4=0,0,pi,8,pi/2 # réglages initiaux
- figer=0
- tA=0
-
- # Pupitre de réglage du tir
- h=H/2 # hauteur du pupitre de réglage
- R,R4,R6,RS=4,25,3*h/8,3*h*r/4/H # rayons du système de réglage
- x4o,y4o,x5o,y5o=L/8-R,H+h/2-R,7*L/8-3*h/16-3*R/2,H+h/2-R
- x4,y4,x5,y5=L/8-R,H+h/2-R,7*L/8-3*h/16-3*R/2,H+h/2-R
-
- # création des widgets "dépendants" :
- can=Canvas(root,bg='dark green',height=H+h,width=L,highlightbackground='brown')
- can.grid(row=1,column=0,rowspan=2)
- can2=Canvas(root,bg='brown',highlightbackground='brown')
- can2.grid(row=1,column=1,sticky=N)
- can3=Canvas(root,bg='white',height=h/3,width=h)
- can3.grid(row=2,column=1,padx=0,pady=0,ipadx=10,ipady=10,sticky=N+S)
-
- # Pupitre de commande
- Pupitre=can.create_rectangle(4,H,L,H+h,width=2,fill='brown')
- t1=can.create_text(L/8,H+h-10,text='Effet et hauteur de tir',fill="white")
- t2=can.create_text(L/2,H+h-10,text='Simulation',fill="white")
- t3=can.create_text(7*L/8,H+h-10,text='Vitesse et orientation de tir',fill="white")
- texte1=can.create_text(L/2,H+7.5,text='Régler le tir, puis "Tirer !"',fill="white")
- texte2=can.create_text(L/8,H+7.5,text='Déplacer la bille bleue',fill="white")
- texte3=can.create_text(7*L/8,H+7.5,text='Déplacer le cercle blanc',fill="white")
- REG4=can.create_oval(L/8-R4,H+h/2-R4,L/8+R4,H+h/2+R4,width=1,fill='white')
- curseur4=can.create_line(L/8,H+h/2+R4,L/8,H+h/2-R4,width=1,fill='white')
- REG6=can.create_rectangle(L/2-3*h/4,H+h/8,L/2+3*h/4,H+7*h/8,width=2,fill='dark green')
- REG5=can.create_oval(7*L/8-R6,H+h/2-R6,7*L/8+R6,H+h/2+R6,width=1,fill='dark green')
- REG5B=can.create_oval(7*L/8-R,H+h/2-R,7*L/8+R,H+h/2+R,width=1,fill='white')
- curseur5=can.create_line(7*L/8-R,H+h/2,7*L/8-3*h/16+R/2,H+h/2,width=1,fill='dark green',arrow=LAST)
-
- # création des cinq points gris sur le tapis et des deux flèches
- pA=can.create_oval(L/4-rr,H/2-rr,L/4+rr,H/2+rr,width=0,fill='light grey')
- pB=can.create_oval(L/2-rr,H/2-rr,L/2+rr,H/2+rr,width=0, fill='light grey')
- pC=can.create_oval(3*L/4-rr,H/2-rr,3*L/4+rr,H/2+rr,width=0,fill='light grey')
- pD=can.create_oval(3*L/4-rr,H/3-rr,3*L/4+rr,H/3+rr,width=0,fill='light grey')
- pE=can.create_oval(3*L/4-rr,2*H/3-rr,3*L/4+rr,2*H/3+rr,width=0,fill='light grey')
- flèche1=can.create_line(0,0,0,0,arrow=LAST)
- flèche3=can.create_line(0,0,0,0,arrow=LAST)
-
- # Message d'introduction
- texte=can.create_text(L/2,L/3,text='Cliquer sur le bouton "Règle du jeu"\n\nou\n\ndirectement sur "Préparer le jeu"',fill="white")
-
- # Menu <Règle du jeu>
- RdJ = Menubutton(can2, text ='Règle du jeu',height=2,width=25,relief=GROOVE,bg="dark green",fg="white")
- RdJ.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
- me1 = Menu(RdJ)
- me1.add_command(label='Présentation',underline=0,command=presentation)
- me1.add_command(label='Processus',underline=0,command=processus)
- me1.add_command(label='Echelle',underline=0,command=echelle)
- me1.add_command(label='A propos ...',underline=0,command=aPropos)
- RdJ.configure(menu=me1)
-
- # Affichage des réglages et des scores:
-
- # hauteur:
- can.hauteur=Label(can2,text='0',fg='white',bg='brown')
- can.hauteur.pack(side=BOTTOM)
- Label(can2,text="hauteur",fg='white',bg='brown').pack(side=BOTTOM)
- # effet:
- can.effet=Label(can2,text='0',fg='white',bg='brown')
- can.effet.pack(side=BOTTOM)
- Label(can2,text="effet",fg='white',bg='brown').pack(side=BOTTOM)
- # vitesse:
- can.vitesse=Label(can2,text='0',fg='white',bg='brown')
- can.vitesse.pack(side=BOTTOM)
- Label(can2,text="vitesse",fg='white',bg='brown').pack(side=BOTTOM)
- # orientation:
- can.orientation=Label(can2,text='0',fg='white',bg='brown')
- can.orientation.pack(side=BOTTOM)
- Label(can2,text="orientation",fg='white',bg='brown').pack(side=BOTTOM)
- # Score B3:
- can.score3=Label(can2,text='0',fg='white',bg='brown')
- can.score3.pack(side=BOTTOM)
- Label(can2,text="score GRISE",fg='white',bg='brown').pack(side=BOTTOM)
- # Score B1:
- can.score1=Label(can2,text='0',fg='white',bg='brown')
- can.score1.pack(side=BOTTOM)
- Label(can2,text="score BLANCHE",fg='white',bg='brown').pack(side=BOTTOM)
-
- # Boutons de commande
-
- # 'Continuer ?':
- CT=Button(can2,text='Continuer? ',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=continuer)
- CT.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
- CT.pack_forget()
- # 'Passer la main ?':
- PM=Button(can2,text='Passer la main? ',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=passer)
- PM.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
- PM.pack_forget()
- # 'Rejouer le coup ?':
- RJ=Button(can2,text='Rejouer le coup ?',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=rejouer)
- RJ.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
- RJ.pack_forget()
- # bouton d'arrêt du mouvement:
- FI=Button(can2,text='Figer le mouvement',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=stop)
- FI.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
- FI.pack_forget()
- # bouton de redémarrage du mouvement:
- RL=Button(can2,text='Relancer le mouvement',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=go)
- RL.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
- RL.pack_forget()
- # 'Tirer !':
- T=Button(can2,text='Tirer !',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=tirer)
- T.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
- T.pack_forget()
- # 'Préparer le tir !':
- J=Button(can2,text='Préparer le jeu !',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=jouer)
- J.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
-
- root.mainloop()
-
#! /usr/bin/env python
# -*- coding: Latin-1 -*-
# <<< Billard >>>
# REMERCIEMENTS : ce projet est très largement inspiré des exemples fournis par Mr Gérard Swinnen dans la deuxième édition de son ouvrage intitulé "Apprendre à programmer avec Python".
from Tkinter import *
from math import *
# CONVENTIONS
# boule BLANCHE....(coordonnées:x1,y1):B1
# boule ROUGE......(coordonnées:x2,y2):B2
# boule GRISE......(coordonnées:x3,y3):B3
# bille bleue......(coordonnées:x4,y4):b4(Réglage de l'effet latéral et de la hauteur de tir)
# cercle blanc.....(coordonnées:x5,y5):b5(Réglage de l'orientation et de la vitesse de tir)
# pupitre de simulation : indice "S"
########## Commande "préparer le jeu" ####################################
def jouer():
"Préparer le jeu"
global flag,texte
if flag==0:flag=1
jouer;config_init() # mise en place de la configuration initiale (boules,flèches,réglages)
can.bind("<Button-1>", mouseDown) # commandes avec le clic gauche de la souris
can.bind("<Button1-Motion>", mouseMove)
can.bind("<Button1-ButtonRelease>", mouseUp)
T.pack(),J.pack_forget() # gestion des boutons de commande
can.delete(texte)
########## Commandes de réglage du tir ###################################
def mouseDown( event):
"Opérations à effectuer quand le bouton gauche de la souris est enfoncé"
global selObject,X,Y,x5,y5,v,o
can.currObject=None
X,Y=event.x,event.y # coordonnées du clic
D1=hypot(X-x1-r,Y-y1-r) # distance entre le clic et le centre de B1
D2=hypot(X-x2-r,Y-y2-r) # idem B2
D3=hypot(X-x3-r,Y-y3-r) # idem B3
D4=hypot(X-x4-R,Y-y4-R) # idem bille bleue
D5=hypot(X-x5-R,Y-y5-R) # idem cercle blanc
X5,Y5=x5-7L/8+R,y5-H-h/2+R
H5=hypot(X5,Y5)
if D1<r:selObject=b1 # sélection de B1 si le clic est à l'intérieur de B1
if D2<r:selObject=b2 # idem B2
if D3<r:selObject=b3 # idem B3
if D4<R:selObject=b4 # idem bille bleue
if D5<4*R:selObject=b5 # plage de sélection du cercle blanc: cercle de rayon 4R
if selObject==b5: # procédure de réglage fin, par clic sussessifs à proximité
dx,dy=(X-x5-R)/40,(Y-y5-R)/40 # pas = 1/40 ème de la distance du clic au centre du cercle
x5,y5=x5+dx,y5+dy
can.move(selObject,dx,dy) # déplacement du cercle blanc
C5=can.coords(b5)
x5,y5=C5[0],C5[1]
o=-atan2(y5-H-h/2+R,x5-7*L/8+R) # récupération de l'angle de tir (o)
wo=round(float(o*180/pi),1)
can.orientation.config(text='%s'%wo) # valeur d'affichage de (o)
v=1+14*hypot(x5+R-7*L/8-2*R*cos(o),y5+R-H-h/2+2*R*sin(o))/(3*h/8-3*R) # récupération de la vitessede tir (v)
wv=round(float(v),1)
can.vitesse.config(text='%s'%wv) # valeur d'affichage de (v)
if B1==1:fl(flèche1,o,x1,y1)
if B3==1:fl(flèche3,o,x3,y3)
can.coords(curseur5,7*L/8+R*cos(o),H+h/2-R*sin(o),x5+R-R*cos(o),y5+R+R*sin(o))
can.itemconfig(selObject,width=2) # le contour de l'objet sélectionné double d'épaisseur
def mouseMove(event):
"Opérations à effectuer quand la souris se déplace, bouton gauche enfoncé"
global O,X,Y
global x1,y1,x2,y2,x3,y3,x4,y4,x5,y5
global e,ha,v,o,o4
XX,YY=event.x,event.y
dx,dy=XX-X,YY-Y
if selObject==b1:
if dx+x1>0 and dx+x1<L-2*r and dy+y1>0 and dy+y1<H-2*r:
can.move(selObject,dx,dy);X,Y=XX,YY # déplacement de B1
C1=can.coords(b1)
x1,y1=C1[0],C1[1] # récupération des coordonnées du coin supérieur gauche
if B1==1:fl(flèche1,pi,x1,y1) # déplacement de la flèche de B1
if selObject==b2 :
if dx+x2>0 and dx+x2<L-2*r and dy+y2>0 and dy+y2<H-2*r:
can.move(selObject,dx,dy);X,Y=XX,YY # déplacement de B2
C2=can.coords(b2)
x2,y2=C2[0],C2[1]
if selObject==b3 :
if dx+x3>0 and dx+x3<L-2*r and dy+y3>0 and dy+y3<H-2*r:
can.move(selObject,dx,dy);X,Y=XX,YY # déplacement de B3
C3=can.coords(b3)
x3,y3=C3[0],C3[1]
if B3==1:fl(flèche3,pi,x3,y3) # déplacement de la flèche de B3
if selObject==b4:
DX4,DY4=dx+x4-L/8+R,dy+y4-H-h/2+R
HD4=hypot(DX4,DY4)
if HD4<R4-R:
can.move(selObject,dx,dy);X,Y=XX,YY # déplacement de la bille bleue
C4=can.coords(b4)
x4,y4=C4[0],C4[1]
o4=atan2(DY4,DX4)
e=(x4-L/8+R)*2/(R4-R)*pi/180 # calcul de l'effet (-2<e<+2)
we=round(float(e*180/pi),1);can.effet.config(text='%s'%we)
ha=-2*(y4-H-h/2+R)/(R4-R) # calcul de la hauteur (-2<h<+2)
wha=round(float(ha),1);can.hauteur.config(text='%s'%wha)
can.coords(curseur4,L/8+R4*cos(o4),H+h/2+R4*sin(o4),L/8-R4*cos(o4),H+h/2-R4*sin(o4))
if selObject==b5:
DX5,DY5=dx+x5-7*L/8+R,dy+y5-H-h/2+R
HD5=hypot(DX5,DY5)
if HD5<3*h/8-R and HD5>2*R:
can.move(selObject,dx,dy);X,Y=XX,YY # déplacement du cercle blanc dans l'espace d'orientation et de vitesse
C5=can.coords(b5)
x5,y5=C5[0],C5[1]
o=-atan2(y5-H-h/2+R,x5-7*L/8+R) # récupération de l'angle de tir (o)
wo=round(float(o*180/pi),1)
can.orientation.config(text='%s'%wo)
v=1+14*hypot(x5+R-7*L/8-2*R*cos(o),y5+R-H-h/2+2*R*sin(o))/(3*h/8-3*R)# récupération de la vitesse de tir (v)
wv=round(float(v),1)
can.vitesse.config(text='%s'%wv)
can.coords(curseur5,7*L/8+R*cos(o),H+h/2-R*sin(o),x5+R-R*cos(o),y5+R+R*sin(o))
if B1==1:fl(flèche1,o,x1,y1)
if B3==1:fl(flèche3,o,x3,y3)
def mouseUp(event):
"Opérations à effectuer quand le bouton gauche de la souris est relâché"
global selObject
can.itemconfig(selObject,width=1) # le contour de l'objet sélectionné revient à son épaisseur initiale
if selObject==b1:selObject=None
if selObject==b2:selObject=None
if selObject==b3:selObject=None
if selObject==b4:selObject=None
if selObject==b5:selObject=None
########## Commande "tirer" ##############################################
def tirer():
"tirer "
global T1,T3,t1,t3,S1,S3,E1,E3,R1,R3,PM1,PM3
global x1,y1,x3,y3,dx1,dy1,dx3,dy3
global xx1,yy1,xx2,yy2,xx3,yy3
global dxx1,dyy1,dxx2,dyy2,dxx3,dyy3
global xx4,yy4,xx5,yy5
global ee,hh,oo,vv,oo4
if B1==1:
T1=1;t1+=1 # indicateur et compteur de tir
dx1,dy1=v*cos(o),-v*sin(o) # coordonnées du vecteur vitesse
can.coords(flèche1,x1+r,y1+r,x1+r,y1+r) # origine de la flèche
can.itemconfig(b4,fill='white',outline='white') # effacement de la bille bleue
can.itemconfig(curseur4,fill='white') # effacement du diamètre de la bille bleue
if B3==1:
T3=1;t3+=1
dx3,dy3=v*cos(o),-v*sin(o)
can.coords(flèche3,x3+r,y3+r,x3+r,y3+r) # idem
can.itemconfig(b4,fill='grey',outline='grey') # idem
can.itemconfig(curseur4,fill='grey')
xx1,yy1,xx2,yy2,xx3,yy3=x1,y1,x2,y2,x3,y3 # mémorisation de la position des trois boules
dxx1,dyy1,dxx2,dyy2,dxx3,dyy3=dx1,dy1,dx2,dy2,dx3,dy3 # mémorisation de la vitesse des trois boules
xx4,yy4,xx5,yy5=x4,y4,x5,y5 # mémorisation de la position de la bille et du cercle
ee,hh,oo,vv,oo4=e,ha,o,v,o4 # mémorisation des réglages du tir
S1,S3,E1,E3,R1,R3,PM1,PM3,CT1,CT3=0,0,0,0,0,0,0,0,0,0 # mise à zéro des indicateurs
T.pack_forget();FI.pack() # gestion des boutons de commande
can.itemconfig(texte1,fill="brown")
can.delete(texte2);can.delete(texte3)
can.itemconfig(b5,outline='dark green') # effacement du cercle blanc
can.itemconfig(curseur5,fill='dark green') # effacement de la flèche
move() # appel de la fonction "mouvement" des boules
###### Commandes "continuer/rejouer/passer la main/figer/relancer" #######
def continuer():
"continuer"
global flag,CT1,CT3,B1,B3
global x1,y1,x2,y2,x3,y3,x4,y4,x5,y5
global e,ha,o,v,o4,o6
if flag==0:flag=1
e,ha,o,v,o4=0,0,pi,8,pi/2 # réglages de départ
x4,y4,x5,y5=x4o,y4o,x5o,y5o # coordonnées de départ de la bille et du cercle
effacer_simulation()
continuer;config() # mise en place de la configuration
if S1==1:CT1=1;B1,B3=1,0;fl(flèche1,o,x1,y1)
if S3==1:CT3=1;B1,B3=0,1;fl(flèche3,o,x3,y3)
T.pack();CT.pack_forget();RJ.pack_forget()
effacer_texteR()
def rejouer():
"rejouer le coup"
global flag,R1,R3,r1,r3
global x1,y1,x2,y2,x3,y3
global e,ha,o,v,o4
if flag==0:flag=1
e,ha,o,v,o4 =ee,hh,oo,vv,oo4 # récupération des réglages avant tir
x1,y1,x2,y2,x3,y3=xx1,yy1,xx2,yy2,xx3,yy3 # récupération des positions avant tir des boules
x4,y4,x5,y5=xx4,yy4,xx5,yy5 # récupération des positions avant tir de la bille et du cercle
rejouer;config() # mise en place de la configuration
if B1==1 :R1=1;fl(flèche1,o,x1,y1);r1+=1
if B3==1 :R3=1;fl(flèche3,o,x3,y3);r3+=1
T.pack();RJ.pack_forget();PM.pack_forget();CT.pack_forget()
effacer_texteR()
def passer():
"passer la main"
global flag,PM1,PM3,B1,B3
global x1,y1,x2,y2,x3,y3,x4,y4,x5,y5
global e,ha,o,v,o4
if flag==0:flag=1
e,ha,o,v,o4=0,0,pi,8,pi/2 # réglages de départ
x4,y4,x5,y5=x4o,y4o,x5o,y5o # coordonnées de départ de la bille et du cercle
effacer_simulation()
passer;config() # mise en place de la configuration
if E1==1:PM1=1;B1,B3=0,1;fl(flèche3,o,x3,y3) # changement de boule (B3 prend la main)
if E3==1:PM3=1;B1,B3=1,0;fl(flèche1,o,x1,y1)
if B3==1:can.itemconfig(REG4,fill='grey');can.itemconfig(REG5B,fill='grey')
if B1==1:can.itemconfig(REG4,fill='white');can.itemconfig(REG5B,fill='white')
T.pack();RJ.pack_forget();PM.pack_forget();CT.pack_forget()
effacer_texteR()
def stop():
"Figer le jeu"
global flag,figer
figer=1;flag=0
dxx1,dyy1,dxx2,dyy2,dxx3,dyy3=dx1,dy1,dx2,dy2,dx3,dy3 # mémorisation de la vitesse des trois boules
RL.pack();FI.pack_forget()
def go():
"Relancer le jeu"
global flag,figer
flag=1;figer=0
dx1,dy1,dx2,dy2,dx3,dy3=dxx1,dyy1,dxx2,dyy2,dxx3,dyy3 # récupération de la vitesse avant arrêt des trois boules
FI.pack();RL.pack_forget();RJ.pack_forget();PM.pack_forget()
move() # redémarrage du mouvement d'ensemble
########## Commande "score" ##############################################
def score():
"Détermination du score"
global score1,score3,texte1S,texte1E,texte3S,texte3E,S1,S3,E1,E3
if B1==1:
if figer==1:RJ.pack_forget();PM.pack_forget()
else:
if point1==1:
S1=1;score1+=1 # Constat de succès : le score de B1 augmente d'un point
texte1S=can3.create_text(2*h/3,h/4,text='La BLANCHE continue\nou\nrejoue le coup',fill ="red",font ="Arial 8")
CT.pack();RJ.pack();FI.pack_forget()
if point1==0:
E1=1;score1+=0 # Constat d'échec
texte1E=can3.create_text(2*h/3,h/4,text='La BLANCHE rejoue le coup\nou\npasse la main',fill ="red",font ="Arial 8")
RJ.pack();PM.pack();FI.pack_forget()
if R1==1:score1+=-1
can.score1.config(text='%s'%score1)
if B3==1:
if figer==1:RJ.pack_forget();PM.pack_forget()
else:
if point3==1:
S3=1;score3+=1
texte3S=can3.create_text(2*h/3,h/4,text='La GRISE continue\nou\nrejoue le coup',fill ="red",font ="Arial 8")
CT.pack();RJ.pack();FI.pack_forget()
if point3==0:
E3=1;score3+=0
texte3E=can3.create_text(2*h/3,h/4,text='La GRISE rejoue le coup\nou\npasse la main',fill ="red",font ="Arial 8")
RJ.pack();PM.pack();FI.pack_forget()
if R3==1:score3+=-1
can.score3.config(text='%s'%score3)
########## Fonction "mouvement" ##########################################
def move():
"mouvement des trois boules au fur et à mesure des chocs"
global flag
global x1,y1,x2,y2,x3,y3
global dx1,dy1,dx2,dy2,dx3,dy3
global c12,c23,c31,point1,point3
global T1,T3,RT1,RT3,RN1,RN3,rt
global sim1,sim3
x1,y1,x2,y2,x3,y3=x1+dx1,y1+dy1,x2+dx2,y2+dy2,x3+dx3,y3+dy3 # création du mouvement
dx1,dy1,dx2,dy2,dx3,dy3=k*dx1,k*dy1,k*dx2,k*dy2,k*dx3,k*dy3 # freinage du tapis (k)
if hypot(dx1,dy1)<s:dx1,dy1=0,0 # arrêt de B1 lorsque la vitesse de B1 devient trop faible (<s)
if hypot(dx2,dy2)<s:dx2,dy2=0,0 # idem B2
if hypot(dx3,dy3)<s:dx3,dy3=0,0 # idem B3
X12,Y12,X23,Y23,X31,Y31=x2-x1,y2-y1,x3-x2,y3-y2,x1-x3,y1-y3
Z12,Z23,Z31=hypot(X12,Y12),hypot(X23,Y23),hypot(X31,Y31)
dx12,dy12,dx23,dy23,dx31,dy31=dx2-dx1,dy2-dy1,dx3-dx2,dy3-dy2,dx1-dx3,dy1-dy3
dz12,dz23,dz31=hypot(dx12,dy12),hypot(dx23,dy23),hypot(dx31,dy31)
k12,K12,k23,K23,k31,K31=dz12*dz12,X12*dx12+Y12*dy12,dz23*dz23,X23*dx23+Y23*dy23,dz31*dz31,X31*dx31+Y31*dy31
u12,u23,u31=Z12-2*r,Z23-2*r,Z31-2*r
# Choc de B1 sur B2 :
if u12<=0: # la distance entre centres est <= à la somme des rayons
# algorithme de recul des deux boules :
c12+=1 # compteur de chocs B1/B2
m12=(K12+sqrt(K12*K12-k12*(Z12*Z12-4*r*r)))/k12
x1,y1,x2,y2=x1-m12*dx1,y1-m12*dy1,x2-m12*dx2,y2-m12*dy2 # recul des deux boules sur leurs directions initales
# algorithme de modification des vecteurs vitesse après le choc:
A12,B12,C12,D12=(X12*dx1+Y12*dy1)/Z12,(-Y12*dx1+X12*dy1)/Z12,(X12*dx2+Y12*dy2)/Z12,(-Y12*dx2+X12*dy2)/Z12
dx1,dy1,dx2,dy2=(-Y12*B12+X12*C12)/Z12,(X12*B12+Y12*C12)/Z12,(-Y12*D12+X12*A12)/Z12,(X12*D12+Y12*A12)/Z12
if T1==1 or T3==1 and RT1==0 and RN1 ==0:
effet_choc(dx1,dy1,dx2,dy2)
dx1,dy1,dx2,dy2=dxAE,dyAE,dxBE,dyBE # vitesse corrigée de l'effet
if B1==1 or B3==1 and c12==1:
hauteur(dxx1,dyy1,dxx2,dyy2) # vitesse corrigée de la hauteur de tir
dx1,dy1,dx2,dy2=dx1+dxACR,dy1+dyACR,dx2+dxBCR,dy2+dyBCR
# Choc de B2 sur B3 :
if u23<=0:
c23+=1 # compteur de chocs B2/B3
m23=(K23+sqrt(K23*K23-k23*(Z23*Z23-4*r*r)))/k23
x2,y2,x3,y3=x2-m23*dx2,y2-m23*dy2,x3-m23*dx3,y3-m23*dy3
A23,B23,C23,D23=(X23*dx2+Y23*dy2)/Z23,(-Y23*dx2+X23*dy2)/Z23,(X23*dx3+Y23*dy3)/Z23,(-Y23*dx3+X23*dy3)/Z23
effet_choc(dx2,dy2,dx3,dy3)
dx2,dy2,dx3,dy3=dxAE,dyAE,dxBE,dyBE
dx2,dy2,dx3,dy3=(-Y23*B23+X23*C23)/Z23,(X23*B23+Y23*C23)/Z23,(-Y23*D23+X23*A23)/Z23,(X23*D23+Y23*A23)/Z23
if B3==1 and c23==1:
hauteur(dxx3,dyy3,dxx2,dyy2)
dx3,dy3,dx2,dy2=dx3+dxACR,dy3+dyACR,dx2+dxBCR,dy2+dyBCR
# Choc de B3 sur B1 :
if u31<=0:
c31+=1 # compteur de chocs B3/B1
m31=(K31+sqrt(K31*K31-k31*(Z31*Z31-4*r*r)))/k31
x3,y3,x1,y1=x3-m31*dx3,y3-m31*dy3,x1-m31*dx1,y1-m31*dy1
A31,B31,C31,D31=(X31*dx3+Y31*dy3)/Z31,(-Y31*dx3+X31*dy3)/Z31,(X31*dx1+Y31*dy1)/Z31,(-Y31*dx1+X31*dy1)/Z31
dx3,dy3,dx1,dy1=(-Y31*B31+X31*C31)/Z31,(X31*B31+Y31*C31)/Z31,(-Y31*D31+X31*A31)/Z31,(X31*D31+Y31*A31)/Z31
if T3==1 or T1==1 and RT3==0 and RN3==0:
effet_choc(dx3,dy3,dx1,dy1)
dx3,dy3,dx1,dy1=dxAE,dyAE,dxBE,dyBE
if B3==1 or B3==1 and c31==1:
hauteur(dxx3,dyy3,dxx1,dyy1)
dx3,dy3,dx1,dy1=dx3+dxACR,dy3+dyACR,dx1+dxBCR,dy1+dyBCR
if c12*c31>0:point1=1 # succès=1 point
else:point1=0 # échec
if c23*c31>0:point3=1
else:point3=0
if x1>L-2*r or x1<0 or y1>H-2*r or y1<0: # Rebonds de la BLANCHE sur les bandes:
if T1==1 and c12==0 and c31==0:
rebond_tir(x1,y1,dx1,dy1)
x1,y1,dx1,dy1,RT1=xR,yR,dxR,dyR,RT
else :
rebond_normal(x1,y1,dx1,dy1)
x1,y1,dx1,dy1,RN1=xR,yR,dxR,dyR,RN
T1=0
if x2>L-2*r or x2<0 or y2>H-2*r or y2<0: # Rebonds de la ROUGE sur les bandes:
rebond_normal(x2,y2,dx2,dy2)
x2,y2,dx2,dy2=xR,yR,dxR,dyR
if x3>L-2*r or x3<0 or y3>H-2*r or y3<0: # Rebonds de la GRISE sur les bandes:
if T3==1 and c31==0 and c23==0:
rebond_tir(x3,y3,dx3,dy3)
x3,y3,dx3,dy3,RT3=xR,yR,dxR,dyR,RT
T3=0
else:
rebond_normal(x3,y3,dx3,dy3)
x3,y3,dx3,dy3,RN3=xR,yR,dxR,dyR,RN
Cboule(b1,x1,y1,r);Cboule(b2,x2,y2,r);Cboule(b3,x3,y3,r) # Nouvelles coordonnées de B1,B2,B3
CbouleS(b1S,x1,y1,RS);CbouleS(b2S,x2,y2,RS);CbouleS(b3S,x3,y3,RS)
if B1==1:sm(x1,y1,dx1,dy1);sim1=sim;can.itemconfig(sim1,fill='white')
if B3==1:sm(x3,y3,dx3,dy3);sim3=sim;can.itemconfig(sim3,fill='grey')
# Algorithmes à l'arrêt des trois boules
if flag==0:
c12+=-c12 # mise à zéro des compteurs de choc
c23+=-c23
c31+=-c31
score() # appel de la commande "score"
rt=0
if flag>0:
root.after(10,move) # déclenchement du mouvement des boules et des flèches
if dx1==0 and dy1==0 and dx2==0 and dy2==0 and dx3==0 and dy3==0:flag=0 # arrêt complet
########## Procédures diverses ###########################################
def config_init():
"Mise en place de la configuration de départ (à partir des 'données initiales)"
global B1,B3,b1,b2,b3,b4,b5,b1S,b2S,b3S
B1,B3=1,0 # Sélection de la boule à tirer (B1)
boule(x1,y1,r,color='white');b1=b # Mise en place de B1
boule(x2,y2,r,color='red');b2=b # idem B2
boule(x3,y3,r,color='grey');b3=b # idem B3
bouleS(x1,y1,RS,color='white');b1S=bS # idem B1/Pupitre
bouleS(x2,y2,RS,color='red');b2S=bS # idem B2/Pupitre
bouleS(x3,y3,RS,color='grey');b3S=bS # idem B3/Pupitre
boule(x4,y4,R,color='blue');b4=b # Mise en place de la bille bleue commandant "effet" et "hauteur"
boule(x5,y5,R,color='dark green');b5=b # Mise en place du cercle des commandant "orientation" et "vitesse"
can.itemconfig(b5,outline='white') # couleur blanche pour le contour
can.itemconfig(curseur4,fill='blue') # couleur blanche pour le contour
can.itemconfig(curseur5,fill='white') # couleur blanche pour le contour
if B1==1:fl(flèche1,o,x1,y1) # Mise en place de la flèche liée à B1
if B3==1:fl(flèche3,o,x3,y3) # Mise en place de la flèche liée à B3
def config():
"Mise en place de la configuration courante"
Cboule(b1,x1,y1,r);Cboule(b2,x2,y2,r);Cboule(b3,x3,y3,r) # nouvelles coordonnées de B1,B2,B3
CbouleS(b1S,x1,y1,RS);CbouleS(b2S,x2,y2,RS);CbouleS(b3S,x3,y3,RS)# idem B1,B2,B3 /Pupitre
Cboule(b4,x4,y4,R);Cboule(b5,x5,y5,R) # idem bille bleue et cercle blanc
can.itemconfig(b4,fill='blue',outline='blue')
can.itemconfig(b5,outline='white')
can.itemconfig(curseur4,fill='blue')
can.itemconfig(curseur5,fill='white')
if continuer or passer:
wo=round(float(o*180/pi),1);can.orientation.config(text='%s'%wo)
wv=round(float(v),1);can.vitesse.config(text='%s'%wv)
we=round(float(e*180/pi),1);can.effet.config(text='%s'%we)
wha=round(float(ha),1);can.hauteur.config(text='%s'%wha)
can.coords(curseur4,L/8,H+h/2+R4,L/8,H+h/2-R4)
can.coords(curseur5,7*L/8-R,H+h/2,7*L/8-3*h/16+R/2,H+h/2)
if rejouer:
can.coords(curseur4,L/8+R4*cos(o4),H+h/2+R4*sin(o4),L/8-R4*cos(o4),H+h/2-R4*sin(o4))
can.coords(curseur5,7*L/8+R*cos(o),H+h/2-R*sin(o),x5+R-R*cos(o),y5+R+R*sin(o))
can.itemconfig(texte1,fill="white")
def effet_choc(dxA,dyA,dxB,dyB):
"Correction au choc pour tenir compte de l'effet latéral"
global dxAE,dyAE,dxBE,dyBE,e
e=(x4-L/8+R)*2/(R4-R)*pi/180
dxAE=dxA*cos(e)+dyA*sin(e)
dyAE=-dxA*sin(e)+dyA*cos(e)
dxBE=dxB*cos(e)+dyB*sin(e)
dyBE=-dxB*sin(e)+dyB*cos(e)
we=round(float(e*180/pi),1)
can.effet.config(text='%s'%we)
def hauteur(dxA,dyA,dxB,dyB):
"Correction au choc pour tenir compte de la hauteur du coup"
global dxACR,dyACR,dxBCR,dyBCR,ha
ha=-2*(y4-H-h/2+R)/(R4-R)
dxACR=dxA*ha/10
dyACR=dyA*ha/10
dxBCR=dxB*abs(ha/10)
dyBCR=dyB*abs(ha/10)
wha=round(float(ha),1)
can.hauteur.config(text='%s'%wha)
def rebond_tir(x,y,dx,dy):
"Rebond sur les bandes pour le premier tir"
global xR,yR,dxR,dyR,RT,rt
RT=1;rt+=1
if rt==1:m=(x4-L/8+R)*2/(R4-R)*(1+(v-1)/20)
else:m=0
if x>L-2*r: # bande droite
dxs,dys=dx+abs(m),dy+m
xR,yR,dxR,dyR=L-2*r,y,-dxs*hypot(dx,dy)/hypot(dxs,dys)*n,dys*hypot(dx,dy)/hypot(dxs,dys)*n
if y>H-2*r: # bande inférieure
dxs,dys=dx-m,dy+abs(m)
xR,yR,dxR,dyR=x,H-2*r,dxs*hypot(dx,dy)/hypot(dxs,dys)*n,-dys*hypot(dx,dy)/hypot(dxs,dys)*n
if x<0: # bande gauche
dxs,dys=dx-abs(m),dy-m
xR,yR,dxR,dyR=0,y,-dxs*hypot(dx,dy)/hypot(dxs,dys)*n,dys*hypot(dx,dy)/hypot(dxs,dys)*n
if y<0: # bande supérieure
dxs,dys=dx+m,dy+abs(m)
xR,yR,dxR,dyR=x,0,dxs*hypot(dx,dy)/hypot(dxs,dys)*n,-dys*hypot(dx,dy)/hypot(dxs,dys)*n
def rebond_normal(x,y,dx,dy):
"Rebond sur les bandes pour les coups suivants"
global xR,yR,dxR,dyR,RN
RN=1
if x>L-2*r:xR,yR,dxR,dyR=L-2*r,y,-dx*n,dy*n # bande droite
if y>H-2*r:xR,yR,dxR,dyR=x,H-2*r,dx*n,-dy*n # bande inférieur
if x<0:xR,yR,dxR,dyR=0,y,-dx*n,dy*n # bande gauche
if y<0:xR,yR,dxR,dyR=x,0,dx*n,-dy*n # bande supérieure
def fl(flèche,a,x,y):
"calcul de la longueur et mise en place de la flèche de tir"
global xf,yf,lf
SG=pi-atan(float(y+r)/float(x+r)) # le coin supérieur gauche du billard est vu par la boule sous l'angle SG
SD=atan(float(y+r)/float(L-x-r)) # le coin supérieur droit du billard est vu par la boule sous l'angle SD
ID=atan(-float(H-y-r)/float(L-x-r)) # le coin inférieur droit du billard est vu par la boule sous l'angle ID
IG=-pi-atan(-float(H-y-r)/float(x+r)) # le coin inférieur gauche du billard est vu par la boule sous l'angle IG
if a==0:lf=L-x-r # limitation de lf par la bande droite (cas limite)
if a==pi or a==-pi:lf=x+r # limitation de lf par la bande gauche (cas limite)
if a<SG and a>SD:lf=(y+r)/sin(a) # limitation de lf par la bande supérieure
if a<=SD and a>ID:lf=(L-x-r)/cos(a) # limitation de lf par la bande droite
if a<=ID and a>IG:lf=-(H-y-r)/sin(a) # limitation de lf par la bande inférieure
if a>=SG and a<pi:lf=-(x+r)/cos(a) # limitation de lf par la bande gauche
if a<IG and a>-pi:lf=-(x+r)/cos(a)
xf,yf=x+r+lf*cos(a),y+r-lf*sin(a) # extrémité de la flèche sur la bande
can.coords(flèche,x+r,y+r,xf,yf) # la flèche accompagne la boule pendant le déplacement
if B1==1:can.itemconfig(flèche,fill='white')
if B3==1:can.itemconfig(flèche,fill='grey')
def sm(x,y,dx,dy):
"Simulation du parcours de la boule tirée"
global sim
sim=can.create_line(3*h*x/2/L+L/2-3*h/4+RS,3*h*y/4/H+H+h/8+RS,3*h*(x+dx)/2/L+L/2-3*h/4+RS,3*h*(y+dy)/4/H+H+h/8+RS)
def effacer_simulation():
"effacer la trajectoire de la boule"
global b1S,b2S,b3S
REG66=can.create_rectangle(L/2-3*h/4,H+h/8,L/2+3*h/4,H+7*h/8,width=2,fill='dark green')
bouleS(x1,y1,RS,color='white');b1S=bS # remise en place de B1/Pupitre
bouleS(x2,y2,RS,color='red');b2S=bS # idem B2/Pupitre
bouleS(x3,y3,RS,color='grey');b3S=bS # idem B3/Pupitre
def effacer_texteR():
"Effacement des textes liés au résultat du tir"
can3.delete(texte1S);can3.delete(texte1E);can3.delete(texte3S);can3.delete(texte3E)
def boule(x,y,r,color):
"Coordonnées de la boule"
global b
b=can.create_oval(x,y,x+2*r,y+2*r,width=1,fill=color)
def Cboule(b,x,y,r):
"Coordonnées de la boule"
can.coords(b,x,y,x+2*r,y+2*r)
def bouleS(x,y,r,color):
"Coordonnées de la boule"
global bS
X,Y=3*h*x/2/L+L/2-3*h/4,3*h*y/4/H+H+h/8 # changement de système de coordonnées (billard vers simulation)
bS=can.create_oval(X,Y,X+2*RS,Y+2*RS,width=1,fill=color)
def CbouleS(bS,x,y,r):
"Coordonnées de la boule"
X,Y=3*h*x/2/L+L/2-3*h/4,3*h*y/4/H+H+h/8 # changement de système de coordonnées (billard vers simulation)
can.coords(bS,X,Y,X+2*RS,Y+2*RS)
def presentation():
"Fenêtre-message contenant la description sommaire du principe du jeu"
msg =Toplevel()
Message(msg, bg ="dark green", fg ="white", width =450,font ="Arial 8",
text =" PRESENTATION\n\n"\
"Au lancement du jeu, trois boules (BLANCHE, ROUGE et GRISE), apparaissent.La BLANCHE commence.\n\n"\
"La première étape, si l'on souhaite un jeu différent, consiste à déplacer les boules (abscisses et ordonnées), vers de nouvelles positions.\n\n"\
"La seconde vise à choisir la direction, la vitesse,l'effet latéral et la hauteur de tir de la boule BLANCHE.\n"\
"Une flèche de tir apparait, dont la longueur est ajustée aux dimensions du billard.\n\n"\
"Les boules étant en place, la touche <Tir !> met en mouvement la boule BLANCHE dans la direction choisie.\n"\
"Aux premiers chocs, les autres boules se mettent à leur tour en mouvement.\n"\
"La vitesse des boules se réduit à chaque itération, pour simuler le freinage du tapis, ainsi qu'à chaque choc (y/c avec les bandes).\n\n"\
"A l' arrêt des boules, le score de la boule BLANCHE est comptabilisé.\n"\
"En cas de succès, la BLANCHE gagne un point.Elle peut alors <Continuer !> ou <Rejouer le coup !> (pour améliorer les positions finales).\n"\
"En cas d' échec, elle peut aussi rejouer le coup,et, sinon, <Passer la main !> à la GRISE.\n\n"\
"La touche <Figer !> permet d'interrompre le mouvement à tout moment, et la touche <Relancer !> de le redémarrer.\n\n\n"\
"ALGORITHME\n\n"\
"Lorsque la boule BLANCHE approche, par exemple, de la boule GRISE, l'algorithme compare la distance entre leurs centres à la somme de leurs rayons.\n"\
"Quand l'écart devient négatif, il y a intersection des deux contours.\n\n"\
"L'algorithme calcule alors le recul en position des deux boules sur leurs directions initiales et en proportion de leurs vitesses, pour revenir au strict contact.\n\n"\
"La sortie du choc, en direction et en vitesse, se fait ensuite selon les lois de la mécanique des chocs inélastiques entre solides.\n"\
"Elle prend en compte (de façon très simplifiée) l'effet latéral et la hauteur de tir imprimés au moment du tir.\n\n"\
"Un coefficient (n) de réduction de la vitesse intervient à chaque choc, y/c avec les bandes.\n"
"Un ralentissement (k) a lieu également à chaque itération.\n").pack(padx =10, pady =10)
def processus():
""
msg =Toplevel()
Message(msg, bg ="dark green", fg ="white", width =450,font ="Arial 8",
text="PROCESSUS à suivre\n\n"\
"1. Cliquer sur <Préparer le jeu !>\n\n"\
"2. Régler vitesse et orientation\n"\
"en déplaçant le cercle blanc\n"\
"(réglage fin par clics successifs)\n\n"\
"3. Régler effet latéral et hauteur\n"\
"en déplaçant la bille bleue\n\n"\
"4. Appuyer sur la touche <Tirer !>\n\n"\
"5. En cas de succès, <Continuer !>\n"\
"ou <Rejouer !> : pour améliorer\n\n"\
"6. Si échec, <Passer la main !>\n"\
"ou <Rejouer !>: pour réessayer\n\n"\
"7. Possibilité de <Figer !> le mouvement\n"\
"puis de <Relancer !>\n\n\n"\
"Echelle du jeu:\n"\
"Elle est peut être modifiée en\n"\
"intervenant dans le menu <Règle du jeu>.\n"\
"Valeurs possibles: de 0.5 à 1.0\n"\
"(valeur actuelle=0.5)\n").pack(padx =10, pady =10)
def aPropos():
"Fenêtre-message indiquant l'auteur"
msg =Toplevel()
Message(msg, width =200, aspect =100, justify =CENTER,
text ="Billard français \n\nHCD, Octobre 2005.\n"\
"Python version 2.4.2\nTk version 8.4").pack(padx =10, pady =10)
def scale(E):
"Changement d'échelle"
global L,H,h,r,rr,R,R4,R6,RS
global x1,y1,x2,y2,x3,y3
global x4o,y4o,x5o,y5o,x4,y4,x5,y5
E=float(E)
L,H,h,r,rr,R,R4,R6,RS=E*L,E*H,E*h,E*r,E*rr,E*R,E*R4,E*R6,E*RS
x1,y1,x2,y2,x3,y3=E*x1,E*y1,E*x2,E*y2,E*x3,E*y3
can.config(height=H+h,width=L)
can2.config(width=h)
can3.config(height=h/3,width=h)
x4o,y4o,x5o,y5o=E*x4o,E*y4o,E*x5o,E*y5o
x4,y4,x5,y5=E*x4,E*y4,E*x5,E*y5
can.coords(Pupitre,E*4,H,L,H+h)
can.coords(texte,E*L/2,E*L/3)
can.coords(t1,L/8,H+h-E*10)
can.coords(t2,L/2,H+h-E*10)
can.coords(t3,7*L/8,H+h-E*10)
can.coords(texte1,L/2,H+E*7.5)
can.coords(texte2,L/8,H+E*7.5)
can.coords(texte3,7*L/8,H+E*7.5)
can.coords(REG4,L/8-R4,H+h/2-R4,L/8+R4,H+h/2+R4)
can.coords(curseur4,L/8,H+h/2+R4,L/8,H+h/2-R4)
can.coords(REG6,L/2-3*h/4,H+h/8,L/2+3*h/4,H+7*h/8)
can.coords(REG5,7*L/8-R6,H+h/2-R6,7*L/8+R6,H+h/2+R6)
can.coords(REG5B,7*L/8-R,H+h/2-R,7*L/8+R,H+h/2+R)
can.coords(curseur5,7*L/8-R,H+h/2,7*L/8-3*h/16+R/2,H+h/2)
can.coords(pA,L/4-rr,H/2-rr,L/4+rr,H/2+rr)
can.coords(pB,L/2-rr,H/2-rr,L/2+rr,H/2+rr)
can.coords(pC,3*L/4-rr,H/2-rr,3*L/4+rr,H/2+rr)
can.coords(pD,3*L/4-rr,H/3-rr,3*L/4+rr,H/3+rr)
can.coords(pE,3*L/4-rr,2*H/3-rr,3*L/4+rr,2*H/3+rr)
can3.coords(texte1S,2*h/3,h/4)
can3.coords(texte1E,2*h/3,h/4)
can3.coords(texte3S,2*h/3,h/4)
can3.coords(texte3E,2*h/3,h/4)
EE=1.0
def echelle():
"Choix de l'échelle"
éch=Toplevel()
curE=Scale(éch,length=200,label="Echelle du jeu",orient=HORIZONTAL,from_=0.95,to=1.05,resolution=0.05,command=scale)
curE.set(1.0) # position initiale du curseur
curE.pack()
######## Programme principal ############################################
# Création du widget principal :
root = Tk()
root.title('>>>>>>> BILLARD <<<<<<<')
# données initiales:
flag=0 # compteur
# Billard
L=600 # longueur du billard
H=L/2 # largeur du billard
r,rr=10,1 # rayons des boules et des marques du tapis
k,s=0.996,0.5 # coefficient de freinage du tapis, vitesse d'arrêt du mouvement
n=0.8 # coefficient de réduction de la vitesse lors d'un choc
x1,y1,x2,y2,x3,y3=3*L/4-r,H/2-r,L/2-r,H/2-r,L/4-r,H/2-r # coordonnées courantes des boules
dx1,dy1,dx2,dy2,dx3,dy3=0,0,0,0,0,0 # composantes courantes des vecteurs vitesse des boules
c12,c23,c31=0,0,0 # compteurs de choc
point1,point3,score1,score3=0,0,0,0 # compteurs de point et de score
R1,R3,T1,T3,PM1,PM3,CT1,CT3=0,0,0,0,0,0,0,0 # indicateurs (rejouer,tirer,passer la main,continuer)
RN1,RN3,RT1,RT3=0,0,0,0 # indicateurs de rebond sur les bandes et après choc
j,j1,j3,t1,t3,r1,r3,rt,t=0,0,0,0,0,0,0,0,0 # compteurs de lancements de jeux et de tirs
texte1E,texte1S,texte3E,texte3S=0,0,0,0
S1,S3,E1,E3=0,0,0,0 # résultats (S=succès,E=échec)
e,ha,o,v,o4=0,0,pi,8,pi/2 # réglages initiaux
figer=0
tA=0
# Pupitre de réglage du tir
h=H/2 # hauteur du pupitre de réglage
R,R4,R6,RS=4,25,3*h/8,3*h*r/4/H # rayons du système de réglage
x4o,y4o,x5o,y5o=L/8-R,H+h/2-R,7*L/8-3*h/16-3*R/2,H+h/2-R
x4,y4,x5,y5=L/8-R,H+h/2-R,7*L/8-3*h/16-3*R/2,H+h/2-R
# création des widgets "dépendants" :
can=Canvas(root,bg='dark green',height=H+h,width=L,highlightbackground='brown')
can.grid(row=1,column=0,rowspan=2)
can2=Canvas(root,bg='brown',highlightbackground='brown')
can2.grid(row=1,column=1,sticky=N)
can3=Canvas(root,bg='white',height=h/3,width=h)
can3.grid(row=2,column=1,padx=0,pady=0,ipadx=10,ipady=10,sticky=N+S)
# Pupitre de commande
Pupitre=can.create_rectangle(4,H,L,H+h,width=2,fill='brown')
t1=can.create_text(L/8,H+h-10,text='Effet et hauteur de tir',fill="white")
t2=can.create_text(L/2,H+h-10,text='Simulation',fill="white")
t3=can.create_text(7*L/8,H+h-10,text='Vitesse et orientation de tir',fill="white")
texte1=can.create_text(L/2,H+7.5,text='Régler le tir, puis "Tirer !"',fill="white")
texte2=can.create_text(L/8,H+7.5,text='Déplacer la bille bleue',fill="white")
texte3=can.create_text(7*L/8,H+7.5,text='Déplacer le cercle blanc',fill="white")
REG4=can.create_oval(L/8-R4,H+h/2-R4,L/8+R4,H+h/2+R4,width=1,fill='white')
curseur4=can.create_line(L/8,H+h/2+R4,L/8,H+h/2-R4,width=1,fill='white')
REG6=can.create_rectangle(L/2-3*h/4,H+h/8,L/2+3*h/4,H+7*h/8,width=2,fill='dark green')
REG5=can.create_oval(7*L/8-R6,H+h/2-R6,7*L/8+R6,H+h/2+R6,width=1,fill='dark green')
REG5B=can.create_oval(7*L/8-R,H+h/2-R,7*L/8+R,H+h/2+R,width=1,fill='white')
curseur5=can.create_line(7*L/8-R,H+h/2,7*L/8-3*h/16+R/2,H+h/2,width=1,fill='dark green',arrow=LAST)
# création des cinq points gris sur le tapis et des deux flèches
pA=can.create_oval(L/4-rr,H/2-rr,L/4+rr,H/2+rr,width=0,fill='light grey')
pB=can.create_oval(L/2-rr,H/2-rr,L/2+rr,H/2+rr,width=0, fill='light grey')
pC=can.create_oval(3*L/4-rr,H/2-rr,3*L/4+rr,H/2+rr,width=0,fill='light grey')
pD=can.create_oval(3*L/4-rr,H/3-rr,3*L/4+rr,H/3+rr,width=0,fill='light grey')
pE=can.create_oval(3*L/4-rr,2*H/3-rr,3*L/4+rr,2*H/3+rr,width=0,fill='light grey')
flèche1=can.create_line(0,0,0,0,arrow=LAST)
flèche3=can.create_line(0,0,0,0,arrow=LAST)
# Message d'introduction
texte=can.create_text(L/2,L/3,text='Cliquer sur le bouton "Règle du jeu"\n\nou\n\ndirectement sur "Préparer le jeu"',fill="white")
# Menu <Règle du jeu>
RdJ = Menubutton(can2, text ='Règle du jeu',height=2,width=25,relief=GROOVE,bg="dark green",fg="white")
RdJ.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
me1 = Menu(RdJ)
me1.add_command(label='Présentation',underline=0,command=presentation)
me1.add_command(label='Processus',underline=0,command=processus)
me1.add_command(label='Echelle',underline=0,command=echelle)
me1.add_command(label='A propos ...',underline=0,command=aPropos)
RdJ.configure(menu=me1)
# Affichage des réglages et des scores:
# hauteur:
can.hauteur=Label(can2,text='0',fg='white',bg='brown')
can.hauteur.pack(side=BOTTOM)
Label(can2,text="hauteur",fg='white',bg='brown').pack(side=BOTTOM)
# effet:
can.effet=Label(can2,text='0',fg='white',bg='brown')
can.effet.pack(side=BOTTOM)
Label(can2,text="effet",fg='white',bg='brown').pack(side=BOTTOM)
# vitesse:
can.vitesse=Label(can2,text='0',fg='white',bg='brown')
can.vitesse.pack(side=BOTTOM)
Label(can2,text="vitesse",fg='white',bg='brown').pack(side=BOTTOM)
# orientation:
can.orientation=Label(can2,text='0',fg='white',bg='brown')
can.orientation.pack(side=BOTTOM)
Label(can2,text="orientation",fg='white',bg='brown').pack(side=BOTTOM)
# Score B3:
can.score3=Label(can2,text='0',fg='white',bg='brown')
can.score3.pack(side=BOTTOM)
Label(can2,text="score GRISE",fg='white',bg='brown').pack(side=BOTTOM)
# Score B1:
can.score1=Label(can2,text='0',fg='white',bg='brown')
can.score1.pack(side=BOTTOM)
Label(can2,text="score BLANCHE",fg='white',bg='brown').pack(side=BOTTOM)
# Boutons de commande
# 'Continuer ?':
CT=Button(can2,text='Continuer? ',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=continuer)
CT.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
CT.pack_forget()
# 'Passer la main ?':
PM=Button(can2,text='Passer la main? ',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=passer)
PM.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
PM.pack_forget()
# 'Rejouer le coup ?':
RJ=Button(can2,text='Rejouer le coup ?',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=rejouer)
RJ.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
RJ.pack_forget()
# bouton d'arrêt du mouvement:
FI=Button(can2,text='Figer le mouvement',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=stop)
FI.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
FI.pack_forget()
# bouton de redémarrage du mouvement:
RL=Button(can2,text='Relancer le mouvement',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=go)
RL.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
RL.pack_forget()
# 'Tirer !':
T=Button(can2,text='Tirer !',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=tirer)
T.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
T.pack_forget()
# 'Préparer le tir !':
J=Button(can2,text='Préparer le jeu !',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=jouer)
J.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
root.mainloop()
Conclusion
Merci à tous ceux qui ont bien voulu prendre connaissance des premières versions. Une nouvelle visite du script devrait les intéresser, car de nombreuses fonctionnalités ont été ajoutées. Commencer par appuyer sur le bouton "Règle du jeu" qui donne une présentation d'ensemble, ainsi que le processus à suivre pour jouer.
PS : commentaires et cotations seront les bienvenus !
Historique
- 18 août 2005 10:23:18 :
- ajout de commentaires
- 09 septembre 2005 00:13:56 :
- Les boules sortent maintenant de façon aléatoire sur le billard ou, en cas de recouvrement, en position "canonique" (alignées).
Le code est surtout complété pour permettre de choisir la position des boules sur le billard, puis la direction de tir de la boule blanche.
Une flèche orientable apparait puis disparait au moment du tir.
L'algorithme du choc entre boules, qui constitue l'originalité du programme, est réintégré dans le nouveau script.
- 17 octobre 2005 22:15:15 :
- Fonctionnalités nouvelles:
1. Prise en compte de l'effet et de la hauteur de tir
2. Création d'un pupitre de tir permettant de commander:
- orientation et vitesse
- effet et hauteur
3. Création de boutons de commande pour gérer les phases de jeu:
- "préparer le tir"
- "continuer", "rejouer le coup", "passer la main"
4. Création du menu "Règle du jeu" avec:
- la "présentation" du script
- la descrition du "processus" à suivre pour jouer
- la possibilité de changer l'"échelle" des canevas
5 . Création d'un billard "miniature" pour visualiser et
mémoriser la trajectoire de la boule tirée
- 30 novembre 2005 01:32:52 :
- Saisie de mots clés
- 23 décembre 2005 01:36:55 :
- Ajout d'un zip
Sources du même auteur
Sources de la même categorie
Commentaires et avis
Discussions en rapport avec ce code source dans le forum
Variation Label grâce à une fonction appellé par Button [ par philux21 ]
bonjour, je souhaite faire varier une valeur affichée dans un label. Je m'y prends ainsi : http://pastebin.com/8qnFG01J je ne comprends pas mon erre
Espace dans un label Tkinter [ par dahrprog ]
Bonjour tout le monde , je voudrais afficher des données de ma base de données sur une interface Tkinter via une Label , ça marche bien , j'ai mis :
Petit problème avec "return" [ par Uims ]
Bonjour, Je suis entrain de faire un annuaire en python (avec Tk), mais j'ai un petit problème avec return dans la fonction "loc", j'aimerai que
Une scrollbar sur un Label ? [ par stephane70 ]
Bonjour, Je mets en place un petit programme destiné à faire un instantanée graphique des connections en cours sur le pc ainsi que les executables en
Problème sur la taille de fenetre en Tkinter [ par stephane70 ]
Bonjour, Je mets en place un petit programme destiné à faire un instantanée graphique des connections en cours sur le pc ainsi que les executables en
héritage de wxObject et polymorphisme ?? [ par RV2931 ]
Bonjour,Je programme en wxPython et j'aurai voulu savoir comment dériver un objet wx pour faire un bouton personalisé par exemple, avec des informatio
[Tkinter] Erreur premier programme [ par O_connor ]
Bonjour à toutes et à tous,Je poste un ce topic car voilà deux jours que je bloque sur ma petite application que j'essaie de réaliser avec une GUI.Ce
Question sur PyQt4 !!!!!! [ par Subversion ]
Bonjour à vous tous,Voilà, je dois programmer en Python via Eclipse (avec PyDev) afin d'élaborer une interface graphique. De ce fait, je suis en train
Gestion d'une interface graphique [ par lilly74 ]
Bonjour, je débute en python et j'essaie de créer une interface graphique qui prend en entrée deux chaînes de caractères et qui les traite selon une m
|
Derniers Blogs
CSS CONTENT STATE SELECTORS (PERSONNAL DRAFT)CSS CONTENT STATE SELECTORS (PERSONNAL DRAFT) par FREMYCOMPANY
Bonjour à tous, Je viens de publier une proposition comprenant 5 pseudo-classes pour le CSS Working Group ayant trait à l'état de chargement d'un élément (ex: IMG,VIDEO,AUDIO,OBJECT pour l'HTML.). Si le c½ur vous en dit, vous pouvez retrouver cette p...
Cliquez pour lire la suite de l'article par FREMYCOMPANY MBA : POURQUOI FAIRE ET COMMENT LE CHOISIR ?MBA : POURQUOI FAIRE ET COMMENT LE CHOISIR ? par ROMELARD Fabrice
Formation initiale Durant la formation, le découpage classique est le suivant (je donnerai les équivalences Suisse lorsque je les connaîtrais) : Ecole primaire jusqu'au Collège : Formation générale permettant d'obtenir les méthodes...
Cliquez pour lire la suite de l'article par ROMELARD Fabrice Y'A DES ERREURS QUI PEUVENT RENDRE LE DéVELOPPEUR VIOLENTY'A DES ERREURS QUI PEUVENT RENDRE LE DéVELOPPEUR VIOLENT par Aleks
Quand on a ce genre d'erreur sans log :
Et bas on a juste envie de choper le gas de Microsoft qu'a développé ça et lui foutre des baffes de Coboye ! ...
Cliquez pour lire la suite de l'article par Aleks [HYPER-V 3] PRéSENTATION DES COMMANDLETS POWERSHELL[HYPER-V 3] PRéSENTATION DES COMMANDLETS POWERSHELL par Pierrick CATRO-BROUILLET
Avec la sortie prochaine de la Beta Consumer Preview de Windows 8, j'avais envie de revenir sur une des fonctionnalités que j'attends le plus et que, en bon geek que je suis, j'utilise déjà : Hyper-V 3 ainsi son module PowerShell.
Il y a déjà pléthor...
Cliquez pour lire la suite de l'article par Pierrick CATRO-BROUILLET IIS7 - COMPRESSION GZIPIIS7 - COMPRESSION GZIP par cyril
La compression GZIP permet d'améliorer les performances de navigation en compressant ce qu'envoie le serveur à un client. Pour comprendre comment cela fonctionne, regardons ce qu'il se passe au niveau HTTP lorsqu'un client tente d'accéder à une ress...
Cliquez pour lire la suite de l'article par cyril
Forum
PYVISA PROBLèMEPYVISA PROBLèME par sandrine44
Cliquez pour lire la suite par sandrine44
Logiciels
Easy-Planning (1.0.0.1)EASY-PLANNING (1.0.0.1)Basé sur les mêmes principes que MyPlanning, Easy-Planning permet de créer des plannings sous la ... Cliquez pour télécharger Easy-Planning Academy System (17.1.3.0)ACADEMY SYSTEM (17.1.3.0)Logiciel de gestion des établissements.
- élèves/étudiants (inscription, dossier, absence...)
-... Cliquez pour télécharger Academy System COLLECTOR PLUS (3.00B)COLLECTOR PLUS (3.00B)COLLECTOR PLUS version 3.00B est un logiciel utilisant une base de données alimentée par :
- L... Cliquez pour télécharger COLLECTOR PLUS PONAMEDIA PREMIUM - HELLLOOO FLASH DEMO (V7.4)PONAMEDIA PREMIUM - HELLLOOO FLASH DEMO (V7.4)PONAMEDIA TV DEVIENS HELLLOOO FLASH
LA TV SUR VOTRE ORDINATEUR.
Toute une plateforme Multi... Cliquez pour télécharger PONAMEDIA PREMIUM - HELLLOOO FLASH DEMO LettresFaciles 2011 (8.0.0.1)LETTRESFACILES 2011 (8.0.0.1)LettresFaciles est un logiciel facilitant la création et la rédaction de lettres types.
Son inte... Cliquez pour télécharger LettresFaciles 2011
|