Bonjour, j'ai commencé à programmer un pong, seulement voilà tous les cinq points j'augmente la vitesse de la balle et à ce moment là mon code gérant la collision avec les raquettes ne fonctionne plus. Voici le code:
collision = 0#vaut 1 si la balle touche la raquette1 ou 2 si elle touche la raquette2
sortie = 0#vaut 0 si la balle n'est pas sortie 1 si c'est derriere la raquette 1 et 2 si c'est derriere la raquette 2
#on modifie les positions de début et de fin des raquettes pour prendre en compte la taille de la balle
pos_debut1 = [raquette1.pos_debut[0] + balle.taille_balle, raquette1.pos_debut[1] - balle.taille_balle]
pos_debut2 = [raquette2.pos_debut[0] - balle.taille_balle, raquette2.pos_debut[1] - balle.taille_balle]
pos_fin1 = [raquette1.pos_fin[0] + balle.taille_balle, raquette1.pos_fin[1] + balle.taille_balle]
pos_fin2 = [raquette2.pos_fin[0] - balle.taille_balle, raquette2.pos_fin[1] + balle.taille_balle]
#collision avec la raquette1
if balle.pos >= pos_debut1 and balle.pos <= pos_fin1:
collision = 1
#collision avec la raquette2
elif balle.pos >= pos_debut2 and balle.pos <= pos_fin2:
collision = 2
#gestion de la sortie
if balle.pos[0] < pos_debut1[0] - balle.taille_balle * 2 - 60:
sortie = 1
elif balle.pos[0] > pos_debut2[0] + balle.taille_balle * 2 + 60:
sortie = 2
#si la balle touche le haut ou le bas on inverse le deplacement verticale
if balle.pos[1] + deplacement[1] <= 0 + balle.taille_balle or balle.pos[1] + deplacement[1] >= taille_h - balle.taille_balle:
deplacement[1] = -deplacement[1]#permet de n'inverser que le deplacement verticale
#gestion du deplacement en fonction de la collision
if collision != 0:
deplacement[0] = -deplacement[0]
pygame.mixer.Sound(son).play()
Salut,
on n'a qu'un morceau de code, donc ça va être réponse aléatoire : il est possible que la vitesse soit trop grande et donc qu'en un pas de temps, la balle passe de part et d'autre de ta raquette sans que tu puisses détecter la collision.
Merci pour ta réponse. De base la balle se déplace de 6 pixels verticalement et horizontalement mais même en mettant la vitesse à 5 pixels la collision ne marche plus. Je mets la boucle pricipale du jeu.
#amplitude du deplacement de la balle et des raquettes en px
deplacement = [-5,-5]
deplacement_raquette = 8
#scores des 2 joueurs
score1 = 0
score2 = 0
#raquettes des 2 joueurs
raquette1 = Raquette([60, taille_h / 2 - 35],[60, taille_h / 2 + 35])
raquette2 = Raquette([taille_l -60, taille_h / 2 - 35],[taille_l - 60, taille_h / 2 + 35])
balle = Balle(taille_l / 2, taille_h / 2, 12)
continuer = True
collision = False
sortie = 0
pos_finale = 0#hauteur a laquelle sera la balle lorsqu'elle frappera la raquette de l'ordi
#varaibles servant a savoir si la touche est toujours enfoncee
haut1 = False
bas1 = False
haut2 = False
bas2 = False
#niveau de l'ia
difficulte = 16
#son lors d'une collision
son = load_sound("pong.wav")
#delai de repetition quand la touche est enfoncee
pygame.key.set_repeat(50,30)
while continuer:
pygame.time.Clock().tick(30)#limitation de la boucle a 30 fps
#gestion des évènements
#gestion de l'ia
collision, sortie, deplacement = is_collision(balle, raquette1, raquette2, deplacement, taille_h, son)
balle.deplacer(deplacement)
collision = 0
#update de la fenetre
J'ai retiré tous les blocs de déplacement et de l'ia pour rendre le tout plus lisible.
De base la balle se déplace de 6 pixels verticalement et horizontalement mais même en mettant la vitesse à 5 pixels la collision ne marche plus.
"De base" ? C'est-à-dire ? En vitesse normale ? Ou après accélération ? À partir de quelle vitesse ça foire ?
J'ai retiré tous les blocs de déplacement et de l'ia pour rendre le tout plus lisible.
Ouais, mais du coup il manque l'essentiel... Avec juste le code que tu as donné, on ne sait même pas comment la balle se déplace, on ne sait rien de sa position ni de celle des raquettes, etc. On n'est pas devins.
Au début du jeu la balle à une vitesse de 6 pixels et mon code fonctionne aussi avec une vitesse de 3 pixels mais ce sont les deux seuls valeurs que j'ai testé et qui fonctionne. Je remets tout le code avec les blocs de déplacement du joueur et de l'ia ainsi que le bloc qui gére l'accélération de la balle. (Ce n'est pas très propre par endroit :p)
while continuer:
pygame.time.Clock().tick(30)#limitation de la boucle a 30 fps
for event in pygame.event.get():
if event.type == QUIT:
sys.exit(0)
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
continuer = False
if event.key == K_UP or haut1 and not bas1 :
raquette1.deplacer(-deplacement_raquette, taille_h)
haut1 = True
if event.key == K_DOWN or bas1 and not haut1:
raquette1.deplacer(deplacement_raquette, taille_h)
bas1 = True
if event.type == KEYUP:
if event.key == K_UP:
haut1 = False
if event.key == K_DOWN:
bas1 = False
collision, sortie, deplacement = is_collision(balle, raquette1, raquette2, deplacement, taille_h, son)
balle.deplacer(deplacement)
#GESTION DE L'IA
if collision == 1 or sortie == 2:
pos_finale = ia(balle, [deplacement[0], deplacement[1]], taille_h, taille_l, sortie, difficulte)
if pos_finale >= raquette2.pos_debut[1] + 35:#si la balle est en dessous de la raquette2
haut2 = False
bas2 = True
if pos_finale <= raquette2.pos_debut[1] + 35:#si la balle est au dessus de la raquette2
haut2 = True
bas2 = False
if ceil(pos_finale/10) == ceil((raquette2.pos_debut[1] + 35)/10):
haut2 = False
bas2 = False
#deplacement de l'ia
if haut2 and not bas2:
raquette2.deplacer(-deplacement_raquette, taille_h)
if bas2 and not haut2:
raquette2.deplacer(deplacement_raquette, taille_h)
collision = 0
fenetre_update(fenetre, taille_l, taille_h, balle, raquette1, raquette2, score1, score2, (taille_l/2-38, 40), (taille_l/2+19, 40))
#gestion des scores et de l'accélération de la balle tous les 5 points
if sortie != 0:
balle.pos = [taille_l / 2, taille_h / 2]
if sortie == 1:
score1 += 1
else:
score2 += 1
if score1 % 5 == 0 and score1 != 0 or score2 % 5 == 0 and score2 != 0:
if deplacement[0] > 0:
deplacement[0] += 3
else:
deplacement[0] -= 3
if deplacement[1] > 0:
deplacement[1] += 3
else:
deplacement[1] -= 3
if score1 == 11 or score2 == 11:
fenetre_update(fenetre, taille_l, taille_h, balle, raquette1, raquette2, score1, score2, (taille_l/2-38, 40), (taille_l/2+19, 40))
afficher_text(fenetre, "Press Enter to continue", (taille_l / 2 * (len("Press enter to continue") / 2), taille_h/2))
while continuer:
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_RETURN:
continuer = False
if event.type == QUIT:
exit(0)
Ouais, enfin avec ça je suis pas bien plus avancé, je ne sais toujours pas quelles sont les positions de tes objets au cours du temps, puisque je n'ai pas les positions de départs (qui ont l'air d'être définies dans le constructeur).
En tout cas, avec cette info en plus :
la balle à une vitesse de 6 pixels et mon code fonctionne aussi avec une vitesse de 3 pixels
ça a tout l'air de confirmer ma toute première hypothèse. Si tu as par exemple une raquette située en (x,36) et que ta balle part de (0,0) il faudra que la vitesse de la balle divise 36 pour que la balle soit située sur la raquette à un moment donné. Ainsi, la balle rencontre la raquette au bout de 12 pas de temps si la vitesse est 3, au bout de 6 pas de temps si la vitesse est 6, jamais si la vitesse est 5 (la balle va passer de 35 à 40, donc traverser la raquette sans que tu détectes la collision).
Pour contrer ça, il suffit que la vitesse d'update de position soit grande devant celle de la balle pour que la balle ne se déplace pas de plus d'un pixel par pas de temps et que tu puisses détecter suffisamment finement sa position.
Mais il reste un probleme : c'est que les raquettes sont à 60 pixels du bord. Mais si je mets la vitesse de la balle à 5 pixels et passe quand même à travers de la raquette donc je pense pas que le problème vienne de là.
Et pour les positions des objets j'avais oublié de remettre le code la deuxième fois.
#les raquettes font 70 pixels 35 au dessus et 35 au dessous du milieu de l'écran
raquette1 = Raquette([60, taille_h / 2 - 35],[60, taille_h / 2 + 35])
raquette2 = Raquette([taille_l -60, taille_h / 2 - 35],[taille_l - 60, taille_h / 2 + 35])
balle = Balle(taille_l / 2, taille_h / 2, 12)
Mais il reste un probleme : c'est que les raquettes sont à 60 pixels du bord
Et alors ? Ce qui compte, c'est la position absolue de la raquette dans le repère que tu utilises, pas celle du bord par rapport à la raquette. Franchement, mets le code complet, de façon à ce qu'il soit testable, parce que sinon, on va pas s'en sortir.
"ça a tout l'air de confirmer ma toute première hypothèse"
Je pense comme @drien. Ça doit être un problème de multiple entre le déplacement de ta balle et la position de la raquette. Par contre, au lieu de mettre tout ton code, je te conseillerai de prendre un peu de recul et d'essayer d'isoler le bout de code qui selon toi pose problème (apparemment ici c'est soit le déplacement, soit la condition qui vérifie la collision (ou soit les 2)). Parce que il est facile de se perdre avec tous ces taille_l - 60, taille_h/2 - 35, (raquette2.pos_debut[1] + 35)/10, etc... Aussi essaie (dans un autre fichier, et sans utiliser pour l'instant pygame) de simuler le déplacement de ta balle et de vérifier ta condition. Par exemple:
balle = [0, 0]
while True:
balle[0] += 3
print(balle) #vérifie les coordonnées de la balle
if balle[0] == 60:
break
ATTENTION: ce code n'a aucun rapport avec le tien. C'est juste pour l'exemple. Mais c'est comme ça qu'on fait. On isole la partie qui nous semble "défectueuse" et on utilise des print pour vérifier le comportement.
Je sais exactement quel est le code qui pose problème c'est la condition qui vérifie la collision avec la raquette puisque la balle rebondi toujours sur les paroies. Je m'étais aussi fait la réfléxion que la balle "passait au travers" alors pour contrer ça j'avais fait une condition qui comparé d'abords la position x puis la position y et en prenant en compte le deplacement de la balle mais toujours le meme problème.
EDIT : je viens de trouver une autre source au problème : la taille de la balle. Elle est de 12 pixels de rayon qui est multiple de 3 et de 6 mais pas de 9 ni de 5 ce qui fait que la bale passe au trevers de la raquette.
Je m'étais aussi fait la réfléxion que la balle "passait au travers" alors pour contrer ça j'avais fait une condition qui comparé d'abords la position x puis la position y mais exactement le meme problème.
Je ne comprends pas comment c'était censé régler ton problème...
EDIT : ah ok.
Tant que tu ne seras pas décidé à nous donner plus d'infos sur la valeur des positions initiales, on ne pourra pas t'aider plus que ça.
La balle est placée au milieu du terrain soit en 390;240 et les raquettes s'étendent de 425;60 à 355;60 et 425;720 à 355;720 en clair le milieu des raquettes est à 60 pixels du coté et au milieu verticalement.
"Je m'étais aussi fait la réflexion que la balle "passait au travers""
C'est sur ce point que tu dois réfléchir. Comment as-tu pris en compte la collision? Juste en ne considérant qu'un point de la balle (par exemple le côté supérieur gauche) ou considère-tu la balle en entière? C'est bien évidemment de la dernière façon qu'il faut faire. Il faut considérer que si une partie de la balle touche une partie de la raquette, alors il y a collision. Voici un exemple console de ça:
#Format des coordonnées: [x1, y1, x2, y2], avec (x1, y1) et (x2, y2): 2 points
#bien choisis pour couvrir la surface totale de chaque objet.
#c_r: coordonnées de la raquette
#c_b: coordonnées de la balle
c_r = [80, 10, 120, 10]
c_b = [90, 0, 93, 3]
#Un petit compteur pour afficher juste les 15 premiers tour de boucle
compteur = 0
while compteur < 15:
#On augmente de 1 chaque ordonnée de la balle: On a un déplacement vertical
c_b[1] += 1
c_b[3] += 1
#RAPPEL
#Un set() est un objet de base de python. C'est un conteneur (comme les
#listes, dico, etc...), et l'une de ses particularité c'est qu'il ne peut
#pas avoir 2 objets identiques (par exemple il ne pourra pas y avoir 2 fois
#le chiffre 5, ou 2 fois le mot "zero")
#Ici c'est l'étape importante.
#inter_x et inter_y représentent les coordonnees communes des 2 objets:
inter_x = set(range(c_b[0], c_b[2]+1)).intersection(range(c_r[0], c_r[2]+1))
inter_y = set(range(c_b[1], c_b[3]+1)).intersection(range(c_r[1], c_r[3]+1))
#set(range(c_b[0], c_b[2]+1)):
#On met l'intervalle des abscisses de la balle dans un set
#.intersection(range(c_r[0], c_r[2]+1))
#intersection() est une méthode de la classe set() qui renvoie les objets
#communs entre 1 set et un itérable. Ici on a mis comme itérable
#l'intervalle des abscisses de la raquette.
#On fait la même chose avec les ordonnées de la balle et de la raquette
#Si la partie abscisse ET la partie ordonnée de chaque objet ont des
#positions communes, alors il y a collision et on affiche les coordonnées
if inter_x and inter_y:
print()
print("collision")
print((inter_x, inter_y))
print()
#On affiche ce que contient inter_x et inter_y
else:
print((inter_x, inter_y))
#Augmente le tour de boucle
compteur += 1
Mais il me semble que pygame a un système intégré de gestion des collisions. Tu devrais plutôt chercher de ce côté.
Simplement parce que sinon le jeu est beaucoup trop lent.
"Mais il me semble que pygame a un système intégré de gestion des collisions. Tu devrais plutôt chercher de ce côté."
Je pense que je vais aller voir, mais le problème c'est que mon anglais ne permet pas de tout comprendre et je n'avais rien trouvé de concluant en français.
Sinon merci quand même car je ne connaissais pas la méthode instersection pour les set.
Je viens de faire quelques recherches sur le système de collision de pygame et je me suis rappelé qu'au début du projet je voulais l'utiliser mais il ne s'applique qu'à des images et je n'en utilise pas.(désolé pour le double post)
Et tu ne veux pas tenter une autre approche, en séparant l'affichage du reste ? Ce qui permettrait d'avancer d'un pixel à la fois et résoudrait ton problème.
Même si ta solution semblait prometteuse, elle ne résout que paritellement le problème : quand j'augmente la vitesse de la balle arrive un moment où la taille de la balle n'est plus un multiple de la vitesse ce qui fait que la balle traverse la raquette. Donc la solution de Olygrim est la plus adaptée.
"mes raquettes et ma balle sont des formes dessinées par pygame. "
Il faut bien comprendre ce que tu as en sortie quand tu utilise une méthode ou une classe. Si tu as dessiné tes raquettes et ta balle avec le module draw de pygame, chaque fonction de ce module renvoie un objet Rect(). Tu peux donc normalement utilisé les méthodes pour gérer les collisions, qui sont justement des méthodes de la classe Rect().
import pygame
#Regarde bien. Chaque fonction renvoie: -> Rect()
help(pygame.draw)
#Les méthodes de collisions sont dans la classe Rect()
dir(pygame.Rect)
#Par contre je ne m'en suis jamais servie.
Le fait est que mes objets ne sont pas des Rect, ils contiennent juste les coordonnées des objets qui eux sont dessinés quand je mets l'affichage à jour.
Le fait est que mes objets ne sont pas des Rect, ils contiennent juste les coordonnées des objets qui eux sont dessinés quand je mets l'affichage à jour.
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.