#26 Le 12/05/2008, à 00:48
- nicolas66
Re : [Python] Projet de casse-briques (maj 23/05 : v0.3.1.1)
Je connais pas trop XML (je pensais à un bête fichier texte)
L'avantage du XML est que tu n'auras pas à écrire le parseur et que tu pourras facilement étendre les fonctionnalités du format de ton fichier.
Exemple
<?xml version="1.0"?>
<casse-briques>
<level name="Premier niveau">
<bloc color="orange" points="10" item="new_life" />
<bloc color="red" points="8" />
<bloc color="red" points="9" />
...
</level>
...
</casse-briques>
Ca me donne trop envie de me faire un casse-briques en C++ / SDL
"The computer was born to solve problems that did not exist before." (B. Gates)
Hors ligne
#27 Le 12/05/2008, à 09:26
- Abu
Re : [Python] Projet de casse-briques (maj 23/05 : v0.3.1.1)
Excellente idée C'est exactement ce qu'il me faut !!
Je vais remanier un peu mes classes pour me préparer à ça
PS: Voilà la version 0.2.5 où la gestion de la souris est vraiment nickelle
(à part que le curseur est toujours visible...c'est couillon qu'ils n'aient pas pensé à mettre un cursor='none'...)
PS2 : Comme mon programme commence à prendre un peu d'ampleur (merci à tous de vos encouragements c'est vraiment hyper motivant ), j'ai changé de nom (arkython c'était trop moche). Maintenant c'est arkapython.
Abu(ntu)
Edit : Suppression du source de la version 0.2.5 remplacée par la 0.3 ci-dessous
Dernière modification par Abu (Le 12/05/2008, à 10:42)
Hors ligne
#28 Le 12/05/2008, à 10:41
- Abu
Re : [Python] Projet de casse-briques (maj 23/05 : v0.3.1.1)
Bon ben voilà ça ressemble VRAIMENT à un casse-briques
Le curseur de la souris est enfin invisible (merci encore mutah)
Donc voilà la version 0.3 de arkapython
Si vous avez essayé les autres, essayez celle là c'est la plus aboutie
Maintenant c'est plus qu'une question de fonctionnalités (menus, messages quand on perd, niveau dans un fichier, sons,.....) et de retouchage un peu de code (la classe Application est devenue hyper bordélique il va falloir que je trie un peu ça) mais l'interface est là et bien là
Enjoy
Abu(ntu)
#!/usr/bin/env python
# -*- coding:Utf-8 -*-
###############################################################################
## #
## /\ #
## /! \ Nécessite d'installer python-xlib et python-tk #
## ----- #
## #
###############################################################################
## #
## Arkapython v0.3 par Abu #
## (12/05/2008) #
## #
## Un petit casse-briques sans prétention aucune , en Python #
## (mais qui commence à ressembler à quelque choe...) #
## #
###############################################################################
## Commandes : #
## ----------- #
## - Boutton gauche : Lance la balle ou met en pause #
## - Boutton droite : Libère la souris #
## - Esc : Quitter #
## - Ctrl+w : Cheat. Avance d'un niveau et donne 10 vies (pour les tests)#
## #
###############################################################################
## #
## Merci à la communauté de ubuntu-fr pour ses encouragements #
## Merci également à Gérard Swinnen pour son excellent cours #
## "Apprendre à programmer avec Python" #
## Dispo librement ici : http://www.ulg.ac.be/cifen/inforef/swi #
## #
## Vous pouvez bien sûr tout réutiliser absolument comme vous voulez :-) #
## Je roule en GPL (le gasoil c'est pas écolo...) #
## Je pense qu'on peut facilement récupérer les classes Raquette et Balle #
## pour faire un pong ^_^ (voire un pong en réseau , troooop bien !!) #
## #
## Enjoy ;-) #
## #
## PS: Python c'est vraiment trop bien :) #
## #
###############################################################################
## Maj 0.3 : Pointeur de la souris invisible. Là c'est un casse-briques :))#
## -------- #
## #
## Maj 0.2.5 : #
## ---------- #
## - Amélioration de le gestion de la souris #
## C'est nikel, plus qu'à rendre le curseur invisible #
## - Changement de nom (je pensais que arkapython existait déjà :P) #
## #
## Maj 0.2.4 : Gestion de la souris #
## ---------- #
## #
## Maj 0.2 : #
## --------- #
## - Implantation de la classe Brique-> Gros progrès #
## - Changement de la façon dont sont crées les niveaux #
## Maintenant ils sont personnalisables et créés dans une matrice #
## - Graphisme old school à la pong :-P #
## - Changement du comportement de la balle (un peu de random) #
## #
## A faire : #
## ---------- #
## Au niveau du jeu : #
## - Revoir les collisions avec les briques (petits bugs) #
## #
## Au niveau du code : #
## - Booléens pour les variables de contôle #
## - Peut-être dériver les classe Raquette et Balle d'une même classe #
## #
## Evolution possibles : #
## - Un menu (difficulté , high-scores , skin ,...) #
## - Messages quand on a perdu ou lv up #
## - Niveaux à stocker dans un fichier #
## #
###############################################################################
## Importation des modules
from Tkinter import Tk, Canvas, Label, Button, Frame
from random import randrange, uniform
import Xlib.display
import os
## Création d'un curseur invisible
kNullCursorData="""
#define t_cur_width 1
#define t_cur_height 1
#define t_cur_x_hot 0
#define t_cur_y_hot 0
static unsigned char t_cur_bits[] = { 0x00};
"""
## Création des classes
class Raquette:
""" Classe de définition de la raquette"""
def __init__(self , canev , x , y , larg = 50 , haut = 30):
"""Initialisation de la raquette"""
self.canev = canev
self.xmax = int(canev.cget('width')) ## Récupération des dimensions
self.ymax = int(canev.cget('height')) ## du canevas
## Coordonnées initiales
self.xdef = x
self.ydef = y
## Coordonnées actuelles
self.x = x
self.y = y
## Dimensions
self.larg = larg
self.haut = haut
## Coordonnées absolue du centre (pour placer la souris)
self.majcoordabs()
## Dessin
self.graph = canev.create_rectangle(self.x-self.larg , self.y , \
self.x+self.larg , self.y+self.haut , width = 2 , fill = 'white')
def __del__(self):
"""Destruction de la raquette : On l'efface"""
self.canev.delete(self.graph)
def redraw(self):
"""Redessine la raquette à la nouvelle position"""
self.canev.coords(self.graph , self.x-self.larg , self.y , \
self.x+self.larg , self.y+self.haut)
def deplace(self , delta):
"""Déplace la raquette de delta.
Renvoie True si le déplacement est possible"""
if (self.x-self.larg > -delta) and (self.x+self.larg < self.xmax-delta):
self.x = self.x+delta
self.majcoordabs()
self.redraw()
return True
else:
return False
def majcoordabs(self):
"""Calcul les coordonnées absolues du centre de la raquette"""
self.xabs = self.canev.winfo_rootx()+self.x
self.yabs = self.canev.winfo_rooty()+self.y+self.haut/2
class Balle:
"""Classe de définition de la balle"""
def __init__(self , canev , x , y , r =15 , v = 1):
"""Initialisation de la balle"""
self.canev = canev
## rayon
self.r = r
## Coordonnées initiales
self.xdef = x
self.ydef = y
## Coordonnées actuelles
self.x = x
self.y = y
## Vitesse (nombre de pixels à chaque déplacement)
self.v = v
## Direction
self.dirx = 1
self.diry = -1
## Dessin
self.graph = canev.create_oval(self.x-self.r , self.y+self.r , \
self.x+self.r , self.y-self.r , width = 2 , fill = 'white')
def __del__(self):
"""Destruction de la balle : On l'efface"""
self.canev.delete(self.graph)
def redraw(self):
"""Redessine la balle à la nouvelle position"""
self.canev.coords(self.graph , self.x-self.r , \
self.y-self.r , self.x+self.r , self.y+self.r)
def deplace(self):
""" Déplace la balle de v dans la direction (dirx , diry)"""
self.x += self.dirx*self.v
self.y += self.diry*self.v
self.redraw()
## Tests de Collisions
## -------------------
## Principe :
## On regarde pour chaque "point cardinal" de la balle
## s'il est dans un rectangle de test
## Si oui , on change la direction de la balle
##
## Ca marche mais c'est pas tip top vu que la balle est ronde
## Un calcul de distance avec le bord du rectangle serait plus judicieux
def test_haut(self , xa , ya , xb , yb):
""" Test si la balle a un contact au dessus"""
if (xa <= self.x <= xb)&(ya <= self.y-self.r <= yb):
self.diry = 1
self.dirx += uniform(-0.5 , 0.5)
return True
else:
return False
def test_bas(self , xa , ya , xb , yb):
""" Test si la balle a un contact en dessous"""
if (xa <= self.x <= xb)&(ya <= self.y+self.r <= yb):
self.diry = -1
self.dirx += uniform(-0.5 , 0.5)
return True
else:
return False
def test_gauche(self , xa , ya , xb , yb):
""" Test si la balle a un contact à sa gauche"""
if (xa <= self.x-self.r <= xb)&(ya <= self.y <= yb):
self.dirx = 1
self.diry += uniform(-0.5 , 0.5)
return True
else:
return False
def test_droite(self , xa , ya , xb , yb):
""" Test si la balle a un contact à sa droite"""
if (xa <= self.x+self.r <= xb)&(ya <= self.y <= yb):
self.dirx = -1
self.diry += uniform(-0.5 , 0.5)
return True
else:
return False
class Brique:
"""Classe de définition des briques"""
def __init__(self , canev , xa , ya , xb , yb , statut = 1 ):
"""Initialisation d'une brique"""
self.canev = canev
## Coordonnées
self.xa = xa
self.ya = ya
self.xb = xb
self.yb = yb
## Statut (nombre de coup pour la détruire)
self.statut = statut
## Couleur en fonction du statut
self.liste_couleurs = ['green' , 'yellow' , 'red']
self.couleur = self.liste_couleurs[self.statut-1]
## Dessin
if self.statut>0 :
self.graph = self.canev.create_rectangle(xa , ya , xb , yb , \
width=2 , fill = self.couleur)
def __del__(self):
"""Destructeur des briques : On l'efface si elle est là"""
if self.statut > 0 :
self.canev.delete(self.graph)
def redraw(self):
"""Redessine la brique"""
self.canev.coords(self.xa , self.ya , self.xb , self.yb)
def changestatut(self,statut):
"""Quand on touche une brique, on change son statut"""
self.statut = statut
self.couleur = self.liste_couleurs[self.statut-1]
self.canev.itemconfigure(self.graph,fill = self.couleur)
class Niveau:
"""Classe de définition des niveaux"""
def __init__(self , canev , lv = 1 ):
"""Initialisation du niveau"""
self.canev = canev
self.xmax = int(canev.cget('width'))
self.ymax = int(canev.cget('height'))
self.top = 100 ## Hauteur de la 1ère ligne
self.left = 50 ## Position de la 1ère colonne (marge gauche/droite)
## Récupération du numéro du lv
self.lv = lv
## Liste des briques du niveau
self.liste_briques = []
## serie : Serie de niveau:
## serie = 0 : Niveaux codés dans les matrices
## serie = 1 : rectangles
## serie = 2 : Niveaux aléatoires
self.serie = 0
## La liste suivante code tous les niveaux de la série 0
## C'est une liste de matrices
## dont chaque terme donne le statut de la brique
listelv = [ \
[ [3,2,3,2,3,2,3], \
[2,1,2,1,2,1,2], \
[0,0,0,0,0,0,0], \
[2,1,2,1,2,1,2], \
[3,2,3,2,3,2,3] ], \
[ [1,0,0,0,0,1], \
[0,3,1,1,3,0], \
[0,1,1,1,1,0], \
[1,1,2,2,1,1],
[0,1,0,0,1,0],
[1,0,0,0,0,1] ], \
[ [1,1,1,1,1,1,1], \
[1,3,3,1,3,3,1], \
[1,3,3,1,3,3,1], \
[1,1,1,1,1,1,1], \
[1,2,1,1,1,2,1], \
[1,1,2,2,2,1,1],
[1,1,1,1,1,1,1] ], \
[ [0,3,3,0,0,3,3,3,3,0,3,0,0,3], \
[3,0,0,3,0,3,0,0,3,0,3,0,0,3], \
[3,3,3,3,0,3,3,3,0,0,3,0,0,3], \
[3,0,0,3,0,3,0,0,3,0,3,0,0,3], \
[3,0,0,3,0,3,3,3,3,0,3,3,3,3] ] \
]
self.nblv = len(listelv) ## Nombre de niveaux codés
## Série 1 : 3 niveaux classiques rectangulaires
if self.nblv < self.lv <= self.nblv+3 :
self.serie = 1
s = self.lv-self.nblv
listelv = [[]]
for i in range(5):
listelv[0].append([s,s,s,s,s,s])
## Série 2 : Niveaux aléatoires
if self.lv > self.nblv+3 :
self.serie = 2
listelv = [[]]
for i in range(5):
ligne = []
for j in range(6):
ligne.append(randrange(4))
listelv[0].append(ligne)
## Création du level
if self.serie == 0 :
self.creer_level( listelv[ (self.lv-1) ] )
else:
self.creer_level( listelv[0] )
def __del__(self):
""" Destructeur : On efface toutes les briques restantes"""
i = 0
while i < self.nbrique:
self.liste_briques[i].statut = 1
self.detruire(i)
i += 1
def creer_level(self,liste):
"""Créé le tableau à partir d'une liste double,
codant le satut de chaque brique"""
## Nombres de briques horizontalement et verticalement
self.nbx = len(liste[0])
self.nby = len(liste)
## Dimension des briques
self.dimx = (self.xmax-2*self.left)/self.nbx
self.dimy = 30
self.nbrique = 0 ## Nombre de briques
## Construction des lignes
for j in range(self.nby):
## Construction des colonnes
for i in range(self.nbx):
## Les briques sont construites dans une liste
if liste[j][i] != 0 :
self.liste_briques.append( \
Brique(self.canev , \
self.left+self.dimx*i , \
self.top+self.dimy*j , \
self.left+self.dimx*(i+1) , \
self.top+self.dimy*(j+1) , \
liste[j][i] ) )
self.nbrique+=1
def detruire(self , num):
"""Détruit la brique numéro num"""
if self.liste_briques[num].statut > 1:
self.liste_briques[num].\
changestatut(self.liste_briques[num].statut-1)
elif self.liste_briques[num].statut == 1:
self.liste_briques[num].__del__
del self.liste_briques[num]
self.nbrique -= 1
class Application:
"""Programme principal"""
def __init__(self , dimx = 400 , dimy = 600):
"""Constructeur de l'interface"""
## Variables de jeu
self.maxtiming = 3
self.timing = self.maxtiming ## Vitesse de la balle
self.maxvie = 3
self.vie = self.maxvie ## Nombre de vies
self.lv = 1 ## Numéro du niveau
## Variables globales de contôle
self.lance = 0 ## 0: La balle est arêtée , 1: Elle est lancée
self.pause = 0 ## 0: Le jeu n'est pas en pause , 1:Pause
self.mousex , self.mousey = -1 , -1 ## Coordonnées de la souris
self.mouseauto = 0 ## 0: La souris est bougée par le joueur,
## 1: Le curseurest placé automatiquement
## 2: Le cureseur est libéré
## Initialisation de X11 pour la gestion de la souris
self.display = Xlib.display.Display()
self.screen = self.display.screen()
self.roots = self.screen.root
## Création du curseur invisible
os.umask(0177) # octal
f=open("invisiblecursor","w")
f.write(kNullCursorData)
f.close()
## Fenêtre de jeu
self.main = Tk()
self.main.title("Arkapython v0.3")
self.root=Frame(bg='black')
self.root.pack()
self.edlv = Label(self.root , text = ' NIVEAU : '+str(self.lv)+" " , \
font = "Courrier 25 bold" , bg = 'black' , fg = 'white')
self.edlv.grid(row = 1 , column = 1 , pady=5)
self.edvie = Label(self.root , text = ' VIES : '+str(self.vie)+" " , \
font = "Courrier 25 bold" , bg = 'black' , fg = 'white')
self.edvie.grid(row = 1 , column = 2)
self.dimx , self.dimy = dimx , dimy ## Dimensions du canevas
self.can = Canvas(self.root , bg = 'black' , cursor='@invisiblecursor white' , \
width = self.dimx , height = self.dimy)
self.can.grid(row = 2 , column = 1 , columnspan = 2 , \
padx = 5 , pady = 5)
Button(self.root , text = "Nouvelle partie" , \
font = "Arial 16 bold" , \
bg='black' , fg='white', relief='flat' , \
activebackground = 'red' , activeforeground = 'black' ,
command = self.newgame).\
grid(row = 3 , column = 1 , padx = 5 , pady = 5 , sticky ='W')
Button(self.root , text = "Quitter" , \
bg='black' , fg='white', relief='flat' , \
font = "Arial 16 bold" , \
activebackground = 'red' , activeforeground = 'black' ,
command = self.root.quit).\
grid(row = 3 , column = 2 , padx = 5 , pady = 5 , sticky ='E')
## Pour les tests. A virer
## -----------------------
## self.edtest = Label(self.root , text = ' Test : ' , \
## font = "Courrier 12 bold" , bg = 'black' , fg = 'white')
## self.edtest.grid(row = 0, column = 1 , columnspan = 2 , sticky='W')
## Button(self.root , text = "Test" , \
## bg='black' , fg='white', relief='flat' , \
## font = "Arial 16 bold" , \
## activebackground = 'red' , activeforeground = 'black' ,
## command = self.test).\
## grid(row = 4 , column = 2 , padx = 5 , pady = 5 , sticky ='E')
## Gestion des événements
self.can.bind('<Button-1>' , self.start)
self.can.bind_all('<Motion>' , self.bouge_raquette)
self.can.bind_all('<Control-w>',self.triche)
self.can.bind_all('<Escape>',self.quitter)
self.can.bind(('<Enter>','<Leave>'),self.rentresouris)
self.can.bind_all(('<Enter>','<Leave>'),self.rentresouris)
self.can.bind_all('<Button-3>',self.liberesouris)
## Création (instanciation) des objets du jeu
self.creer_raquette()
self.creer_balle()
self.creer_niveau()
## Partir sur de bonnes bases
self.root.update()
self.newgame()
self.test()
def test(self):
"""Fonction de test qui affiche des paramètres, à virer à terme"""
## x1=self.can.winfo_rootx()
## y1=self.can.winfo_rooty()
## x2=self.can.winfo_rootx()+self.raquette.x
## y2=self.can.winfo_rooty()+self.raquette.y+self.raquette.haut/2
## x3=self.raquette.xabs
## y3=self.raquette.yabs
## self.edtest.configure(text="Test : %s"%(self.mouseauto))
##
## self.root.after(1000,self.test)
pass
def centresouris(self):
"""Centre la souris sur la raquette"""
## On met à jour les coordonnées de la raquette
self.raquette.majcoordabs()
## On place la souris grace à xlib
self.roots.warp_pointer(self.raquette.xabs,self.raquette.yabs)
self.display.sync()
## Maj des coordonnées relatives de la souris
self.mousex = self.raquette.xabs-self.can.winfo_rootx()
## L'event généré ne doit pas déplacer la raquette
self.mouseauto = 1
def rentresouris(self,event):
"""Rentre la souris dans le canevas"""
if self.pause == 0 and self.mouseauto != 2:
self.can.configure(cursor='@invisiblecursor white')
self.centresouris()
def liberesouris(self,event):
"""Libère la souris"""
if self.mouseauto != 2:
self.mouseauto = 2
self.can.configure(cursor='arrow')
else:
self.can.configure(cursor='@invisiblecursor white')
self.centresouris()
def quitter(self,event):
"""Fermer l'appli"""
self.root.quit()
def creer_raquette(self):
"""Construit la raquette"""
self.raquette = Raquette(self.can , self.dimx/2 , self.dimy-100)
def creer_balle(self):
"""Construit la balle"""
r = 15 ## Rayon de la balle
self.balle = Balle(self.can , self.dimx/2 , self.dimy-100-r , r)
def creer_niveau(self):
"""Construit le niveau lv"""
self.niveau = Niveau(self.can , lv=self.lv)
def newgame(self):
""" Lance une nouvelle partie"""
self.setvie(self.maxvie)
self.setlv(1)
self.reinit()
def reinit(self):
"""Redessine un niveau complet"""
## Destruction et recréation des instances
self.raquette.__del__()
self.creer_raquette()
self.balle.__del__()
self.creer_balle()
self.niveau.__del__()
self.creer_niveau()
## Position de départ pour la raquette et la balle
self.stop()
def start(self , event):
"""Lance la balle ou met en pause/dépause"""
if self.lance == 0:
self.lance = 1
self.pause = 0
self.centresouris()
self.can.configure(cursor='@invisiblecursor white')
self.avance_balle()
elif self.lance == 1:
self.lance = 0
self.pause = 1
def stop(self):
"""Stop la balle et remet raquette+balle à leur position d'origine"""
self.lance = 0
self.pause = 0
self.raquette.x = self.raquette.xdef
self.raquette.y = self.raquette.ydef
self.raquette.redraw()
self.centresouris()
self.balle.x = self.raquette.x
self.balle.y = self.raquette.y-self.balle.r
self.balle.redraw()
self.balle.dirx = 1
self.balle.diry = -1
def triche(self,event):
"""Juste pour passer d'un niveau, pour les tester bien sûr ^_^ """
self.gagne()
self.setvie(10)
def gagne(self):
"""Si on gagne on passe d'un lv"""
self.setlv(self.lv+1)
self.reinit()
def perdu(self):
"""Si plus de vie"""
self.newgame()
def setvie(self , vie):
""" Met à jour le nombre de vies"""
self.vie = vie
self.edvie.configure(text = ' VIES : '+str(self.vie)+" ")
if self.vie == 0 :
self.edvie.configure(fg = 'red')
else:
self.edvie.configure(fg = 'white')
def settiming(self , n):
"""Change la vitesse de jeu"""
if n >= 1:
self.timing = n
def setlv(self , lv):
""" Met à jour le niveau"""
self.lv = lv
self.edlv.configure(text = ' NIVEAU : '+str(self.lv)+" ")
## A chaque niveau ça va un peu plus vite
## Tous les 2 niveaux on gagne une vie
self.settiming(max(self.maxtiming-(self.lv-1)/2,2))
if lv > 1:
self.setvie(self.vie+self.lv%2)
def bouge_raquette(self , event):
"""Gestion de la raquette à la souris, réponse à l'event <Move>"""
## Si on veut vraiment avoir le curseur
if self.mouseauto == 2 :
return
## Si le curseur a été positionné automatiquement, on sort
elif self.mouseauto == 1 :
self.mouseauto = 0
return
## Si le joueur à réellement bougé la souris
elif self.mouseauto == 0 :
## Initialisation de la position de la souris
if self.mousex == -1:
self.mousex = int(event.x)
else:
## Calcul de la variation de position
delta = int(event.x)-self.mousex
## Mise à jour des nouvelles coordonnées
self.mousex = int(event.x)
## Test si le jeu n'est pas en pause
if self.pause == 0:
## On essaie de déplacer la raquette
if self.raquette.deplace(delta):
## Si position de départ on bouge aussi la balle
if self.lance == 0:
self.balle.x = self.raquette.x
self.balle.y = self.raquette.y-self.balle.r
self.balle.redraw()
## Si on peut pas c'est qu'on est sur un bord
## et on replace le curseur au centre de la raquette
else:
self.centresouris()
def test_bords(self):
"""Test si la balle touche un bord de l'écran ou la raquette"""
## Test si la balle touche les bords du jeu
self.balle.test_haut(0 , 0 , self.dimx , 5)
self.balle.test_droite(self.dimx-5 , 0 , self.dimx , self.dimy)
self.balle.test_gauche(0 , 0 , 5 , self.dimy)
## Test si la balle touche la raquette
self.balle.test_bas(self.raquette.x-self.raquette.larg-5 , \
self.raquette.y , \
self.raquette.x+self.raquette.larg+5 , \
self.raquette.y+10)
def test_briques(self):
"""Test si une brique est touchée et la supprime si c'est le cas"""
## Tolérance de la zone de test : La plus petite dimension d'une brique
tol = min(self.niveau.dimx,self.niveau.dimy)
if self.niveau.nbrique > 0:
## S'il reste des briques en jeu
num = 0
## Parcours de la liste des briques
for brique in self.niveau.liste_briques:
exist = brique.statut
x1 = brique.xa
y1 = brique.ya
x2 = brique.xb
y2 = brique.yb
if exist >= 1:
## Principe :
## Si la brique est encore en jeu ,
## On test si la balle la touche dans chaque direction
## Si c'est le cas , on la détruit (avec sa méthode)
## et on sort de la boucle
if self.balle.test_haut(x1 , y2-tol , x2 , y2):
self.niveau.detruire(num)
break
elif self.balle.test_bas(x1 , y1 , x2 , y1+tol):
self.niveau.detruire(num)
break
elif self.balle.test_droite(x1 , y1 , x1+tol , y2):
self.niveau.detruire(num)
break
elif self.balle.test_gauche(x2-tol , y1 , x2 , y2):
self.niveau.detruire(num)
break
num+=1
else:
## Si plus de brique on a fini le lv
self.gagne()
def test_mort(self):
"""Test si la balle passe sous la raquette"""
if self.balle.y >= self.raquette.y+self.raquette.haut:
if self.vie > 0:
self.setvie(self.vie-1)
elif self.vie == 0:
self.perdu()
self.stop()
def avance_balle(self):
"""Boucle de déplacement de la balle"""
if self.lance == 1:
self.test_bords()
self.balle.deplace()
self.test_briques()
self.test_mort()
self.root.after(self.timing , self.avance_balle)
## Lancement du prog principal
app = Application()
app.root.mainloop()
Dernière modification par Abu (Le 12/05/2008, à 11:15)
Hors ligne
#29 Le 12/05/2008, à 10:56
- poupoul2
Re : [Python] Projet de casse-briques (maj 23/05 : v0.3.1.1)
Juste une remarque concernant ton post: remets plutôt systématiquement la dernière version de ton script dans le premier post. ca permet de suivre plus facilement l'évolution de la chose.
Ca tombe bien : Je me lance un peu dans la programmation et Python m'a l'air parfait pour débuter. En tout cas, pour le moment, je comprends tout. Je vais étudier ton script à la loupe (le code ouvert, c'est vraiment top pour ça)
Accessoirement, je vais m'amuser un peu aussi
#30 Le 12/05/2008, à 11:10
- Abu
Re : [Python] Projet de casse-briques (maj 23/05 : v0.3.1.1)
C'est fait. C'est vrai que c'est une bonne idée (mais je laisse quand même la 1ère qui est assez simple pour les débutants qui voudraient étudier le source)
En tous cas si tu as des questions sur mon script n'hésite pas
Abu(ntu)
Hors ligne
#31 Le 12/05/2008, à 19:44
- aleph
Re : [Python] Projet de casse-briques (maj 23/05 : v0.3.1.1)
> La gestion unicode de python est tellement pointilleuse qu'elle semble avoir été remaniée de fond en comble avec python 3.0
> La gestion unicode de python est tellement pointilleuse...
Non, elle n'est pas spécialement pointilleuse et Python n'est pas en cela
fondamentalement supérieur à d'autres langages.
Ce que Python fait (depuis 2.3), et que d'autres outils ne font pas, est d'exposer
à l'utilisateur par défaut et nativement les codages de caractères. Python propose
d'office la panoplie d'outils permettant de travailler avec les codages. Principalement,
les fonctions/méthodes encode() et decode() des types/classes str et unicode.
D'autres outils (langages) sont parfois plus stricts et imposent implicitement l'utilisation
d'un codage donné.
Python a certainement fait prendre conscience à bien des utilisateurs les notions
de codage.
> ... été remaniée de fond en comble avec python 3.0
C'est un peu la motivation de mon intervention. Attention à ne pas (déjà)
répandre des informations incorrectes.
Dans Python 3, la gestion unicode n'a pas été remaniée (en laissant de côté
les petites améliorations). Elle correspond à celle de Python 2.3, 2.4, 2.5, 2.6.
Dans Python 3, le type unicode de Python 2.* disparaît. Le type str de Python 3.0
est ce qu'est unicode dans Python 2.*.
Pour les amateurs de Python, la version alpha 5 de Python 3.0 est disponible
depuis quelques jours.
http://python.org/
Pour les intéressés aux nouveautés de Python 3 :
http://docs.python.org/dev/3.0/
Petite illustration
>>> import sys
>>> sys.version
'3.0a5 (py3k:62932M, May 9 2008, 16:23:11) [MSC v.1500 32 bit (Intel)]'
>>> u = 'élève'
>>> type(u)
<class 'str'>
>>> u.encode('unicode_internal')
b'\xe9\x00l\x00\xe8\x00v\x00e\x00'
>>> len(u.encode('unicode_internal'))
10
>>> import sys
>>> sys.version
'2.5.2 (r252:60911, Feb 21 2008, 13:11:45) [MSC v.1310 32 bit (Intel)]'
>>> u = u'élève'
>>> type(u)
<type 'unicode'>
>>> u.encode('unicode_internal')
'\xe9\x00l\x00\xe8\x00v\x00e\x00'
>>> len(u.encode('unicode_internal'))
10
>>>
#32 Le 13/05/2008, à 21:52
- Abu
Re : [Python] Projet de casse-briques (maj 23/05 : v0.3.1.1)
Bon voici la dernière version du jour : Arkapython v0.3.0.1, dispo sur la 1ère page (Il parait qu'il faut realeaser souvent non ? J'ai lû ça quelque part ^_^)
J'ai pas mal retravaillé le code et le gameplay, ainsi que les commentaires (voir le change log)
J'attends vos avis avec impatience, et surtout des idées, voire un coup de main pour certains trucs si certains se sentent motivés à participer
En fait surtout l'implantation de lv en XML qui est une priorité. Bon je pourrais toujours me dépatouiller (ça c'est clair)
Et aussi l'organisation générale des classes j'avoue je suis un peu paumé pour les faire communiquer proprement et les organiser, ça commence à être un beau foutoir (c'est la 1ere fois que je fais de l'objet si si... du moins que je crée mes propres classes pour un projet (je connaissais bien le principe hein...) ) et plein de petites questions très simples mais qui me prennent un temps fou (mais j'apprends la masse de trucs là...j'enquille doc après doc (8 pdf d'ouverts sur mon bureau ) )
Donc si ça dit à qqun de s'amuser un peu sur ce projet avec moi ben welcome
Abu(ntu)
Hors ligne
#33 Le 13/05/2008, à 21:52
- cat_loic
Re : [Python] Projet de casse-briques (maj 23/05 : v0.3.1.1)
J'ai testé la dernière version, pour l'étude du code, je verrais un peu plus tard (quand j'aurais le temps : je suis pas encore très objet ).
Au début j'avais un peu peur que le design ne soit pas très joli (Tkinter...), mais l'idée de n'y faire que comme ça est très bonne, ça me rappelle xjump (aussi connu sous le nom de sdljump), c'est vraiment pas mal
Petit rapport de bug : la vitesse de la balle : je ne trouve pas très fluide les changements de vitesse de la balle : parfois quand elle va un peu vite et qu'elle rebondi sur un bord, elle va subitement lentement, du coup on a pas le temps de s'habituer à une vitesse fixe...
Enfin : pour le blocage de la souris dans la fenêtre, je serais plutôt contre, j'ai de mauvais souvenir venant de logiciels utilisant cette technique... Par exemple pour quitter, je ne sais pas pourquoi mais je ne pouvais plus cliquer sur le bouton, j'ai du faire Esc (heureusement que les bind ont été prévus ).
Pour conclure : je suis moi aussi assez bluffé par la qualité du programme, il est certes améliorable, mais pour une première version comme ça, c'est vraiment bluffant !
edit : arf, je vais tester la 3.0.1
Dernière modification par cat_loic (Le 13/05/2008, à 21:53)
Hors ligne
#34 Le 13/05/2008, à 22:00
- Abu
Re : [Python] Projet de casse-briques (maj 23/05 : v0.3.1.1)
Merci pour le rapport de bug
J'avais prévu dès le départ le coup de la souris bloquée
Normalement avec le bouton droit tout devrait bien se passer (juste un détail à régler (léger conflit bouton droit/gauche mais rien de grave)
Pour l'instant c'est la seule solution que j'aie trouvée
Quand à la vitesse de la balle normalement c'est réglé aussi (encore que j'aie pas eu le temps de tester à fond (je code depuis que je suis rentré du boulot même pas eu le temps de jouer ^_^)). Est-ce que tu as la 0.3.0.1 ?
Merci du compliment, c'est vrai que le look old school j'aime beaucoup et je compte rester là dessus
Abu(ntu)
Hors ligne
#35 Le 13/05/2008, à 22:09
- cat_loic
Re : [Python] Projet de casse-briques (maj 23/05 : v0.3.1.1)
Merci pour le rapport de bug
J'avais prévu dès le départ le coup de la souris bloquée
Normalement avec le bouton droit tout devrait bien se passer (juste un détail à régler (léger conflit bouton droit/gauche mais rien de grave)
Pour l'instant c'est la seule solution que j'aie trouvéeQuand à la vitesse de la balle normalement c'est réglé aussi (encore que j'aie pas eu le temps de tester à fond (je code depuis que je suis rentré du boulot même pas eu le temps de jouer ^_^)). Est-ce que tu as la 0.3.0.1 ?
Merci du compliment, c'est vrai que le look old school j'aime beaucoup
et je compte rester là dessus
Abu(ntu)
Je viens de tester, le problème de vitesse semble avoir disparu (loi de Murphy ??), mais par contre c'est la direction de la balle cette fois qui a attiré mon attention : quand elle avait une trajectoire presque horizontale en descendant, normalement elle aurait du mettre un petit bout de temps avant d'arriver tout en bas, sans changer de direction, et tout d'un coup elle est partie vers le bas, avec une trajectoire plus verticale.
Pour le curseur : oui effectivement, en cliquant (gauche), la pause se met et on peut sortir le curseur (et cliquer sur les boutons) .
Ha, et au bout d'un petit temps de jeu, on se rend compte que la fenêtre est trop petite ^^ . Parce que en testant 5 minutes, ça va, mais quand on veut jouer sérieusement, on se rend compte qu'une fenêtre plus grande serait la bienvenue .
edit : et je ne peux pas me retenir : gg pour le jeu de mot en signature ^^' .
Dernière modification par cat_loic (Le 13/05/2008, à 22:09)
Hors ligne
#36 Le 13/05/2008, à 23:03
- Abu
Re : [Python] Projet de casse-briques (maj 23/05 : v0.3.1.1)
Pour la vitesse j'ai normalisé le vecteur vitesse. Donc la vitesse est constante (avant il y avait une composante =+-1 et une composante aléatoire ce qui provoquait les changements de vitesse)
Par contre le changement subit de direction c'est pas prévu ça
Ca doit être une brique invisible. Mes collisions sont pas top (ça faut vraiment que j'y retravaille en détail, ça devient urgent, en plus c'est une des parties les plus intéressantes) et des fois en un coup ça touche plusieurs fois la balle, donc elle disparait de suite.
Si ça se reproduit, dans la classe Brique il y a une liste de couleurs. Change 'black' en 'blue' pour voir les briques invisibles et si c'est ça.
En essayant (vite fait) d'autres casses briques j'ai vu qu'ils ont tous des toutes petites balles ce qui facilite le test. Moi je veux rester avec une balle de ping pong (change le paramètre r de la classe Balle pour t'amuser, mais trop gros ça bug encore plus)
Pour la taille de la fenêtre le canevas est en 400*600
Qu'est ce que tu suggérerais ? (tu peux tester en changeant dimx et dimy dans Application.__init__(...), mais les tailles risquent de ne pas toutes suivre, j'ai encore pas mal de nettoyage de code à faire )
Parce que je me suis posé la question et je ne sais pas quoi mettre pour que ça reste compatible avec les écran plus petit tout en étant jouable...J'avais testé genre 1000*1200 et ça claque
De toutes façons j'ai prévu d'implémenter un menu, je mettrai un réglage pour ça
Merci encore de tes tests ça me rend bien service
Abu(ntu)
Hors ligne
#37 Le 14/05/2008, à 02:31
- nicolas66
Re : [Python] Projet de casse-briques (maj 23/05 : v0.3.1.1)
Bon j'ai testé la nouvelle version et je confirme que les collisions souffrent de quelques problèmes. Exemple : ma balle monte en rebondissant contre les murs puis reviens en faisant le trajet inverse avant de toucher la moindre brique.
Les boutons sont devenus inaccessibles et ca manque un peu de son . Concernant les collisions, tu devrais pouvoir tester en temps constant si la balle se trouve à l'endroit d'une brique ou pas. Suffirait de passer de l'espace "continu" du canvas au repère "discret" du tableau 2d de briques (2 divisions).
Bref, ca fait plaisir, ca avance vite et bien, continue
"The computer was born to solve problems that did not exist before." (B. Gates)
Hors ligne
#38 Le 14/05/2008, à 07:20
- Abu
Re : [Python] Projet de casse-briques (maj 23/05 : v0.3.1.1)
Pour les rebonds de la balle, je ne sais pas trop comment m'y prendre :
Si le rebond reste symétrique par rapport à la normale, ben la balle fait toujours les 4 mêmes angles (penser à un losange). C'est ce que j'avais au début.
Du coup à chaque contact, je rajoute un nombre aléatoire entre -0.5 et 0.5 (c'est peut-être trop) à une composante (et l'autre vaut +-1) (voir la fonction Balle.test_haut()). Donc il se peut que s'il y a plusieurs rebonds successifs dans le même axe (par ex verticale) la composante en x change de signe, d'où retour de la balle...
Pas mal l'idée de passer en coordonnées discrètes. Je vais regarder ça de plus près.
A priori je pensais rajouter les 4 points de contact en diagonal à 45° (modulo 90°) (NE,SE,SW et NW) de la balle. Par ex pour test_haut, tester N, NW et NE.
De toutes façon faut que je retravaille ça en détail maintenant que l'interface est bien avancée car c'est quand même le coeur du jeu (rebonds, et tests de collisions)
Pour les boutons normalement on sort la souris de la fenêtre de jeu avec un clique droit (si ça ne marche pas c'est qu'il y a une erreur que j'ai pas vu)
En ce qui concerne le son je cherche une bibliothèque qui permette de générer des sons sans passer par un fichier externe car j'adore le concept du source à copier-coller ^^ (du moins pour l'instant). Ca me rappelle le bon vieux temps et c'est pratique à distrbuer.
A l'époque du basic (sur MSX ça date pas d'hier) j'avais une commande "sound" qui générait une wave, si je pouvais retrouver l'équivalent je pourrais faire un truc pas mal je pense.
Abu(ntu)
Hors ligne
#39 Le 14/05/2008, à 10:08
- XGouchet
Re : [Python] Projet de casse-briques (maj 23/05 : v0.3.1.1)
Ce que font beaucoup de casse brique, c'est faire un rebond symétrique pour les murs, et par contre modifier l'angle en fonction du palet (genre un palet un pet incurvé).
Tu peux aussi le faire avec la vitesse du palet.
Le problème de l'aléatoire est que le joueur ne le contrôle pas, du coup le "talent" de la frappe ne joue pas.
Life would be easier if they gave me the source code...
Mon Blog
Hors ligne
#40 Le 14/05/2008, à 18:28
- cat_loic
Re : [Python] Projet de casse-briques (maj 23/05 : v0.3.1.1)
Pour le son, il y a la solution ultime, mais qui va demander un gros changement et un nouvel apprentissage : pygame, librairie fait exprès pour les jeux. Je ne l'ai pas testé, je fais pas encore dans le graphique, mais apparemment ça a l'air puissant...
http://www.pygame.org/news.html
sudo apt-get install python-pygame # il me semble.
Par contre, ça ne marche qu'avec Python 2.4...
edit : et il faudrait abandonner Tkinter pour refaire la GUI avec Pygame.
Dernière modification par cat_loic (Le 14/05/2008, à 18:29)
Hors ligne
#41 Le 14/05/2008, à 20:34
- Abu
Re : [Python] Projet de casse-briques (maj 23/05 : v0.3.1.1)
Bon pas eu le temps de code aujourd'hui (faut bien bosser une peu ^^)
Enfin juste un petit bug ultra mineur corrigé sur l'augmentation de vie à chaque niveau (j'avais enlevé un modulo '%') : ligne 782, à remplacer par
self.setvie(self.vie+1)
(je veux pas faire une release juste pour ça... )
J'ai pas mal réfléchi au rebond de la balle. Effectivement XGouchet, tu as raison, il faut que le rebond de la balle dépende de la position de contact sur la raquette.
J'ai juste un mini (?) problème technique qui demande un peu d'aide pour faire ça (encore une fois je débute en python) :
Comment faire pour récupérer une propriété d'une classe dans une autre ?
Plus précisément : Je veux implanter la méthode de rebond dans la classe Balle ce qui me semble le plus logique, mais j'ai besoin de récupérer les coordonnées de la raquette (instance de Raquette crée dans Application). Est-ce que c'est possible, et est-ce que c'est propre au niveau programmation, et surtout comment faire ? Il me semble que ça pose un problème logique....
Si qqun a une solution ça me gagnerait pas mal de temps pour me concentrer sur l'algorithme (je tiens à préciser que je n'ai encore rien essayé hein...). C'est à dire avoir un truc du type :
class Raquette:
....
self.x=x ## Valeur en abscisse de la raquette
self.larg=larg ## Largeur de la raquette
class Balle:
...
def rebond_raquette(self):
self.dirx=(self.x-Application.raquette.x)/Application.raquette.larg
## Ca marchera ???
## Direction de la balle en x = écart avec le centre de la raquette divisé par la largeur de la raquette :
## Au milieu : 0, la balle remonte verticalement,
## Droite : 1, la balle part à 45° à droite ,
## Gauche : -1, la balle part à 45° à gauche.
## Pas sûr que ça marche, mais à tester.
...
class Application:
def __init__(blabla):
....
self.raquette=Raquette(blibli)
self.balle=Balle(bloublou)
....
Ou bien est-ce que c'est mieux de le coder directement dans Application ?
PS: Vous cassez pas la tête en fait je vais trouver une astuce et coder ça dans Application. Je me rend compte en tapant le code ci-dessus que ça me parait vraiment pas propre comme truc...
PS2: Du coup cette intervention est vraiment très utile.....:P
@cat_loic : Je ne veux pas utiliser pygame, je préfère tout faire avec un minimum d'outils quitte à réinventer l'eau tiède. Le but pour moi c'est avant tout d'apprendre python et je pense que je me servirai plus de Tkinter que de Pygame dans mes futurs projets.
Je vais bien trouver ce qui permet de créer des sons....
Abu(ntu)
Dernière modification par Abu (Le 14/05/2008, à 20:37)
Hors ligne
#42 Le 14/05/2008, à 20:54
- snapshot
Re : [Python] Projet de casse-briques (maj 23/05 : v0.3.1.1)
Pour le rebond de la balle sur la raquette, j'ai toujours eu une idée à ce sujet : c'est de considérer la raquette non pas comme une plaque plate, mais bombée : en forme de moitié d'ellipse aplatie en fait. Au milieu de la raquette, la surface est plate mais plus on va vers les bords, plus la pente est prononcée (jusqu'à la verticale ? 45° ? 60° ça doit dépendre d'un paramètre à mon avis).
En tripotant les fonctions sin() et tan(), il doit bien y avoir un moyen de le faire... Reste plus qu'à trouver un moyen de calculer l'angle du rebond..
Pensez à mettre [Résolu] dans le titre une fois votre problème réglé !
Hors ligne
#43 Le 14/05/2008, à 20:58
- Abu
Re : [Python] Projet de casse-briques (maj 23/05 : v0.3.1.1)
Bon ben y aura quand même une release du jour , je m'en suis sorti au final très facilement (grâce à mon brouillon du post précédent ^^)
Voici la version 0.3.0.2 : Le comportement de la balle a été revu et correspond à ce que XGouroux m'a suggéré (merci du tip). Ca change vachement le jeu du coup, en vachement mieux...
Dispo en 1ère page
Abu(ntu)
Hors ligne
#44 Le 14/05/2008, à 21:04
- Abu
Re : [Python] Projet de casse-briques (maj 23/05 : v0.3.1.1)
Excellente idée snapshot, je vais regarder ça (je suis prof de maths, ça devrait pas me poser bcp de pb pour faire les calculs )
Du coup c'est toujours symétrique mais par rapport aux normales à une ellipse
Whaouh mieux, je peux carrément dessiner la raquette bombée avec cette même ellipse, genre tite soucoupe. Je vais y réfléchir
PS: Comme d'hab j'attends vos feed back sur la 0.3.02
Abu(ntu)
Hors ligne
#45 Le 14/05/2008, à 21:04
- mutah
Re : [Python] Projet de casse-briques (maj 23/05 : v0.3.1.1)
Pour le son, il y a des modules inclus (le slogan de python est "battery included" )
il y a un exemple ici de code multiplateforme, peu lisible car l'indentation avec des tabulations a été supprimé par le forum :
http://www.velocityreviews.com/forums/t337346-how-to-play-sound-in-python.html
En gros, sous windows, il faut utiliser le module winsound et sous linux le module ossaudiodev :
http://docs.python.org/lib/module-ossaudiodev.html
enjoy
Ce n'est pas le chemin qui est difficile, c'est le difficile qui est chemin.
Hors ligne
#46 Le 14/05/2008, à 21:18
- snapshot
Re : [Python] Projet de casse-briques (maj 23/05 : v0.3.1.1)
Prof de math ?! et bien tu m'enlève une belle épine du pied ! J'étais en train de me casser la tête avec un tableur pour trouver une formule et surtout sa dérivée pour avoir sa tangente ! ça remonte à loin pour moi ! très bien, je te laisse faire !
Pensez à mettre [Résolu] dans le titre une fois votre problème réglé !
Hors ligne
#47 Le 14/05/2008, à 21:48
- Abu
Re : [Python] Projet de casse-briques (maj 23/05 : v0.3.1.1)
lol c'est sympa de ta part
Je suis trop crevé pour faire ça maintenant mais ça doit être assez rapide avec l'équation paramétrique de l'ellipse :
Vecteur tangent : u( x'(t), y'(t) )
x(t)=a*cos(t), y(t)=b*sin(t), où t dans [0,2Pi],
d'où u(-a*sin(t) , b*cos(t)),
d'où le vecteur normal : n(b*cos(t), a*sin(t))
D'où en remplaçant on a le vecteur normal au point (x,y): n ( b/a*x, a/b*y)
Ca doit être quelque chose comme ça....
Pour les sons je veux rester dans cette esprit old school (graphismes à la pong, font courrier de partout en énormae,...). Je vois bien des sons type vieilles consoles (genre des "tip" "toup" "zjouwww" (bon c'est pas très parlant mais moi je les entend bien ^^)...) et une zik façon très synthétique, mais avec des clins d'oeil modernes quand même...
Hors ligne
#48 Le 14/05/2008, à 22:21
- cat_loic
Re : [Python] Projet de casse-briques (maj 23/05 : v0.3.1.1)
En musique de jeu, je ne peux que te conseiller Maf : http://www.jamendo.com/fr/artist/maf
Musique libre (\o/), et très bien pour els jeux je trouve, je voulais utiliser ses musiques pour mon pierre papier ciseaux, mais je suis pas allé jusqu'au bout donc bon...
Bon, je ne sais pas si ça fait old school comme musique, j'étais pas encore né (à la limite, Game gear de Séga, ça passe, la PS1 aussi, mais pas plus vieux .
Hors ligne
#49 Le 15/05/2008, à 01:49
- nicolas66
Re : [Python] Projet de casse-briques (maj 23/05 : v0.3.1.1)
C'est fun le style old-school. Perso, j'avais mis quelques musiques du jeu Alex Kid dans un de mes projets
"The computer was born to solve problems that did not exist before." (B. Gates)
Hors ligne
#50 Le 15/05/2008, à 06:47
- aleph
Re : [Python] Projet de casse-briques (maj 23/05 : v0.3.1.1)
La méthode __del__ est le destructeur d'une classe dans le sens objet/classe en mémoire. Elle est utilisée à ces fins. Son utilisation comme gomme, fonction de gommage graphique, n'est pas très judicieux. Une méthode/fonction "delete" ou "efface" similaire à redraw est préférable.
>>> class C:
def __init__(self):
print '--> __init__'
def __del__(self):
print '--> __del__'
>>> a = C()
--> __init__
>>> del a
--> __del__
>>> a
Traceback (most recent call last):
File "<psi last command>", line 1, in <module>
NameError: name 'a' is not defined