DANS LA PANADE, jeu python en tkinter

Signaler
Messages postés
14
Date d'inscription
dimanche 28 octobre 2012
Statut
Membre
Dernière intervention
15 mai 2014
-
 clemgamer -
Bonjour à tous,
Voila je suis en terminale en ISN. J'ai un projet a présenter, jai déjà écris le programme de base. Quand on lance le programme, le canevas s'ouvre avec une image de menu. Il y a plusieurs boutons play, go, quitter. Un chrono qui sert de score. le bouton play enlève l'image du menu et laisse la place au background et la fusée contrôler par le joueur. EN appuyant sur go la boule arrive.
Voila déjà le problème est que un appui sur le bouton= une boule. plus on appuis sur le bouton plus la boule va vite et des quelle sort de l'ecran une autre arrive.
Mais le prof nous a dis que déjà les restriction étant de rester en tkinter rend la tache difficile mais surtout moi esthétique et aussi cela fait que 2/3 mois qu'on pratique donc il ne s'attend pas un quelque chose de très compliquer ou sans problème mais il veut voir qu'on a bosser et essayé.^^ Donc les boules ne sont pas mon problème principal. J''ai chercher beaucoup de solution mais beaucoup de personne ce servait de pygame, ce qui est logique mais pas bon pour moi car toujours pas de solution.
Donc mon problème c'est le game over. Il faut bien un but au jeu.
J'avais penser a:
If....
gameover= ImageTk.PhotoImage(Image.open("gameover.gif"))

Donc ai l'image et c'est écris game over dessus donc pas besoin de label. Mais mon problème c'est de déterminer les condition pour qu'il affiche le game over. Je sais pas si il faut entrer des paramètre de collision avec la fusée. Ou lorsque les coordonnées de la balle sont la même que la fusée on a perdu.

Merci d'avance pour votre aide, je suis dans la .... panade^^
L'année prochaine je veut aller en dut info. ce projet de m'a pas du tout dégoûter mais c'est pas facile au début.... comme toute chose

5 réponses

Messages postés
16
Date d'inscription
dimanche 11 mars 2007
Statut
Membre
Dernière intervention
22 mai 2014
20
Salut,

Concernant les collisions, je pense que la fonction que tu cherches est find_overlapping dans Tkinter (quelques explications http://effbot.org/tkinterbook/canvas.htm#canvas.Canvas.find_overlapping-method)

Cette fonction retourne la liste des objets qui se recouvrent (même partiellement) dans un rectangle fourni en paramètres (la hitbox). Même si ce n'est pas idéal dans le cas d'une fusée, il est possible d'y arriver en bidouillant un peu (définir plusieurs rectangles qui recouvrent approximativement ta fusée). Ca peut te permettre de gérer simplement les collisions.

Bon courage
--
Messages postés
74
Date d'inscription
samedi 8 décembre 2012
Statut
Membre
Dernière intervention
14 juin 2014
15
Eviter d'utiliser la méthode Canvas.find_overlapping lorsque l'on connait déjà les coordonnées de chacun des éléments, la technique des hitboxes comme expliqué par pixel_overflow car Canvas.find_overlapping sera clairement plus lourd.
Messages postés
2
Date d'inscription
mercredi 14 mai 2014
Statut
Membre
Dernière intervention
15 mai 2014

Bonjour !

Tout d'abord une simple question :
Comment codes-tu ? Utilises tu des Objets, ou juste des fonctions ?

Si tu utilises des objets, tu devrais avoir un objet boule.
Si tu ne les utilises pas, je te conseille de les utiliser ^^
Non, si tu ne sais pas utiliser les structures, essaye un tabeau qui

contiendrait les paramètres de tes boules si il y en a plusieurs à la fois sur l'écran. Mais c'est plus dur, moins précis

et peu intuitif...

Je pense que tu dois avoir une variable vitesse_boule qui est augmentée

quand tu appuies sur Go.

Donc postes la portion de code qui te sert à créer/déplacer/modifier la

boule pour que nous puissions voir un peu ton code :)

Pour le Game Over :
Qu'est ce qui définit que le joueur à perdu ?
Une grosse collision entre la fusée et la boule (enfin je pense).
Donc il va te falloir une fonction de gestion du game over, et de gestion

des collisions. (ici c'est plus simples, car il n'y a qu'un seul paramètre

de Game Over : la collision).

pour tes collisions, non, juste comparer deux coordonnées serait trop facile

^^
Le cas ou les deux coordonnées sont égale, c'est juste quand les deux objets sont alignés sur le coin supérieur gauche. Ici on va aussi utiliser largeur/longueur.

Je te propose donc de lire ceci pour tes collisions :
http://fr.openclassrooms.com/informatique/cours/theorie-des-collisions

Donc on va partir du principe que et ta fusée et ta boule sonnt des AABB

(Aligned Axes Bouncing Boxes ou des boites rectangles alignés sur les axes)

pour éviter de se lancer dans des calculs ultra compliqués et rester dans de

la non prise de tête ;)

Si tu utilisais des objets tu aurais :

class Boule :
def __init__(self):
self.x = 50 #coordonnées X et Y de la boule (coin supérieur

gauche)
self.y = 42 #ici, totalement arbitraires, hein c'est juste

une position de départ, et c'est toi qui code une fonction de déplacement

(dans l'objet)

self.tx = 60 #et la taille.
self.ty = 60
...


tu aurais la même chose pour la fusée et tu "n'aurais qu'à" tester une

collision.

pour cela :
mettons deux rectangles qui représentent la hitbox de ta boule (oui, une hitbox rectangle pour une boule, mais là ça ne devrait pas vraiment gêner ton prof ni le joueur ni personne) et de ta fusée.
Et s'il y a une intersection, soit si un rectangle rentre dans l'autre, alors il y a une collision, et tu sais ce que tu dois en faire.
Par exemple, commence par calculer si la fusée est potentiellement touchée en X par la

boule :

if boule_x < fusée_x+fusée_taille_X or boule_x+boule_taille_x > fusée_x :
#on a la fusée qui est verticalement centrée sur la fusée.
#Tu teste comme si dessus avec y à la place de x pour savoir si

c'est également le cas horizontalement
#et si c'est le cas, alors les deux hitbox se touchent/se croisent

et donc c'est une collision.

soit :
SI le coté gauche est avant le coté droit de la fusée (la position du coté gauche + la largeur) OU QUE le coté droit de la boule est après le coté gauche de la fusée
ALORS :
il y a potentiellement une collision et tu continues pour la hauteur des éléments pour vérifier ou pas et donner un résultat.

En espérant t'avoir aidé,
Adrien.
Merci de ta réponse je vais regarder cela attentivement.
En effet j'utilise les boule de python. Je n'est pas pu regarder aujourd'hui j'étais à un entretine d'admission à un iut pour un dut info^^

remerci j'espère que je vais pouvoir sortir quelque chose de potable^^
je te met le code dessous si tu veux regarder pour me donner des conseil ^^ (oui j'ai pas fais de list mais je suis débutant et je cherche pas la complique mais pour l'instant le programme tourne et sans erreur^^) remerci A+ clém (ps: des truc serve a rien comme l'identifiant sa ouvre un cannevas ou sa demande de se co c'est pour le style =) Non normalement peut être un jour sa marchera.

from tkinter import *
from PIL import Image, ImageTk
from getpass import getpass
import random
import sys


x = 100
y = 250
dx = 0
dy = 10
chrono_var=0

bx1,by1=1350,random.randint(100,490) # definition des variables
x1,y1=200,490 # definition des variables
y2,x2=y1,x1 # definition des variables
point=0 # definition des variables
temoin=0 # definition des variables
x=5 # definition des variables

####################################################################Definitions

def reset():
    global play
    python = sys.executable
    os.execl(python, python, * sys.argv)
    
    

def monte (event=None):
    global y,dy, img #on importe ce dont on a besoin
    y  = y - dy #on change la hauteur
    if y<-29 :
        y= 510
    #changer les coordonnées
    can.coords(img,x,y)
    can.update()#update du cavnas
    
def descend (event=None):
    global x, y, dy, img
    y  = y + dy
    if y>510 :
        y= -29
    can.coords(img,x,y)
    can.update()

def boucle_principale():
    global top, depart, chrono_var_princ,  chrono_var
    #faire avancer les obstacles
    #gérer le chronomètre
    chrono_var = chrono_var + 1 ####change la valeur
    chrono_var_princ.set(str(chrono_var))
        
    fen.after(100, boucle_principale)
   
    can.update()
    
def play():
    global jeu_lance, chrono_var_princ, label_chrono
    jeu_lance=True
    can.delete(menu)
    ###construire le compteur
    chrono_var_princ = StringVar()
    label_chrono = Label(fen, textvar = chrono_var_princ, bg='white')
    label_chrono.pack()
    fen.after(1, boucle_principale)
    
   
def vitehaut(event=None): 
    global x, y, img
    y  = y - 150
    if y<-29 :
        y= 510
    can.coords(img,x,y)
    can.update()
    
def vitebas(event=None):
    global x, y, img
    y  = y + 150
    if y>510 :
        y= -29
    can.coords(img,x,y)
    can.update()
    
def connection() :
    global iden,mdp
    if iden=="rayane" and mdp=="bonjour":
        print("bravo")
    else :
        print("perdu")
#getpass(prompt='Password:Bonjour ', stream=None)
        
def boule():#
        global bx1,by1,x1,y1,point,x,x2,y2, test #importation des variables
        bx1=bx1-x #variable utilisee pour faire bouger la boule sur x
        can.coords(balle,bx1,by1,bx1-20,by1-20) # applicationd e la variable changée à la boule
        if y2<by1 and y2>by1-20 and x2<bx1 and x2>bx1-20: #verification des coordonees de la boule pour voir si elle touche la grosse boule
                bx1=1200 #remettre les coordonees de la boule à 0 pour repartir d'au dessus
                by1=random.randint(10,390) #position aléatoire de la boule sur Y
                fen.after(1,boule) #refaire redescendre la nouvelle boule sans arrets
        elif bx1<0: #si la balle a pasé le vaisseau
                bx1=1200 #remettre les coordonees de la boule à 0 pour repartir d'au dessus
                by1=random.randint(10,390) #position aléatoire de la boule sur Y
                fen.after(1,boule) #refaire redescendre la nouvelle boule sans arrets
        elif bx1>0: # si la boule est toujours "en jeu"
                fen.after(1,boule) #la boule avance

        
        
        
#################################################################################################
#################################################################################################
#########################################     PROGRAMME     #####################################
#################################################################################################
#################################################################################################



###############################################premiere fenetre avec identification
#iden=get(entr1)
#mdp=get(entr2)

fen0 = Tk()
bouton1=Button(fen0,bg="blue", text="connection",width=15, command=connection)
bouton1.pack()
txt0 = Label(fen0, text = "Bienvenue sur Fuse, veuillez vous connecter sur votre session")
txt1 = Label(fen0, text = 'Identifiant :')
txt2 = Label(fen0, text = 'Mot de Passe :')
entr1 = Entry(fen0)
entr2 = Entry(fen0)
txt0.grid(row=-0)
txt1.grid(row =1)
txt2.grid(row =2)
entr1.grid(row =1, column =1)
entr2.grid(row =2, column =1)
bouton1.grid(row=3, column =1)
fen0.mainloop()      




#################################################################################MOT DE PASSE############
#import getpass
#getpass(prompt= "Bonjour", stream=None)



########################################################Fenetre avec canevas

    
#création de la fenêtre
fen = Tk()
fen.title("FUSE")

texte=Label(fen,text="BIENVENUE SUR FUSE ")
texte.pack()


#on ouvre l'image

image_tk = ImageTk.PhotoImage(Image.open("image.jpg")) #on la transforme pour tk

#on la met dans le canvas
can = Canvas(fen,width=1300, height=600)
can.pack()

fusee_tk = ImageTk.PhotoImage(Image.open("fusee.gif"))
image  = can.create_image(-19,0, anchor = NW, image=image_tk)
img  = can.create_image(x,y, anchor = NW, image=fusee_tk)

menu_tk = ImageTk.PhotoImage(Image.open("menu.png"))
menu = can.create_image(0,0, anchor = NW, image=menu_tk)
can.delete(image_tk) 



#########################################################Creation de la balle

balle = can.create_oval(bx1, by1, bx1-20, by1-20,width=35, fill="black") # creation de la balle

##########################################################Creation de boutons

bouton= Button(fen, bg="white", text = "PLAY",height=5,width=20, command = play)
bouton.pack()

bou1 = Button(fen, text='GO',width=20, command=boule) # creation du bouton pour lancer le programme, permet aussi a la boule d'aller plus vite
bou1.pack()

bouton=Button(fen,bg="red", text="Quitter",width=20, command=fen.destroy)
bouton.pack()


################################################Lier les évènements clavier

fen.bind("<Up>",monte)
fen.bind("<Down>",descend)
fen.bind("a",vitehaut)
fen.bind("q",vitebas)
#fen.bind("<Space>", boost)




#a garder a la fin
fen.mainloop()
merci pour l'article du nouveau site du zéro j'avis cherché mais quand sa commençais a parlé de pygame j'ai du abandonné et pas cherché en profondeur^^
Messages postés
2
Date d'inscription
mercredi 14 mai 2014
Statut
Membre
Dernière intervention
15 mai 2014

Pour le code, il faut pas utiliser tant de global. Ce n'est pas un bonne chose ; surtout si c'est pour les déclarer dans une fonction comme jeu_lance. Mais du coup, cette variable peut te servir à empêcher l'apparition de nouvelles boules : si on appuies sur go et si le jeu n'est pas lancé alors on lance le jeu et on crée une boule. Sinon rien du tout.
Et tu n'as pas besoin de Pygame pour faire des bonnes collision. Juste d'un peu de calcul. Mais comme l'a dit beschtraffer find_overlapping est une bonne solution.

Et après, c'est juste pour moi mais pour le déplacement je te propose quelque chose pour un vrai déplacement fluide au clavier qui gère bien les touches fléchées même quand deux sont appuyées en même temps, et pas que seule la dernière touche soit prise en compte :

Mettons pour Gauche et Droite :
tu déclares toucheGauche = 0 et toucheDroite =0
et quand on appuie sur flêche gauche, tu mets toucheGauche = 1 et quand on la relâche toucheGauche = 0.
Idem pour la touche droite.
du coup, pour déplacer horizontalement tu fais :
posX += (toucheDroite-toucheGauche)*vitesse

comme ça, (toucheDroite-toucheGauche) te renvoie -1, 0 ou 1 en fonction des touches directionnelles gauche et droites appuyées et donc de la direction à prendre. Et c'est plus pratique, et c'est plus fluide, et tu ne touches pas plusieurs fois à ta vitesse. Et tu ne crée qu'une seule fonction récursive qui à chaque appel effectue cette opération de déplacement en fonction des touches appuyées ou pas, et donc une seule fonction qui peut toucher à ta fusée directement. C'est plus lisible.
Puis tu fais pareil pour tes touches Haut et Bas.

Bonne chance
Messages postés
14
Date d'inscription
dimanche 28 octobre 2012
Statut
Membre
Dernière intervention
15 mai 2014

merci pour ton conseil, je verrai si j'ai le temps de modifier avant la présentation du projet.
Messages postés
14
Date d'inscription
dimanche 28 octobre 2012
Statut
Membre
Dernière intervention
15 mai 2014

Merci à tous je m'attendais à pas autant de réponse^^
Alors pour vous tenir au courant j'ai intégrer le bouton go a la fonction play donc plus qu'un bouton et tous se lance. J'ai également résolus le problème de la boucle qui se trouvait dans les conditions de répétitions de la déf avec les coordonnées bx1>=0 ...
Voila la on commence a avoir un jeu a peu près présentable pour débutant^^
Me reste plus que le game over. J'essaie cela soir
A+ bonne continuation à tous Clém
Voila cela fait quelque jour que j'essaye mais je n'arrive toujours pas.
Ma boule est bien un objet mais elle n'est pas definis comme l'exemple de pixel_overflow est ce un problème?
Mais le gros soucis c'est que ma fustee c'est une image ambulante.^^
Je m'explique, en gros c'est une image et je n'est definit aucun objet qui la reprèsente ( je ne sais pas si c'est compréhnesible). Par exemple j'aurai deux rectangle definit et je met

if rect1_x < rect2_x+rect_taille_X or rect2_x+rect_taille_x >
rect1_x : print(gameover)
can.destroy()

je pense que j'arriverai a faire fonctionner mais la j'ai une image rogné. Est ce que je peux definir un rectangle autour de la fusee comme suggerer par beschtraffer il me semble ("Cette fonction retourne la liste des objets qui se recouvrent (même partiellement) dans un rectangle fourni en paramètres (la hitbox). Même si ce n'est pas idéal dans le cas d'une fusée..")

Faut til que je reprenne tous.... ;S (avec list et tout....pas le temps avant présentation projet==BOn les gars jvais me tirer une Balle^^)
Merci a tout le monde de m'avoir repondu mais je suis un débutant qui a l'air de coder de la simple merde.
Je parle à moi même sa fait un peu skyso
tu coup j'arrive tjrs pas j'ai essayer
if bx1<xf and by1>y-dy and by1<y+dy and by1<y-dy and by1>y+dy
et toute les forme possible mais il me met invalid sintax
Messages postés
74
Date d'inscription
samedi 8 décembre 2012
Statut
Membre
Dernière intervention
14 juin 2014
15
Votre projet devient vite compliqué sans l'utilisation des classes. Vous allez avoir un code 4 fois plus long et plus compliqué uniquement avec des fonctions.

Pour le rectangle qui entoure vos objets, grâce au fait que vous utilisez PIL, il est possible de définir une hitbox qui exclue les pixels 'invisibles' ( RGBA == (0,0,0,0) ). Mais encore une fois, sans créér de classes, ça va être long et difficile ... Et perso je me tirerais une balle dans la tête.

Ne pensez pas que vous codez de la merde, en pensant de la sorte vous allez finir par coder de la merde ! Dites vous que TOUT LE MONDE a été débutant :)

Bien à vous,
YepoMax
Bien le bonjour yépomax, je suis encore en vie hehe^^
du coup avec cela:

if (bx1<= xf <= by1+20 or bx1-20 <= xf <= by1+20 and bx1-20 <= xf <= bx1+20) and xf == 10:
can.delete(img)

j'arriva à faire disparaitre la fusée quand la balle la dépasse mais pour n'importe quelle endroit de la boule. EN gros même quand la boule n'est pas aligné à la fusée si la boule dépasse cette dernière elle disparait du coup j'aurai besoin de votre aide pour définir correctement la condition de "l'alignement " entre la boule et fusee.
Merci
Messages postés
74
Date d'inscription
samedi 8 décembre 2012
Statut
Membre
Dernière intervention
14 juin 2014
15
Que vaut "xf" dans le code que vous venez de poster ?

Vous comparez des coordonnées en x avec des coordonnées en y et avec xf, à moins que xf soit un élément magique, je ne vois pas la logique ^^

Je vous ai fait un code qui vous permet de déterminer si il y a collision.
Disons que les coordonnées de la boule son bx1, by1, les coordonnées de la fusée sont x et y, la taille de l'image de la boule est appelée hitbox_boule et celle de la fusée hitbox_fusee.

On obtient le code suivant :

hitbox_boule = (30, 30) # La boule fait 30x30 pixels (par exemple)
hitbox_fusee = (60, 20) # La fusée fait 60x20 pixels (par exemple)

def check_collision( coordsA, coordsB, hitboxA = (1,1), hitboxB = (1,1) ):
    # Note : les coordonnées doivent être le centre de l'objet

    collision_x = coordsB[0] - hitboxB[0]/2 - hitboxA[0]/2 < coordsA[0] < coordsB[0] + hitboxB[0]/2 + hitboxA[0]/2
    collision_y = coordsB[1] - hitboxB[1]/2 - hitboxA[1]/2 < coordsA[1] < coordsB[1] + hitboxB[1]/2 + hitboxA[1]/2

    # Pour qu'il y ai collision, il faut collision sellon x et selon y
    return collision_x and collision_y


if check_collision( (x, y), (bx1, by1), hitbox_boule, hitbox_fusee ):
    can.delete(img)


Et dans un cas plus général, on utilisera la fonction suivante pour vérifier une collision en précisant l'ancre :

def check_collision( coordsA, coordsB, hitboxA = (1,1), hitboxB = (1,1), anchor="CENTER" ):
    # Note : les ancres valides sont soit CENTER soit une composition des lettres N, S, W et E comme dans tkinter (majuscule ou minuscule).

    # Les calculs de collision se baseront sur les coins supérieur gauche, en fonction de l'ancre, on va déterminer les coordonnées de ces points.
    CORRECTION = (-0.5, -0.5)

    anchor_definition = {
        "N": (0, 0.5),
        "S": (0, -0.5),
        "W": (0.5, 0),
        "E": (-0.5, 0)
                        }

    if anchor.upper() != "CENTER":
        for letter in anchor: CORRECTION = (CORRECTION[0] + anchor_definition[letter.upper()][0], CORRECTION[1] + anchor_definition[letter][1])

    (upper_leftA, upper_leftB) = ((coordsA[0] - int(hitboxA[0]*CORRECTION[0]), coordsA[1] - int(hitboxA[1]*CORRECTION[1])),
                                  (coordsB[0] - int(hitboxB[0]*CORRECTION[0]), coordsB[1] - int(hitboxB[1]*CORRECTION[1])))


    # Et maintenant on regarde si il y a collision !
    return (upper_leftB[0] - hitboxA[0] < upper_leftA[0] < upper_leftB[0] + hitboxB[0]) and (upper_leftB[1] - hitboxA[1] < upper_leftA[1] < upper_leftB[1] + hitboxB[1])
en Faite a la base il y avait deux x avec des valeur différentes, cela ne crée pas de problème du coup je ne l'avais pas vu. Donc xf est la coordonnée de la fusée d'ou xf. Voilà et c'est vrai que la logique n'était plus présente a cette heure la^^
Mais ne vous inquiéter pas je passe mon oral demain( je voulais améliorer mais le résultat compte peu en sachant que cela ne fait même pas un ans que l'on côtoie python.
Par contre le jury tiendra compte de toutes idées ou toute tentative et que l'utilisation de forum est très recommander et fait partie d'une des compétences de la grille de notation.
Je voudrais d'abord remercier tous ceux qui ont intervenu dans ce forum. Je pense que je ne laisserai pas tombé ce projet et quitte à refaire avec des class et des list et bien je le referais.
Merci à tous ,et bonne soirée Clém.