Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Jeu] Classique: Snake

Sujet résolu
    8 octobre 2010 à 15:51:05

    Bonjour,

    Je me suis mi dans la tête de coder un Snake avec Tkinter.
    Pour cela, j'ai crée trois classes, <Snake> & <Principale> & <Pomme>.

    <Principale> créée une fenêtre, un Canevas, des boutons qui encapsule <Snake>.

    Mes questions:

    1- Est ce que l'affichage graphique doit encapsuler tout mon jeu ou bien c'est elle qui doit se faire encapsulée ?

    2- Comment permettre à mon snake de se déplacer tout seul ? (Mon appel récursif bloc tout mon jeu, comment faire ?)

    Mon code-source comporte un seul fichier. Cependant, je vous donne mon code-source classe par classe (deux en tout car j'ai regroupé <Snake> & <Pomme>)
    Je vous remercie d'avance.

    Classe <Principale>:
    from tkinter import *
    import random
    
    
    #-*-*- <Les Classes> || Début de <Principale> -*-*-#
    
    class Principale(object):
        """Classe créant les fenêtre, boutons..."""
        def __init__(self):
            """Constructeur"""
            #Variables de cette classe
            self.flag = "" #Pour voir si un touche est préssée
            self.score = 0
            self.etat = False
            #Variables d'instances
            self.a_serp = Serpent()
            self.a_pomme = Pomme()
    
            #Fenêtre
            self.fen = Tk()
            self.fen.title("Snake")
    
            #Canevas
            self.can = Canvas(self.fen, height = 300, width = 300, \
                              relief = RIDGE, bg = "dark grey")
            self.can.bind_all("<Up>",   lambda event: self.a_serp.move(event, "H"))
            self.can.bind_all("<Right>",lambda event: self.a_serp.move(event, "D"))
            self.can.bind_all("<Down>", lambda event: self.a_serp.move(event, "B"))
            self.can.bind_all("<Left>", lambda event: self.a_serp.move(event, "G"))
            self.can.pack()
    
            #Bouton
            self.bou = Button(self.fen, text = "Jouer/Recommencer", command = self.jouer)
            self.bou.pack()
    
        def initialiser(self):
            """Initialise le plateau de jeu"""
            self.score = 0
            self.a_serp.nombreBlocs = 1
            self.a_serp.listeBlocs  = [[20, 20], [40, 20],[60, 20]]
            self.a_pomme.bol_pomme  = False
        
            self.can.delete(ALL)
            
            self.a_pomme.genererPomme()
            self.afficherElem()
            
        def jouer(self):
            """Lance la partie"""
            self.initialiser()
    
        def etatPartie(self):
            """La partie est elle gagnée ou perdue"""
            pass
            
        def mangerPomme(self):
            """Est ce qu'une partie du serpent est en contacte avec une pomme"""
            pass
    
        def afficherElem(self):
            """Affiche graphiquement les éléments dans le canvas"""
            self.can.delete(ALL)
            
            #Création des blocs du snake
            for i in self.a_serp.listeBlocs:
                 self.can.create_rectangle((i[0], i[1]), \
                                            i[0]+self.a_serp.tailleBloc, i[1]+self.a_serp.tailleBloc, \
                                            fill = "green")
            #Création d'une pomme     
            self.can.create_oval(self.a_pomme.posPomme[0], self.a_pomme.posPomme[1], \
                                 self.a_pomme.posPomme[0]+10, self.a_pomme.posPomme[1]+10, \
                                 width = 2, fill = "red")
            #Une boucle appellée récursivement toute les 200ms
            self.can.after(200, self.afficherElem)
    


    Classe <Snake>:
    #-*-*- <Les Classes> || Début de <Serpent> -*-*-#
        
    class Serpent(object):
        """Classe définissant le serpent"""
        def __init__(self):
            """Constructeur"""
            self.nombreBlocs = 3
            self.tailleBloc  = 20
            self.listeBlocs  = [[20, 20], [40, 20],[60, 20]]
          
        def move(self, event, direction):
            """Dans quelle direction doit on bouger le serpent"""
            fin = []
            #On parcours /listeBlocs/ grâce à l'entier /i/
            #Si on arrive au dernier élément
            #On ajouter le contenue du tuple dans la liste /fin/
            for i in range(len(self.listeBlocs)):
                    if i+1 >= len(self.listeBlocs):
                        for j in self.listeBlocs[i]:
                            fin.append(j)
                            
            if  direction == "H":
                print(direction, fin)    #vaut [60, 20]                   
                self.listeBlocs.append([fin[0], fin[1]-20])           
                del(self.listeBlocs[0])  
                
            elif direction =="D":
                print(direction, fin)    #vaut [60, 20] 
                self.listeBlocs.append([fin[0]+20, fin[1]])           
                del(self.listeBlocs[0])  
                
            elif direction =="B" :
                print(direction, fin)    #vaut [60, 20] 
                self.listeBlocs.append([fin[0], fin[1]+20])           
                del(self.listeBlocs[0])  
                
            elif direction =="G" :
                print(direction, fin)    #vaut [60, 20] 
                self.listeBlocs.append([fin[0]-20, fin[1]])           
                del(self.listeBlocs[0])
    
            
    
    #-*-*- <Les Classes> || Début de <Pomme> -*-*-#
        
    class Pomme(object):
        """Classe définissant les pommes"""
        def __init__(self):
            """Constructeur"""
            self.bol_pomme = False
            self.posPomme = [0,0]
    
            self.genererPomme()
    
        def genererPomme(self):
            """Genère une pomme aléatoirement"""
            self.posPomme = [random.randrange(0, 300-20), random.randrange(0, 300-20)]
    
        
        
    if __name__ == "__main__":
        p = Principale()
        p.fen.mainloop()
    


    Realmagma.
    • Partager sur Facebook
    • Partager sur Twitter
      8 octobre 2010 à 16:35:45

      Si ton but est de programmer un snake, je te conseille plutôt une librairie 2D comme Pygame ou PySFML. Si ton but est de te familiariser avec les GUI, un snake n'est peut-être pas le meilleur choix, vu que ça va surtout consister à imiter une autre librairie à l'intérieur d'un canevas. D'ailleurs, si tu veux faire de la GUI "sérieusement", TkInter n'est pas un très bon choix. Je conseille personnellement PyQt, certains diront PyGTK ou WxPython.
      • Partager sur Facebook
      • Partager sur Twitter
        8 octobre 2010 à 20:55:10

        exemple de snake avec pygame:

        from pygame import*;d=display;y,D,S=s=[15,16,17];n,p,x=D,99,d.set_mode([225]*2).fill
        while(s.count(S)&1)*S%n*(S&240):
            for e in event.get(2):D=(-1,-n,n,1)[e.key&3]
            s=s[p!=S:]+[S+D];x(0)
            if p==S:p=s[0]
            for i in[p]+s:x(-1,((i-1)%n*y,(i-n)/n*y,y,y))
            d.flip();S=s[-1];time.wait(99)
        


        oui, je sais, je sais ... :p
        • Partager sur Facebook
        • Partager sur Twitter

        Python c'est bon, mangez-en. 

          8 octobre 2010 à 21:26:02

          Bonjour,
          Tu peux aller voir sur ce post (dernier message). J'ai réalisé un petit snake avec tkinter.
          ça peut te donner des idées.
          • Partager sur Facebook
          • Partager sur Twitter
            8 octobre 2010 à 22:33:47

            Citation : josmiley

            exemple de snake avec pygame:

            from pygame import*;d=display;y,D,S=s=[15,16,17];n,p,x=D,99,d.set_mode([225]*2).fill
            while(s.count(S)&1)*S%n*(S&240):
                for e in event.get(2):D=(-1,-n,n,1)[e.key&3]
                s=s[p!=S:]+[S+D];x(0)
                if p==S:p=s[0]
                for i in[p]+s:x(-1,((i-1)%n*y,(i-n)/n*y,y,y))
                d.flip();S=s[-1];time.wait(99)
            



            oui, je sais, je sais ... :p


            C'est de la triche ça...
            • Partager sur Facebook
            • Partager sur Twitter
              9 octobre 2010 à 7:08:23

              Citation : realmagma

              2- Comment permettre à mon snake de se déplacer tout seul ? (Mon appel récursif bloc tout mon jeu, comment faire ?)


              thread-le ...


              Citation : Maxibolt

              C'est de la triche ça...


              na, c'est du byte-crunching ^^
              • Partager sur Facebook
              • Partager sur Twitter

              Python c'est bon, mangez-en. 

                9 octobre 2010 à 12:42:25

                Bonjour,

                je sais que Tkinter n'est pas fait pour les jeux, je fais ça juste pour le fun.
                Je voudrai juste savoir comment faire pour que mon snake avance tout seul dans mon code.

                Je cherche toujours et si quelqu'un aurait une solution, qu'il me le fasse savoir.
                Merci d'avance,
                Realmagma.
                • Partager sur Facebook
                • Partager sur Twitter
                  9 octobre 2010 à 20:47:53

                  le monsieur va répéter ... thread-le
                  si possible ...
                  • Partager sur Facebook
                  • Partager sur Twitter

                  Python c'est bon, mangez-en. 

                    9 octobre 2010 à 23:47:29

                    Citation : josmiley

                    le monsieur va répéter ... thread-le


                    ou pas.

                    Simplement tu fais une boucle principale, et à chaque tour de boucle tu déplaces ton snake en fonction du temps écoulé depuis le dernier affichage.

                    Un thread pour déplacer un snake.

                    o_O
                    Il n'y a surement qu'en python ou en Java qu'on voit ça, je pense...
                    • Partager sur Facebook
                    • Partager sur Twitter
                    Zeste de Savoir, le site qui en a dans le citron !
                      10 octobre 2010 à 6:18:02

                      Citation : GurneyH


                      Un thread pour déplacer un snake.
                      Il n'y a surement qu'en python ou en Java qu'on voit ça, je pense...



                      On demande une solution, j'en donne une ...
                      la demande est :

                      Citation : realmagma

                      Je voudrai juste savoir comment faire pour que mon snake avance tout seul dans mon code.

                      • Partager sur Facebook
                      • Partager sur Twitter

                      Python c'est bon, mangez-en. 

                        10 octobre 2010 à 14:47:48

                        Désolé Josmiley, je n'avais pas vu ton message :D
                        Avec le code que j'ai fait, je ne peux pas Gurney H, si je boucle à un endroit, l'affichage ne se fera plus.
                        Je vais voir du côté des Threads, mais cela ne me plaît pas du tout.
                        • Partager sur Facebook
                        • Partager sur Twitter
                          10 octobre 2010 à 14:53:26

                          Je ne connais pas Tkinter, mais pourquoi ne pas placer un affichage en fin de boucle.

                          Avec les lib 2d faites pour ce genre de choses, le schéma classique
                          while(done)
                              gestion de événements
                              update des éléments de ton jeu 
                              affichage
                              rafraichissement


                          Après savoir si c'est possible avec Tkinter?.
                          • Partager sur Facebook
                          • Partager sur Twitter
                          Zeste de Savoir, le site qui en a dans le citron !
                            10 octobre 2010 à 15:34:03

                            J'ai essayé ce que tu m'as dit GurneyH:

                            #Canevas
                                    self.can = Canvas(self.fen, height = 300, width = 300, \
                                                      relief = RIDGE, bg = "dark grey")
                                    self.can.bind_all("<Up>",   lambda event: self.truc(event, "H"))
                                    self.can.bind_all("<Right>",lambda event: self.truc(event, "D"))
                                    self.can.bind_all("<Down>", lambda event: self.truc(event, "B"))
                                    self.can.bind_all("<Left>", lambda event: self.truc(event, "G"))
                                    self.can.pack()
                            
                            #Plus loin dans la même classe <Principale>
                            #
                            #
                            def afficherElem(self):
                                    """Affiche graphiquement les éléments dans le canvas"""
                                    self.can.delete(ALL)
                                    
                                    #Création des blocs du snake
                                    for i in self.a_serp.listeBlocs:
                                         self.can.create_rectangle((i[0], i[1]), \
                                                                    i[0]+self.a_serp.tailleBloc, i[1]+self.a_serp.tailleBloc, \
                                                                    fill = "green")
                                    #Création d'une pomme     
                                    self.can.create_oval(self.a_pomme.posPomme[0], self.a_pomme.posPomme[1], \
                                                         self.a_pomme.posPomme[0]+10, self.a_pomme.posPomme[1]+10, \
                                                         width = 2, fill = "red")
                                    
                                    
                                def truc(self, event, direction):
                                    """Rajouté"""
                                    self.afficherElem()
                                    self.a_serp.move(event, direction)
                                    
                                    self.can.after(200, self.truc(event, direction))
                            



                            Fonction move() dans la classe <Serpent>

                            def move(self, event, direction):
                                    """Dans quelle direction doit on bouger le serpent"""
                                    fin = []
                                    #On parcours /listeBlocs/ grâce à l'entier /i/
                                    #Si on arrive au dernier élément
                                    #On ajouter le contenue du tuple dans la liste /fin/
                                    for i in range(len(self.listeBlocs)):
                                            if i+1 >= len(self.listeBlocs):
                                                for j in self.listeBlocs[i]:
                                                    fin.append(j)
                                                    
                                    if  direction == "H":
                                        print(direction, fin)    #vaut [60, 20]                   
                                        self.listeBlocs.append([fin[0], fin[1]-20])           
                                        del(self.listeBlocs[0])  
                                        
                                    elif direction =="D":
                                        print(direction, fin)    #vaut [60, 20] 
                                        self.listeBlocs.append([fin[0]+20, fin[1]])           
                                        del(self.listeBlocs[0])  
                                        
                                    elif direction =="B" :
                                        print(direction, fin)    #vaut [60, 20] 
                                        self.listeBlocs.append([fin[0], fin[1]+20])           
                                        del(self.listeBlocs[0])  
                                        
                                    elif direction =="G" :
                                        print(direction, fin)    #vaut [60, 20] 
                                        self.listeBlocs.append([fin[0]-20, fin[1]])           
                                        del(self.listeBlocs[0])
                            


                            Une autre solution or mis les Threads ?
                            • Partager sur Facebook
                            • Partager sur Twitter
                              10 octobre 2010 à 15:39:06

                              Avec ce code, il se passe quoi?

                              Ton serpent est immobile?

                              Il faut conserver la direction courante jusqu'au prochain évènement(changement de direction.)
                              • Partager sur Facebook
                              • Partager sur Twitter
                              Zeste de Savoir, le site qui en a dans le citron !
                                10 octobre 2010 à 15:54:32

                                Par exemple si j'appuie sur la touche fléchée-D, mon print s'affiche (D, [xx, xx]) indéfiniment, comme si j'étais dans une boucle infinie.

                                Si j'appuie une seconde fois sur la touche fléchée-H ou B ou G, rien ne se passe.
                                Je suis donc obligé de faire un CTRL-C deux fois de suite et quitter salement mon programme.

                                EDIT: Oui mon snake reste immobile.
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  10 octobre 2010 à 22:19:45

                                  tu as déjà posé la question sur le forum C, et j'ai posté un code...

                                  Jamais, on utilise les trheads pour effectuer une anim...(sauf en Java et en Python...)

                                  Genre un shoot, 100 ennemis simultanés?
                                  100 threads? :lol:

                                  Bref, en python, je ne peux pas aider plus, mais j'ai répondu à ta question sur le forum C.

                                  Lorsque tu as posé la question...
                                  Il faut lire les threads et tester
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                  Zeste de Savoir, le site qui en a dans le citron !
                                    10 octobre 2010 à 22:31:09

                                    y a pas un timer livré avec TK ?
                                    • Partager sur Facebook
                                    • Partager sur Twitter

                                    Python c'est bon, mangez-en. 

                                    Anonyme
                                      10 octobre 2010 à 22:53:21

                                      Le threading est totalement inutile ici, même en python !
                                      Je pense que tu devrais revoir tout ton script pour pouvoir implémenter un systême de boucle ou avec la méthode 'after()'. (nyko77 à proposé une solution que tu devrais étudier. ;) )
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        11 octobre 2010 à 9:08:20

                                        Je ne comprends pas pourquoi mon code ne marche pas.
                                        J'utilise la méthode after():

                                        • - J'affiche à l'écran
                                        • - Je bouge
                                        • - Je rappel la fonction (Équivalent à une boucle)


                                        Le problème c'est que les coordonnées de mon snake bougent, mais le snake reste immobile (pa de blit) malgré mon affichage. De plus je ne peux même plus changer de direction...

                                        Pourquoi donc ? C'est ça que je n'arrive pas à comprendre...

                                        P.S: Je n'utiliserai pas de Threads
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          11 octobre 2010 à 14:41:16

                                          j'ai regardé ton code original, j'ai essayé d'appliquer ça:
                                          http://www.commentcamarche.net/forum/a [...] -et-tkinter#9
                                          mais je ne connais pas Tkinter, j'y suis pas arrivé, ça peut t'aider pitêtre.
                                          • Partager sur Facebook
                                          • Partager sur Twitter

                                          Python c'est bon, mangez-en. 

                                          [Jeu] Classique: Snake

                                          × 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.
                                          • Editeur
                                          • Markdown