IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Tkinter Python Discussion :

jeu d'obstacles avec tkinter


Sujet :

Tkinter Python

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Avril 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Avril 2014
    Messages : 7
    Par défaut jeu d'obstacles avec tkinter
    Bonjour à tous, je rédige ce post pour demander votre aide car je suis un peu dos au mur...
    Avec mon groupe d'ISN nous avons pour projet de faire un jeu d'obstacle (un bonhomme doit sauter par dessus des carrés), le problème vient du fait que j'arrive à créer un obstacle qui va de droite à gauche, mais au moment d'en faire plusieurs, qui apparaissent à des moments différents (sinon cela n'aurait pas d'intérêt), c'est l'impasse.

    Je vous joins le code pour générer les obstacles en espérant pouvoir trouver une solution...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
    obstacle= [0, 0, 0, 0]
    pos_x_o2 = 0
    def app_obst(x):
        global obstacle, del_obst, dpcmt, pos_x_b
        while x >= 0:
                for i in range (len(obstacle)):
                    if i == len(obstacle):
                        i=0
                    can.move(obstacle[i], -dpcmt, 0)
                    x = x - dpcmt
                    print(x, ", ", pos_y_o)
                    if x <= -30:
                        del_obst= True
                        can.delete(obstacle[i])
                    elif (pos_x_b-20 < x < pos_x_b+50) & (pos_y_b+320 < pos_y_o <= pos_y_b+360):
                        game_over()
     
    def deplacement():                                             
            global obstacle, pos_x_o, pos_x_o2, del_obst
            pos_x_o2 = pos_x_o
            while arret == False:
                fen.after(100, app_obst(pos_x_o2))
     
    def obst(): #dessin de l'obstacle
        for i in range (len (obstacle)):
            obstacle[i] = can.create_rectangle(pos_x_o,pos_y_o,pos_x_o+30,pos_y_o+30, fill='red')

  2. #2
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par BLOODY_mirai Voir le message
    Bonjour à tous, je rédige ce post pour demander votre aide car je suis un peu dos au mur...
    Avec mon groupe d'ISN nous avons pour projet de faire un jeu d'obstacle (un bonhomme doit sauter par dessus des carrés), le problème vient du fait que j'arrive à créer un obstacle qui va de droite à gauche, mais au moment d'en faire plusieurs, qui apparaissent à des moments différents (sinon cela n'aurait pas d'intérêt), c'est l'impasse.
    Bonjour,

    Faites attention aux tabulations (indentations) dans votre code : Python est très sensible à l'alignement du code dans le bon bloc d'instructions.

    Exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    # préférez le pluriel pour les collections d'objets
    # ici obstacles est une collection d'IDs de canvasItems
    obstacles = [0] * 4
     
    # décrivez le rôle de cette variable, svp
    pos_x_o2 = 0
     
    def app_obst(x):
        # on utilise 'global' lorsqu'on MODIFIE une variable globale
        global del_obst
        # on boucle (?)
        while x >= 0:
            # parcourir une collection d'objets
            for obstacle in obstacles:
                # déplacer les obstacles un par un
                can.move(obstacle, -dpcmt, 0)
            # end for
     
            # attention à vos blocs d'indentation /!\
            # NOTE: les balises '# end ...' que j'ai ajoutées
            # vous aident à vous repérer dans le flux du code
     
            # màj index de scrolling
            x -= dpcmt
            # debug: TRON console
            print(x, ", ", pos_y_o)
            # hors limites ?
            if x <= -30:
                # on supprime le premier obstacle du canevas
                can.delete(obstacles[0])
                # màj indicateur
                del_obst = True
            # fin de partie ?
            elif (-20 < x - pos_x_b < 50) and (320 < pos_y_o - pos_y_b <= 360):
                # fini
                game_over()
            # end if
        # end while
    # end def
     
    # NOTE: les balises '# end ...' que j'ai ajoutées
    # vous aident à vous repérer dans le flux du code
     
    def deplacement():
        global pos_x_o2
        pos_x_o2 = pos_x_o
        while not arret:
            fen.after(100, app_obst, pos_x_o2)
        # end while
    # end def
     
    def init_obstacles():
        "dessin des obstacles"
        # taille de l'obstacle
        size = 30
        # écart entre obstacles
        step = size * 2.5
        # boucle sur collection
        for i in range(len(obstacles)):
            # calcul position obstacle
            x = pos_x_o + i * step
            # création de l'obstacle
            obstacles[i] = can.create_rectangle(
                x, pos_y_o,
                x + size, pos_y_o + size,
                fill='red',
            )
        # end for
    # end def
    N'hésitez pas à utiliser des balises # end ... pour faciliter le repérage du flux d'instructions dans le code, cela vous permettra de vous assurer d'être dans le bon alignement (indentation) au bon endroit au bon moment.

    N'essayez pas de résoudre tous les problèmes en une seule fois et en même temps : commencez par résoudre le problème du défilement (scrolling) des obstacles, puis réfléchissez à ce que vous pourriez faire lorsque le premier obstacle affiché sort de la zone d'affichage du canvas et enfin, posez-vous la question "comment détecter simplement le fait qu'il n'y a plus d'obstacles affichés dans le canvas pour déterminer le moment où la partie se termine ?"

    Pour finir, vous utilisez une boucle while x>=0, est-ce vraiment pertinent ?

    Ne vaut-il pas mieux travailler étape par étape ?

    Dans la grande boucle du jeu, il vous faudra une étape où le joueur déplace son coureur, une étape de scrolling des obstacles, une étape de détection de collision entre le coureur et un obstacle et enfin une étape de détection de game over.

    S'il vous faut toutes ces étapes, mieux vaut peut-être dès lors programmer étape par étape.

    @+.

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Avril 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Avril 2014
    Messages : 7
    Par défaut
    Dans la grande boucle du jeu, il vous faudra une étape où le joueur déplace son coureur, une étape de scrolling des obstacles, une étape de détection de collision entre le coureur et un obstacle et enfin une étape de détection de game over.

    S'il vous faut toutes ces étapes, mieux vaut peut-être dès lors programmer étape par étape.
    bonjour, et bien merci de votre réponse, je vais essyer de faire comme conseillé étape par étape, mais en piochant quand même dans votre code pour essayer de rendre le mien un peu plus fonctionnel... par ailleurs, les problèmes qui se posent assez souvent à moi dans le cas de ce jeu sont aussi le fait de placer les fonctions *args.mainloop()... (qui font tourner la fenêtre graphique en boucle pour ne pas qu'elle se ferme) le plus souvent c'est avec les boucles "while" et "for" que j'ai le problème de la fenêtre qui ne s'ouvre pas mais les coordonnées qui défilent, ou la fenetre qui s'ouvre mais les obstacles qui ne défilent pas (même leurs coordonnées ne sont pas calculées)

    encore merci de votre réponse

  4. #4
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par BLOODY_mirai Voir le message
    bonjour, et bien merci de votre réponse, je vais essyer de faire comme conseillé étape par étape, mais en piochant quand même dans votre code pour essayer de rendre le mien un peu plus fonctionnel... par ailleurs, les problèmes qui se posent assez souvent à moi dans le cas de ce jeu sont aussi le fait de placer les fonctions *args.mainloop()... (qui font tourner la fenêtre graphique en boucle pour ne pas qu'elle se ferme) le plus souvent c'est avec les boucles "while" et "for" que j'ai le problème de la fenêtre qui ne s'ouvre pas mais les coordonnées qui défilent, ou la fenetre qui s'ouvre mais les obstacles qui ne défilent pas (même leurs coordonnées ne sont pas calculées)

    encore merci de votre réponse
    Bonjour,

    La méthode widget.mainloop() est la boucle principale du gestionnaire d'événements de Tkinter : il faut donc s'appuyer sur cette boucle pour construire les interactions du jeu (capture touches du clavier, animations découpées dans le temps avec widget.after(delay, func, *args), clics souris, etc) et donc ne vous servir des boucles for / while que pour des petits traitements localisés et non pas pour gérer une boucle programme principale qui viendrait court-circuiter widget.mainloop().

    En termes plus simples, c'est widget.mainloop() la boucle principale de votre jeu, il ne faut donc pas en créer une autre mais plutôt apprendre à vous servir de widget.mainloop() avec pertinence.

    @+.

  5. #5
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Avril 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Avril 2014
    Messages : 7
    Par défaut
    merci pour la réponse comme toujours, mais dans la partie de code que vous m'avez envoyé, ou mettre le widget.mainloop() alors pour que la fenêtre graphique se lance? (j'ai essayé de le mettre à la fin mais elle ne voulait pas se lancer...)

  6. #6
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Avril 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Avril 2014
    Messages : 7
    Par défaut
    merci pour la réponse comme toujours, mais dans la partie de code que vous m'avez envoyé, ou mettre le widget.mainloop() alors pour que la fenêtre graphique se lance? (j'ai essayé de le mettre à la fin mais elle ne voulait pas se lancer...), j'ai bien sûr préalablement défini le canevas et la fenêtre.

  7. #7
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par BLOODY_mirai Voir le message
    merci pour la réponse comme toujours, mais dans la partie de code que vous m'avez envoyé, ou mettre le widget.mainloop() alors pour que la fenêtre graphique se lance? (j'ai essayé de le mettre à la fin mais elle ne voulait pas se lancer...), j'ai bien sûr préalablement défini le canevas et la fenêtre.
    Le plus simple serait de publier la totalité du code du fichier pour que je voie où vous en êtes et comment vous aider.

  8. #8
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Avril 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Avril 2014
    Messages : 7
    Par défaut
    je vous joins une ancienne version du programme avec UN seul obstacle qui se déplace et le Bonhomme qui peut sauter par dessus (projet_v2.1.0), ainsi que la version actuelle(projet_v2.3.0), ce n'est pas folichon, mais déjà mieux que rien (attention l'ancienne version est peut-être mal commentée)
    Fichiers attachés Fichiers attachés

  9. #9
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par BLOODY_mirai Voir le message
    je vous joins une ancienne version du programme avec UN seul obstacle qui se déplace et le Bonhomme qui peut sauter par dessus (projet_v2.1.0), ainsi que la version actuelle(projet_v2.3.0), ce n'est pas folichon, mais déjà mieux que rien (attention l'ancienne version est peut-être mal commentée)
    Bon, je viens de jeter un oeil à vos fichiers : clairement, vous n'avez pas compris le fonctionnement de mainloop() => vous en mettez un peu partout, au petit bonheur la chance.

    Si j'avais un seul conseil à vous donner, ce serait celui-ci : créez-vous un fichier tout neuf et procédez dans l'ordre :

    1. créez votre fenêtre avec ses composants, prenez le temps de bien maîtriser déjà cette étape (je vous y aiderai) ;

    2. utilisez plutôt des noms de variables complets (ne perdez pas de temps à vous demander ce que cette variable fait ou ne fait pas, vous ne devriez même pas perdre de temps à essayer de vous remémorer ce que le nom de la variable suggère) ;

    3. ne partez pas dans toutes les directions en même temps, c'est la meilleure façon de vous "embourber" dans votre code ;

    Exemple de code qui dit les choses simplement comme elles sont :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
     
    import tkinter as TK
     
    # nous verrons cette action dans l'étape no. 2
     
    def demarrer_partie ():
     
        print("la partie démarre ici.")
     
        # on bloque les appels intempestifs
     
        bouton_demarrer.configure(state=TK.DISABLED)
     
    # end def
     
    # étape no. 1 : le cadre graphique du programme
     
    fenetre = TK.Tk()
     
    # on définit quelques infos pratiques
     
    fenetre.title("jeu par Quentin LEBLANC / Corentin PRECOMA")
     
    # on ajoute les composants du jeu
     
    canevas = TK.Canvas(fenetre, width=500, height=300, background="white")
     
    # on place les composants dans la fenêtre principale
     
    canevas.pack(side=TK.TOP, padx=10, pady=10)
     
    # ajoutons un bouton 'Démarrer la partie'
     
    bouton_demarrer = TK.Button(fenetre, text="Démarrer la partie", command=demarrer_partie)
     
    bouton_demarrer.pack(side=TK.LEFT, padx=10, pady=10)
     
    # ajoutons un bouton 'Quitter le jeu'
     
    bouton_quitter = TK.Button(fenetre, text="Quitter le jeu", command=fenetre.quit)
     
    bouton_quitter.pack(side=TK.RIGHT, padx=10, pady=10)
     
    # on entre **UNE SEULE FOIS** dans la grande boucle mainloop()
     
    fenetre.mainloop()
    Vous voyez l'intérêt de coder simple et clair à présent ?

    On sait toujours où on va quand le code est sans ambiguïté.

    @+.

  10. #10
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Avril 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Avril 2014
    Messages : 7
    Par défaut
    On sait toujours où on va quand le code est sans ambiguïté.
    c'est sûr que quand on sait où on va, le chemin à prendre est desuite plus évident, merci pour l'aide et les éclaircissements que vous m'apportez

  11. #11
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Avril 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Avril 2014
    Messages : 7
    Par défaut
    Bon voilà la fenêtre en suivant vos conseils avec un chronomètre intégré, je pense avoir compris comment appeler la fonction principale widget.mainloop(), et comment aérer mon code...
    test_fen.py

  12. #12
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par BLOODY_mirai Voir le message
    Bon voilà la fenêtre en suivant vos conseils avec un chronomètre intégré, je pense avoir compris comment appeler la fonction principale widget.mainloop(), et comment aérer mon code...
    test_fen.py
    Voilà qui est en effet beaucoup mieux. Bravo. +1

    Donc, vous avez bien compris qu'on n'appelle widget.mainloop() qu'UNE SEULE FOIS, généralement via la fenêtre principale fenetre.mainloop() et que c'est cette boucle principale mainloop() qui sera la grande boucle de votre programme, nous sommes d'accord.

    Ensuite, il faut effectivement composer avec cette grande boucle, "faire avec" en quelque sorte, notamment en découpant les actions en petites étapes, quitte à ce que ces étapes s'appellent elles-mêmes (récursivité) pour continuer à fonctionner, comme vous l'avez très judicieusement fait dans la fonction top_horloge() :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    def top_horloge():
        global depart,flag, message
        y=time.time()-depart
        minutes = time.localtime(y)[4]
        secondes = time.localtime(y)[5]
        if flag :
            # évitez ce format sous Python 3
            message.configure(text="%i min %i sec "%(minutes,secondes))
            # format Python 3
            message.configure(text="{m} min {s} sec ".format(m=minutes, s=secondes))
        #fin if
        # on relance dans 1 seconde
        fenetre.after(1000, top_horloge)
    Ce concept sera valable pour les animations de saut du coureur ainsi que pour les animations de défilement latéral des obstacles.

    Petite note en passant : utilisez 'global' uniquement lorsque vous MODIFIEZ une variable globale, si vous accédez à cette variable en lecture seule, vous n'avez pas besoin de la citer dans 'global'.

    Ici, ni depart ni flag ni message ne sont directement modifiées, vous pouvez retirer la ligne de déclaration 'global'.

    Autres remarques :

    Si vous comptez utiliser le chronomètre dans votre jeu, il faudrait peut-être réfléchir à son emplacement dans la fenêtre (je le verrais bien en haut à droite du canevas) et donc se pencher sur la méthode widget.grid() en remplacement de widget.pack().

    Documentation :

    http://effbot.org/tkinterbook/grid.htm

    http://effbot.org/tkinterbook/pack.htm

    De plus, j'ajouterais qu'il n'est peut-être pas nécessaire de l'afficher aussi gros, que ce serait plus "classe" de l'afficher au format HH:MM:SS (e.g. 00:01:34) qu'en toute lettre, mais ça, c'est une question de choix esthétiques / artistiques.

    Après, chacun fait comme il veut.

    Pied sur le frein, attention à ne pas repartir dans tous les sens : finissez bien d'abord toute la partie chronomètre avant d'attaquer autre chose.

    Bravo pour les progrès accomplis.

    @+.

Discussions similaires

  1. Jeu le mot le plus long avec Tkinter
    Par calaca dans le forum Tkinter
    Réponses: 12
    Dernier message: 10/12/2013, 19h16
  2. [Projet Jeu] - Moteur 2D avec GLScene / Asphyre
    Par Leobaillard dans le forum Langage
    Réponses: 61
    Dernier message: 06/05/2006, 18h26
  3. Comment faire un jeu en réseau avec J2ME ?
    Par Yakurena dans le forum Java ME
    Réponses: 1
    Dernier message: 27/03/2006, 19h09
  4. [Tkinter] Plusieurs fenêtre avec Tkinter
    Par cyrpaut dans le forum Tkinter
    Réponses: 2
    Dernier message: 04/01/2006, 22h24
  5. [Tkinter] Un petit souçis d'event avec Tkinter
    Par fire.stone dans le forum Tkinter
    Réponses: 4
    Dernier message: 29/10/2005, 20h56

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo