Ce script est présenté sous la forme d'un JEU.
Il fait intervenir un SERPENT orientable en direction et "armé" :
- d'une FLECHE rétractable
- d'un MISSILE à autoguidage terminal
Le but du jeu consiste pour le serpent à détruire le plus rapidement possible plusieurs cibles.
Cinq niveaux de jeu sont proposés.
Source / Exemple :
#! /usr/bin/env python
# -*- coding: Latin-1 -*-
# Python version 2.4.2
# Tk version 8.4
# IDLE version 1.1.2
# <<< Serpent PYTHON >>>
############# PRESENTATION #################
# Ce script est présenté sous la forme d'un JEU.
# Il fait intervenir un SERPENT orientable en direction et "armé" :
# - d'une FLECHE rétractable
# (commmande de tir par la touche < Espace > du clavier
# - d'un MISSILE à autoguidage terminal
# (commmande de tir par la touche de la lettre < X > du clavier
#
# La "FLECHE" est représentée par un cercle blanc ancré au nez du serpent, auquel elle est reliée
# par un "fil" extensible losqu'elle est projetée. Elle change de couleur, en bleu, lorsqu'elle est
# "désactivée".
# Le missile est représenté aussi par un cercle blanc, plus petit.Il est situé à l'extrémité de la queue
# du serpent et s'en détache quand il est mis en oeuvre. Il revient à sa place après un tir suivi d'une collision.
#
# Le but du jeu consiste pour le serpent à détruire le plus rapidement possible plusieurs CIBLES.
#
# Les CIBLES, de couleur marron, sont immobiles au départ.
# Elles peuvent se mettre en mouvement dans le courant de la partie.
# Elles deviennent alors DANGEREUSES pour le serpent qui risque la DESTRUCTION en cas de collision.
# Lorsque le serpent tire avec sa flèche rétractable, la cible est normalement détruite immédiatement.
# Mais cette flèche peut se désactiver; dans ce cas, la cible n'est pas détruite et, surtout, elle devient MOBILE.
# La flèche se réactive au tir suivant ... si le serpent a survécu.
# Qand elle est désactivée, un message d'avertissement apparait dans le panneau rouge situé à droite
# du plan de jeu.
# Les cibles sont également entourées d'un cercle de détection pour les tirs de missile.
# Dès que le missile entre en contact avec l'un de ces cercles, il change d'orientation et
# se dirige automatiquement vers le centre de la cible détectée.
# La cible se met en mouvement, puis elle est rapidement détruite au contact du missile.
# Lorsqu'il y a une détection multiple, les autres cibles deviennent aussi mobiles, et donc DANGEREUSES.
#
# Dix OBSTACLES fixes sont placés sur le jeu. Ils sont alignés et de couleur bleue. Indestructibles, ils
# permettent au serpent de rebondir et ainsi de multiplier les changements de trajectoire.
# Les cibles peuvent s'y cacher.
#
# La partie n'est donc pas gagnée d'avance !!!
#
# La fenêtre de jeu comprend:
# - un plan carré à l'intérieur duquel évoluent le serpent et les cibles
# - un champ de saisie du niveau de jeu choisi (1, 2, 3, 4)
# - quatre boutons de commande :
# . < Mise en place ! >
# . < Lancer le jeu ! >
# . < Stop ! >
# . < Quitter le jeu ! >
# - un bouton donnant la :
# . < Règle du jeu ! >
# - un compteur visualisant le temps écoulé
# - un compteur visualisant le nombre de cibles détruites
# - un panneau rouge pour le message d'avertissement
#
#
# Commencer -comme il est d'usage- par prendre connaissance de la < Règle du jeu ! >.
# and "enjoy it !!!"
############# COMMENTAIRE #################
# Le programme fait intervenir l'interface graphique Tkinter, avec quatre modules :
# math, random, tkMessageBox, time.
# L'utilisation de LISTES (pour les coordonnées et les diamètres des cercles) et d'une BIBLIOTHEQUE
# pour leur identification, permet de réduire considérablement le nombre de lignes de code.
# C'est l'intérêt de ce script.
# L'algorithme de collision des cercles est celui que j'avais présenté dans les codes intitulés:
# "BILLARD Français", et "COLLISIONS multiples".
######################################################################################
from Tkinter import*
from math import hypot,sqrt,floor,log
from random import randrange
from tkMessageBox import askokcancel
from time import time
import tkFont
######################################################################################
nS=40# nombre de cercles constituant le serpent
nC=39# nombre de cibles
nO=10# nombre d'obstacles
######################################################################################
def niveau_jeu():
" choix du niveau de jeu "
global V,TD,nS
if activation_cases==1:
N=choix_niveau.get()# entrée du niveau de jeu choisi (de 1 à 5)
# V est un paramètre de réglage de la vitesse du serpent
# TD est un paramètre de réglage du nombre total de cibles détruites, pour lequel un tir de flèche
# devient dangereux pour le serpent : les cibles détectées deviennent en effet mobiles ...et susceptibles
# de le détruire en cas de collision par le travers :
if N==1: V=2.0; TD=20;nS=40# correspond à la 20ème cible détruite
if N==2: V=2.0; TD= 5;nS=40# correspond aux destructions de rang multiple de 5 : 5ème, 10ème, 15ème,...,35ème
if N==3: V=2.0; TD= 4;nS=45# rang multiple de 4 : 4ème, 8ème, 12ème,..., 36ème cible détruite
if N==4: V=2.5; TD= 3;nS=40# rang multiple de 3 : 3ème, 6ème, 9ème,..., 39ème cible détruite
if N==5: V=3.0; TD= 2;nS=32# rang multiple de 2 : 2ème, 4ème, 6ème,..., 38ème cible détruite
def mise_en_place():
" commande de mise en place du jeu "
global flag,top_start,score_time
flag=1
ST.configure(state=NORMAL)# activation du bouton de commande < Stop !>
LJ.configure(state=NORMAL)# id <Lancer le jeu !>
MP.configure(state=DISABLED)# désactivation du bouton de commande < Mise en place !>
niveau_jeu()# prise en compte du niveau de jeu choisi, en provenance du module ci-dessus
score_time=0# mise à zéro du compteur de temps écoulé
can.score.config(text='%s'%score_time)# visualisation de ce compteur
top_start=time()# top départ
can.delete(ALL)# nettoyage" du plan de jeu
serpent()# activation du module (ci-dessous)
cibles()# id
obstacles()# id
def lancer_le_jeu():
" commandes de lancement des mouvements et de gestion des collisions "
global activation_cases
LJ.configure(state=DISABLED)# désactivation du bouton de commande <Lancer le jeu !>
activation_cases
if flag==1:
mouvements_serpent()# activation du module (ci-dessous)
mouvements_fleche()# id
mouvements_cibles()# id
collisions_serpent_obstacles()# id
collisions_serpent_cibles()# id
collisions_missile_cibles()# id
if total_destruction == nC:# arrêt lorsque toutes les cibles sont détruites
top_end=time()# top fin de partie
score_time=int(round(top_end-top_start,0))# calcul de la durée de la partie
for i in range(0,nO):can.delete(O[i])# effacement des obstacles fixes
for i in range(1,150):sapin();can.delete(ALL)# activation en boucle du module animé "sapin+neige"
for i in range(1,150):sapin()
can.create_text(L/2,H/3-50,text='Joyeuses fêtes !!!',fill="white",font="Arial 12")
root.after(10000,stop)# l'animation finale dure 10 secondes
if hypot(x[nS-2]-x[1],y[nS-2]-y[1])>200*V-80:# critère de désintégration du serpent
destruction()# destruction du serpent
score_time=int(round(time()-top_start,0))# calcul de la durée de la partie
can.score.config(text='%s'%score_time)# visualisation du temps écoulé
can.total_destruction.config(text='%s'%total_destruction)# visualisation du nombre de cibles détruites
activation_cases=0
root.after(10,lancer_le_jeu)
######################################################################################
def serpent():
" création du serpent PYTHON (S) et de sa flèche (F) "
global S,LF,x,y,dx,dy,DS
x=[L-(i+2)*V*n for i in range(0,nS)]# liste des abscisses des 40 cercles constituant le serpent
y=[H-(i+2)*2*V*n for i in range(0,nS)]# liste des ordonnées
dx=[-V*n for i in range(0,nS)]# liste des vitesses horizontales
dy=[-2*V*n for i in range(0,nS)]# liste des vitesses verticales
DS=[7]
for i in range(0,nS-1):DS.append(1+d*(1+i)/nS) # liste des diamètres
S={}# bibliothèque des cercles
LF=can.create_line(x[nS-1],y[nS-1],x[nS-2],y[nS-2],fill="orange")# ligne reliant la flèche à la tête du serpent
for i in range(0,nS):
S[i]=can.create_oval(x[i]-DS[i]/2,y[i]-DS[i]/2,x[i]+DS[i]/2,y[i]+DS[i]/2,fill="orange",outline="orange")
can.itemconfig(S[nS-4],width=9);can.itemconfig(S[nS-3],width=6);can.itemconfig(S[nS-2],width=3)# dessin de la tête du serpent
can.itemconfig(S[0],fill="white")# couleur blanche pour le missile (en queue)
can.itemconfig(S[nS-1],fill="white",width=1,outline="blue")# dessin de la flèche rétractable (extrémité en forme de cercle)
def cibles():
" création des cibles (C) "
global C,Q,xC,yC,dxC,dyC,DC,DQ
xC=[randrange(10,780) for i in range(0,25)]# liste des abscisses des 39 cibles (distribution aléatoire)
for i in range(25,39):xC.append(randrange(10,520))# pour éviter au départ de placer une cible sur le serpent
yC=[10+i*19 for i in range(0,nC)]# liste des ordonnées (régulièrement espacées)
dxC=[0 for i in range(0,nC)]# les cibles sont immobiles
dyC=[0 for i in range(0,nC)]# id
DC=[randrange(10,20) for i in range(0,nC)]# diamètres compris entre 10 et 20
DQ=[100 for i in range(0,nC)]# diamètres des cercles de détection des cibles
C={}# bibliothèque des cibles
Q={}# bibliothèque des cercles de détection
for i in range(0,nC):
Q[i]=can.create_oval(xC[i]-DQ[i]/2,yC[i]-DQ[i]/2,xC[i]+DQ[i]/2,yC[i]+DQ[i]/2,outline='#007000')
C[i]=can.create_oval(xC[i]-DC[i]/2,yC[i]-DC[i]/2,xC[i]+DC[i]/2,yC[i]+DC[i]/2,fill="brown",outline="yellow")
def obstacles():
" création des obstacles fixes (C) "
global O,xO,yO,dxO,dyO,DO
xO=[L/4+i*50 for i in range(0,nO)]# liste des abscisses des 10 obstacles (distribution régulière)
yO=[H/4+i*50 for i in range(0,nO)]# liste des ordonnées (id)
dxO=[0 for i in range(0,nO)]# les cibles sont immobiles
dyO=[0 for i in range(0,nO)]# id
DO=[40 for i in range(0,nO)]# diamètre des obstacles
O={}# bibliothèque des obstacles
for i in range(0,nO):
O[i]=can.create_oval(xO[i]-DO[i]/2,yO[i]-DO[i]/2,xO[i]+DO[i]/2,yO[i]+DO[i]/2,fill="blue",outline="yellow")
######################################################################################
def mouvements_serpent():
" mouvements du serpent (S) "
global x,y,dx,dy,DS
global vF,tirF,GC,DR,HT,BS,iG,iD,iH,iB
if tirF==1:desactiver_touches()# concerne les flèches du clavier
if tirF==0:activer_touches()# id
for i in range(0,nS):
# commandes de direction
if GC==1:# clavier : activation de la flèche gauche
desactiver_touches();X,Y=x[i]-u,y[i]-v;Z=hypot(X,Y)
if Z==0 :iG+=1;dx[i],dy[i]=-hypot(du,dv),0
if iG==nS-1:activer_touches();GC=0;iG=0
if DR==1:# clavier : activation de la flèche droite
desactiver_touches();X,Y=x[i]-u,y[i]-v;Z=hypot(X,Y)
if Z==0 :iD+=1;dx[i],dy[i]=hypot(du,dv),0
if iD==nS-1:activer_touches();DR=0;iD=0
if HT==1:# clavier : activation de la flèche haute
desactiver_touches();X,Y=x[i]-u,y[i]-v;Z=hypot(X,Y)
if Z==0 :iH+=1;dx[i],dy[i]=0,-hypot(du,dv)
if iH==nS-1:activer_touches();HT=0;iH=0
if BS==1:# clavier : activation de la flèche basse
desactiver_touches();X,Y=x[i]-u,y[i]-v;Z=hypot(X,Y)
if Z==0 :iB+=1;dx[i],dy[i]=0,hypot(du,dv)
if iB==nS-1:activer_touches();BS=0;iB=0
# mouvements
x[i],y[i]=x[i]+(1+collisionF/nC)*dx[i],y[i]+(1+collisionF/nC)*dy[i]# le mouvement du serpent s'accélère avec la destruction des cibles
if tirM==0:
x[0],y[0]=x[1]-dx[1],y[1]-dy[1]# le missile est maintenu en queue
can.coords(S[i],x[i]-DS[i]/2,y[i]-DS[i]/2,x[i]+DS[i]/2,y[i]+DS[i]/2)
# collisions avec les bordures
for i in range(0,nS-1):# maintien dans les limites du jeu par rebond sur les bords
collision_bordures(x[i],y[i],dx[i],dy[i],DS[nS-1])
x[i],y[i],dx[i],dy[i]=pp,qq,rr,ss
def mouvements_fleche():
" mouvements de la flèche (F) "
global x,y,dx,dy
global vF,tirF,activationF,total_destruction
can.coords(LF,x[nS-1],y[nS-1],x[nS-2],y[nS-2])
if tirF==1:# la flèche du serpent est lancée dans l'axe à une vitesse supérieure
dx[nS-1],dy[nS-1]=vF*dx[nS-1]/hypot(dx[nS-1],dy[nS-1]),vF*dy[nS-1]/hypot(dx[nS-1],dy[nS-1])
x[nS-1],y[nS-1]=x[nS-1]+dx[nS-1],y[nS-1]+dy[nS-1]
if tirF==1 and x[nS-1]>L-d/2 or x[nS-1]<d/2 or y[nS-1]>H-d/2 or y[nS-1]<d/2:# maintien dans les limites du jeu
x[nS-1],y[nS-1],dx[nS-1],dy[nS-1]=x[nS-2],y[nS-2],dx[nS-2],dy[nS-2]
vF,tirF=0,0
if tirF==0 and x[nS-1]>L-d/2 or x[nS-1]<d/2 or y[nS-1]>H-d/2 or y[nS-1]<d/2:# maintien dans les limites du jeu
x[nS-1],y[nS-1],dx[nS-1],dy[nS-1]=x[nS-2],y[nS-2],dx[nS-2],dy[nS-2]
total_destruction = collisionF + collisionM
for i in range(1,13):
if total_destruction==TD*i:# si le nombre de cibles détruites est un multiple de TD (voir le module niveau_jeu ci-dessus)
activationF=1
can.itemconfig(S[nS-1],fill="blue")# la flèche du serpent change de couleur
avertissement.config(bg="yellow",fg="red")# un message d'avertissement apparait dans la fenêtre
if total_destruction==TD*i+1:# pour les valeurs suivantes
activationF=0
can.itemconfig(S[nS-1],fill="white")# la flèche reprend sa couleur
avertissement.config(bg="brown",fg="brown")# le message disparait
def mouvements_cibles():
" petits mouvements des cibles lors des collisions(O) "
global xC,yC,dxC,dyC
for i in range(0,nC):
# mouvement
xC[i],yC[i]=xC[i]+dxC[i],yC[i]+dyC[i]
dxC[J],dyC[J]=0.9995*dxC[J],0.9995*dyC[J]
can.coords(C[i],xC[i]-DC[i]/2,yC[i]-DC[i]/2,xC[i]+DC[i]/2,yC[i]+DC[i]/2)
can.coords(Q[i],xC[i]-DQ[i]/2,yC[i]-DQ[i]/2,xC[i]+DQ[i]/2,yC[i]+DQ[i]/2)
# collisions avec les bordures
collision_bordures(xC[i],yC[i],dxC[i],dyC[i],DC[i])
xC[i],yC[i],dxC[i],dyC[i]=pp,qq,rr,ss
######################################################################################
def collisions_serpent_obstacles():
" gestion des collisions Serpent / Obstacles "
global x,y,dx,dy,DS
global xO,yO
for j in range(0,nO):
if tirF==1:# après un tir
X,Y=xO[j]-x[nS-1],yO[j]-y[nS-1]
Z=hypot(X,Y)
if Z<=DS[nS-1]/2+DO[j]/2:# s'il y a collision Flèche / Obstacle
x[nS-1],y[nS-1],dx[nS-1],dy[nS-1]=x[nS-2],y[nS-2],dx[nS-2],dy[nS-2]# la flèche revient en place
for i in range(0,nS):# collisions Serpent / Obstacles
collisions(x[i],y[i],xO[j],yO[j],dx[i],dy[i],dxO[j],dyO[j],DS[nS-1],DO[j])
x[i],y[i],xO[j],yO[j]=rxa,rya,rxb,ryb
dx[i],dy[i]=rdxa,rdya
def collisions_serpent_cibles():
" gestion des collisions Serpent / Cibles "
global x,y,dx,dy
global xC,yC
global collisionF,tirF,vF,activationF,J
for j in range(0,nC):
if tirF==1:# après un tir
X,Y=xC[j]-x[nS-1],yC[j]-y[nS-1]
Z=hypot(X,Y)
if Z<=DS[nS-1]/2+(1+collisionF/3)*DC[j]/2:# s'il y a collision Serpent / Cibles
J=j# rang (dans la liste) des cibles détectées
if activationF==1:# si la flèche est activée (couleur bleue)
xC[J],yC[J]=xC[j],yC[j]
dxC[J],dyC[J]=4*dy[nS-1]/hypot(dx[nS-1],dy[nS-1])/Z,-4*dx[nS-1]/hypot(dx[nS-1],dy[nS-1]/Z)# les cibles touchées se mettent en mouvement
can.itemconfig(C[J],fill="green")# et changent de couleur
collisionF==-1# le tir n'est pas compté
else:
xC[j],yC[j],DC[j],DQ[j]=0,0,0,0# la cible est détruite
x[nS-1],y[nS-1],dx[nS-1],dy[nS-1]=x[nS-2],y[nS-2],dx[nS-2],dy[nS-2]# la flèche revient en place
collisionF+=1# le tir est comptabilisé
vF,tirF=0,0
can.create_rectangle(L*(collisionF-1)/nC,H-10,L*collisionF/nC,H,fill="pink",outline="blue")
can.create_text(50,H-15,text='flèche',fill="white")
if collisionM!=0:# s'il y a eu, en outre, destruction d'une cible, une nouvelle cible apparait
dxC[j],dyC[j]=0,0# immobilisation de celle-ci
for i in range(0,nS):# collisions Serpent / Cibles
collisions(x[i],y[i],xC[j],yC[j],dx[i],dy[i],dxC[j],dyC[j],DS[nS-1],DC[j])
x[i],y[i],xC[j],yC[j]=rxa,rya,rxb,ryb
dx[i],dy[i]=rdxa,rdya
def collisions_missile_cibles():
" gestion des collisions Missile de queue / Cibles / Cercle de détection "
global x,y,dx,dy,DS
global tirM,collisionM
global xC,yC,dxC,dyC,DC
global DQ
if tirM==1:# lorsque le missile est tiré
for j in range(0,nC):
DQ[j]=DQ[j]+0.05# le diamètre des cercles de détection augmente à chaque tir
X,Y=x[0]-xC[j],y[0]-yC[j]
Z=hypot(X,Y)
if Z<=DQ[j]/2+DS[0]/2:# s'il y a contact du missile avec le cercle de détection
dx[0],dy[0]=-X/Z*hypot(dx[0],dy[0]),-Y/Z*hypot(dx[0],dy[0])# le missile s'oriente en direction de la cible
DQ[j]=0.97*DQ[j]# le cercle de détection rétrécit lentement
can.itemconfig(C[j],fill='#00FF00')# la couleur des cibles détectées passe au vert
dxC[j],dyC[j]=0.25*randrange(1,2),0.25*randrange(1,2)# les cibles détectées se mettent en mouvement
" ATTENTION !!! A partir de ce moment, les cibles mises en mouvement sont DANGEREUSES. "
" Le serpent est détruit s'il entre à leur contact : il lui faut donc les détruire en priorité "
" et, sinon, les éviter "
if DQ[j]<0.97*nC:# collision du missile avec la cible visée
collisionM+=1
tirM=0
xC[j],yC[j],dxC[j],dyC[j],DC[j],DQ[j]=0,0,0,0,0,0# destruction de la cible
x[0],y[0]=x[1]-dx[1],y[1]-dy[1]# le missile revient à sa place (en queue du serpent)
can.create_rectangle(L-L*collisionM/nC,H-10,L-L*(collisionM-1)/nC,H,fill="grey",outline="blue")
can.create_text(L-50,H-15,text='missile',fill="white")
if tirM==0 :
x[0],y[0]=x[0],y[0]
######################################################################################
def collision_bordures(p,q,r,s,D):
" algorithme commun de collision avec les bordures "
global pp,qq,rr,ss
if p>L-D/2:pp,qq,rr,ss=L-D/2,q,-r,s
if p<D/2:pp,qq,rr,ss=D/2,q,-r,s
if q>H-D/2:pp,qq,rr,ss=p,H-D/2,r,-s
if q<D/2:pp,qq,rr,ss=p,D/2,r,-s
if p<=L-D/2 and p>=D/2 and q<=H-D/2 and q>=D/2:
pp,qq,rr,ss=p,q,r,s
def collisions(xa,ya,xb,yb,dxa,dya,dxb,dyb,da,db):
" algorithme commun de collisions entre cercles "
global rxa,rya,rxb,ryb
global rdxa,rdya
X,Y=xb-xa,yb-ya
Z=hypot(X,Y)
if Z<=(da+db)/2:
dX,dY=dxb-dxa,dyb-dya
dZ=hypot(dX,dY)
if dZ==0:m=0
else:
k,K=dZ*dZ,X*dX+Y*dY
m=(K+sqrt(K*K-k*(Z*Z-(da+db)/2*(da+db)/2)))/k
rxa,rya,rxb,ryb=xa-m*dxa,ya-m*dya,xb-m*dxb,yb-m*dyb
X,Y=rxb-rxa,ryb-rya
Z=hypot(X,Y)
if Z<=(da+db)/2:
dxb,dyb=0,0
dX,dY=dxb-dxa,dyb-dya
dZ=hypot(dX,dY)
if dZ==0:m=0
else:
k,K=dZ*dZ,X*dX+Y*dY
m=(K+sqrt(K*K-k*(Z*Z-(da+db)/2*(da+db)/2)))/k
rxa,rya,rxb,ryb=xa-m*dxa,ya-m*dya,xb-m*dxb,yb-m*dyb
xx,xy,yy=X*X/Z/Z,X*Y/Z/Z,Y*Y/Z/Z
rdxa,rdya=(yy-xx)*dxa-2*xy*dya,-2*xy*dxa-(yy-xx)*dya
else:
rxa,rya,rxb,ryb=xa,ya,xb,yb
rdxa,rdya=dxa,dya
######################################################################################
# Fonctions de déplacement des touches :
def left(event):
" S à gauche "
global u,v,du,dv,GC
GC+=1
u,v,du,dv=x[nS-1],y[nS-1],dx[nS-1],dy[nS-1]
def right(event):
" S à droite "
global u,v,du,dv,DR
DR+=1
u,v,du,dv=x[nS-1],y[nS-1],dx[nS-1],dy[nS-1]
def up(event):
" S vers le haut "
global u,v,du,dv,HT
HT+=1
u,v,du,dv=x[nS-1],y[nS-1],dx[nS-1],dy[nS-1]
def down(event):
" S vers le bas "
global u,v,du,dv,BS
BS+=1
u,v,du,dv=x[nS-1],y[nS-1],dx[nS-1],dy[nS-1]
def tirer_fleche(event):
" commande touche < Espace > "
global vF,tirF
tirF=1
vF=10
def tirer_missile(event):
" commande touche < x > ou < X > "
global tirM
tirM=1
def activer_touches():
""
root.bind("<Left>",left)
root.bind("<Right>",right)
root.bind("<Up>",up)
root.bind("<Down>",down)
def desactiver_touches():
""
root.unbind("<Left>")
root.unbind("<Right>")
root.unbind("<Up>")
root.unbind("<Down>")
######################################################################################
def destruction():
" message explicatif "
stop()
can.delete(texte)
texte2=can.create_text(L/2,420,text='''Le serpent a été détruit après collision avec une cible mobile (de couleur verte) !\n\n
Lorsque le serpent tire un missile, il peut arriver que plusieurs cibles fixes soient détectées.
Dans ce cas, les cibles détectées changent de couleur : elles passent du marron au vert.
et, surtout, elles entrent en mouvement.
Le missile se dirige vers la première détectée et la détruit.
Mais les autres cibles, devenues mobiles, sont dangereuses pour le serpent.
Elles doivent être détruites le plus rapidement possible et, surtout, absolument évitées.\n\n
Vous pouvez continuer en appuyant sur : Mise en place !
et, sinon, sur : Quitter le jeu !\n''',fill="white",font="Arial 12")
######################################################################################
def stop():
" arrêt des mouvements et mise à zéro de tous les compteurs "
global flag,tirF,collisionF,tirM,collisionM,activationF,GC,DR,HT,BS,texte,arrivée,activation_cases
ST.configure(state=DISABLED)
LJ.configure(state=DISABLED)
MP.configure(state=NORMAL)
avertissement.configure(bg="brown",fg="brown")
flag=0
tirF,collisionF=0,0
tirM,collisionM=0,0
root.bind("<Left>",left)
root.bind("<Right>",right)
root.bind("<Up>",up)
root.bind("<Down>",down)
GC,DR,HT,BS=0,0,0,0
for i in range(0,nO):can.delete(O[i])
for i in range(0,nC):can.delete(C[i]),can.delete(Q[i])
texte=can.create_text(L/3,100,text='''MERCI\net\nn' hésitez pas à commenter (et à coter...) ce script !''',fill="white",font="Arial 12")
top_end=time()
activationF=0
activation_cases=1
def quitter():
" façon classique de quitter l'application "
ans=askokcancel('Serpent PYTHON',"Voulez-vous réellement quitter ?")
if ans:root.quit()
def sapin():
" petit dessin en guise de récompense !!!"
can.create_polygon(400,400 ,385,455 ,415,455,fill="green")
can.create_polygon(400,440 ,375,495 ,425,495,fill="green")
can.create_polygon(400,480 ,365,530 ,435,530,fill="green")
can.create_polygon(400,510 ,355,570 ,445,570,fill="green")
can.create_polygon(400,540 ,345,610 ,455,610,fill="green")
can.create_rectangle(392,610 ,408,625 ,fill="green")
a,b,c=randrange(0,800),randrange(0,800),randrange(2,8)
can.create_oval(a,b,a+c,b+c,fill="white")
######################################################################################
def presentation():
"Fenêtre-message contenant la description sommaire du principe du jeu"
msg =Toplevel()
Message(msg, bg ="dark green", fg ="white", width =810,font ="Arial 10",
text =''' PRESENTATION\n
Au lancement du jeu, le bouton < Mise en place > fait apparaître:\n
- le serpent PYTHON constitué de 40 cercles de diamètres décroissants, de la tête vers la queue
- la FLECHE (rétractable) du serpent : cercle blanc placé au niveau du nez
- le MISSILE (à autoguidage terminal) : petit cercle blanc situé en queue
- 10 obstacles fixes indestructibles de couleur bleue et de même diamètre
(sur lesquels rebondissent serpent, flèche et missile)
- 39 cibles à détruire, de couleur marron et de diamètre variable
(leurs abscisses ont des valeurs aléatoires, leurs ordonnées sont échelonnées régulièrement)
(ces cibles sont toute entourées d'un cercle de détection dont le diamètre est constant au départ, puis variable ensuite)\n\n
Le jeu consiste pour le serpent à détruire les 39 cibles, le plus rapidement possible, sans être lui-même détruit.
(la durée de la partie et le nombre de cibles détruites sont affichés à droite de la fenêtre de jeu)\n
Les moyens dont le serpent dispose sont:
- sa FLECHE, qui peut être tirée par pression rapide ou continue sur la touche < Espace > du clavier
- le MISSILE, qui est tirable par pression rapide sur la touche < X > du clavier
(la progression des destructions est visualisée en bas du plan de jeu)\n\n
Utilisation de la FLECHE\n
Au début, les tirs de la flèche doivent être précis pour pouvoir détruire les cibles.
Ils deviennent plus faciles ensuite, car la distance d'interception augmente lentement avec le nombre de succès.
Mais il ne sont pas sans risques pour le serpent, car à une certaine occurence, fonction du niveau de jeu choisi, cette flèche s'active.
Ceci a pour effet, lors du tir suivant, de neutraliser sa capacité de destruction, et surtout de mettre en mouvement les cibles détectées.
Il y a alors DANGER de DESTRUCTION pour le serpent, en cas de collision avec celles-ci.
Une fois tirée, la flèche se désactive, et les tirs sans risques redeviennent possibles...jusqu'à l'activation suivante.\n
Utilisation du MISSILE\n
Après tir par le serpent dans la zone de détection d'une cible, le missile se réoriente pour se diriger vers le centre de la cible.
La cible entre en mouvement, sa couleur passe au vert, son cercle de détection se rétracte, puis elle disparait.
Lorsqu'une ou plusieurs autres cibles sont aussi détectées, elles deviennent également mobiles; leur couleur passe aussi au vert.
Le missile reprend sa place, en queue du serpent, et peut à nouveau être tiré.
Mais il y a alors DANGER pour le serpent, puisque ces cibles sont mobiles.\n
En fin de partie, l'utilisation des flèches (haut,bas,gauche,droite) du clavier pourra permettre de gagner du temps.
Elles modifient la direction de marche du serpent.\n
Pour réussir une partie, une combinaison des deux types de tir sera nécessaire pour éviter la destruction du serpent.
Avec un peu d'entrainement, on parviendra au niveau 5, le plus intéressant.\n\n''').pack(padx =10, pady =10)
def processus():
"Fenêtre-message contenant la description du processus de jeu"
msg =Toplevel()
Message(msg, bg ="dark green", fg ="white", width =450,font ="Arial 10",
text='''PROCESSUS à suivre\n\n
1. Choisir le niveau de jeu
(cinq valeurs possibles : 1, 2, 3, 4, 5)\n
2. Cliquer sur le bouton < Mise en place ! >\n
3. puis sur le bouton < Lancer le jeu ! >\n
4. Tir avec la flèche rétractable :
appuyer sur la touche < Espace > du clavier\n
5. Tir d'un missile :
appuyer sur la touche de la lettre < X > du clavier\n
6. Changement de direction du serpent :
utiliser les quatre flèches du clavier
(haut, bas, gauche, droite)\n
7. Bouton < Stop !>
pour arrêter les mouvements\n
8. Bouton < Quitter le jeu !>
pour abandonner la partie\n''').pack(padx =10, pady =10)
def aPropos():
"Fenêtre-message indiquant les versions utilisées"
msg =Toplevel()
Message(msg, width =200, aspect =100, justify =CENTER,
text ='''Serpent PYTHON
HCD, Décembre 2005
Python version 2.4.2
Tk version 8.4''').pack(padx =10, pady =10)
######## Programme principal ############################################
root = Tk()
root.title('>>>>>>> Serpent PYTHON <<<<<<<')
f=1
L,H=800*f,800*f
flag=0
d=10
n=1.5
V=0
tirF,collisionF=0,0
tirM,collisionM=0,0
activationF=0
u,v=0,0
GC,DR,HT,BS=0,0,0,0
iG,iD,iH,iB=0,0,0,0
score_time=0
top_end=0
J=0
activation_cases=1
# mise en place des deux canevas
can=Canvas(root,bg='dark green',height=H,width=L)
can.grid(row=1,column=0,rowspan=2)
can2=Canvas(root,bg='brown',highlightbackground='brown')
can2.grid(row=1,column=1,sticky=N)
# commandes à partir du clavier
root.bind("<Left>", left)
root.bind("<Right>", right)
root.bind("<Up>", up)
root.bind("<Down>", down)
root.bind('<space>', tirer_fleche)
root.bind('x', tirer_missile)
root.bind('X', tirer_missile)
#Avertissement
can.total_destruction=Label(can2,text='0',fg='white',bg='brown')
can.total_destruction.pack(side=BOTTOM)
Label(can2,text="Nombre de cibles détruites",fg='white',bg='brown').pack(side=BOTTOM)
texte3='''ATTENTION !!!
La flèche du serpent
est passée au BLEU
Le prochain tir est risqué !
CONSEIL
Tirer le missile !
(La flèche repasse au BLANC
ensuite)'''
avertissement=Label(can2,text=texte3,height=13,width=24,relief=GROOVE,font='BOLD',bg="brown",fg="brown",command=None)
avertissement.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
# Score (durée de la partie)
can.score=Label(can2,text='0',fg='white',bg='brown')
can.score.pack(side=BOTTOM)
Label(can2,text="Temps écoulé",fg='white',bg='brown').pack(side=BOTTOM)
# Menu <Règle du jeu>
RdJ = Menubutton(can2, text ='Règle du jeu',height=2,width=35,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='A propos ...',underline=0,command=aPropos)
RdJ.configure(menu=me1)
# Boutons de commande à partir de la fenêtre Tkinter
Button(can2,text='Quitter le jeu !',height=2,width=35,relief=GROOVE,bg="white",command=quitter).pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
ST=Button(can2,text='Stop !',height=2,width=35,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=stop)
ST.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
LJ=Button(can2,text='Lancer le jeu !',height=2,width=35,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=lancer_le_jeu)
LJ.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
MP=Button(can2,text='Mise en place !',height=2,width=35,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=mise_en_place)
MP.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
# Niveau de jeu
Label(can2,text='''Choisir le niveau de jeu''',fg='white',bg='brown').pack(padx=5,pady=5,side=BOTTOM)
niveau=["1","2","3","4","5"]
choix_niveau=IntVar()
choix_niveau.set(niveau[0])
for i in range(0,5):
rad=Radiobutton(can2,text=str(i+1),variable=choix_niveau,value=niveau[i],command=niveau_jeu)
rad.pack(padx=6,pady=5,side=LEFT)
#root.resizable(0,0)
root.config(bg="brown")
root.mainloop()
root.destroy()
Conclusion :
Commentaires et cotations seront les bienvenus !
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.