Partage
  • Partager sur Facebook
  • Partager sur Twitter

Le jeu du serpent.

    22 août 2010 à 5:26:36

    Salut.

    Tout le monde connaît le fameux jeu du serpent (ou snake).
    C'est le jeu que je suis en train de coder.

    Par contre, je suis en ce moment face à un problème que je redoutait depuis le début
    du dévelopement: quand le serpent mange un item, il ne grandit pas.

    Je n'arrive pas à créer une fonction qui génère un autre carré qui suit le premier, et ainsi de suite.

    Voici l'intégralité du code (version 3.1.2)(touches directionnelles pour se déplacé)

    from tkinter import *
    from random import randrange
    
    def go():
        global dx, dy, a, A, z, Z, flag1, flag2, flag3, flag4, x, y, STOP
        dx, dy = 10, 10
        a, A, z, Z = 1, 1, 1, 1
        x, y = 250, 250
        can.coords(carre,x, y, x+10, y+10)
        STOP = 1
        flag1 = 0
        flag2 = 0
        flag3 = 0
        flag4 = 0
       
        
    
    def RANDRANGE ():
        global rond, RandX, RangeY
        RandX = randrange(10,500)
        RangeY = randrange(10,500)
        
        can.coords(rond,RandX, RangeY, RandX+10, RangeY+10)
        
    
           
    def mouvement (evt): #Droite#
        global flag1, flag2, flag3, flag4, a, A, z, Z, STOP
        
        if(flag2 == 0):
         flag1, flag2, flag3, flag4 = 1,0,0,0
    
         STOP=0
         
         if (flag1 == 1 and a == 1):
           droite()
       
    
    def mouvement2 (evt): #Gauche#
        global flag1, flag2, flag3, flag4, a, A, z, Z, STOP
    
        if(flag1 == 0):
         flag1, flag2, flag3, flag4 = 0,1,0,0
        
         STOP=0
         
         if (flag2 == 1 and A == 1):
           gauche()
      
    
    
    def mouvement3 (evt): #Haut#
        global flag1, flag2, flag3, flag4, a, A, z, Z, STOP
    
        if(flag4 == 0):
         flag1, flag2, flag3, flag4 = 0,0,1,0
        
         STOP=0
         
         if (flag3 == 1 and z == 1):
           haut()
       
    
    def mouvement4 (evt): #Bas#
        global flag1, flag2, flag3, flag4, a, A, z, Z, STOP
    
        if(flag3 == 0):
         flag1, flag2, flag3, flag4 = 0,0,0,1
        
         STOP=0
         
         if (flag4 == 1 and Z == 1):
           bas()
    
        
    
    def droite (): #S'active avec a#
        global x, y, dx, dy, flag1, a, A, z, Z, RandX, RangeY, STOP
        a  = 0
        A  = 1
        z  = 1
        Z  = 1
        if(STOP == 1):
            flag1 = 0
        
    
        
        if ((x - RandX)**2 + (y - RangeY)**2 <= (5 + 5)**2):
            RANDRANGE()
            
            
    
        x = x+dx
        can.coords(carre, x, y, x+10, y+10)
    
        if (x > 500):
          go()
            
        
            
            
        if (flag1 > 0):
            fen1.after(60, droite)
            
    
    
    
    def gauche (): #S'active avec A#
        global x, y, dx, dy, flag2, a, A, z, Z, RandX, RangeY, STOP
        a  = 1
        A  = 0
        z  = 1
        Z  = 1
        if(STOP == 1):
            flag2 = 0
            
       
        if ((x - RandX)**2 + (y - RangeY)**2 <= (5 + 5)**2):
            RANDRANGE()
            
            
    
        x = x-dx
        can.coords(carre,x, y, x+10, y+10)
    
        if (x < 0):
           go()
    
             
            
        if (flag2 > 0):
            fen1.after(60, gauche)
    
                    
    
    
    def haut (): #S'active avec z#
        global x, y, dx, dy, flag3, a, A, z, Z, RandX, RangeY, STOP
        a  = 1 
        A  = 1
        z  = 0
        Z  = 1
        if(STOP == 1):
            flag3 = 0
        
         
        if ((x - RandX)**2 + (y - RangeY)**2 <= (5 + 5)**2):
            RANDRANGE()
            
            
    
        y = y-dy
        can.coords(carre,x, y, x+10, y+10)
    
        if (y < 0):
          go()
    
       
            
        if (flag3 > 0):
           fen1.after(60, haut)
    
    
    
    def bas (): #S'active avec Z#
        global x, y, dx, dy, flag4, a, A, z, Z, RandX, RangeY, STOP
        a  = 1
        A  = 1
        z  = 1
        Z  = 0
        if(STOP == 1):
            flag4 = 0
       
           
        if ((x - RandX)**2 + (y - RangeY)**2 <= (5 + 5)**2):
            RANDRANGE()
           
            
    
        y = y+dy
        can.coords(carre,x, y, x+10, y+10)
    
        if (y > 500):
            go()
    
        
            
        if (flag4 > 0):
           fen1.after(60, bas)
           
    
    
    #========== Programme principal =============
    x, y = 250, 250
    dx, dy = 10, 10
    flag1 = 0
    flag2 = 0
    flag3 = 0
    flag4 = 0
    a     = 1
    A     = 1
    z     = 1
    Z     = 1
    RandX = randrange(10,500)
    RangeY = randrange(10,500)
    STOP = 0
    
    
    
    
    fen1 = Tk()
    fen1.title("Serpent")
    
    
    
    
    can = Canvas(fen1,bg='dark grey',height=500, width=500)
    can.pack(side=LEFT, padx =5, pady =5)
    
    
    carre = can.create_rectangle(x, y, x+10, y+10, width=2, fill='black')
    rond  = can.create_oval(RandX, RangeY, RandX+10, RangeY+10, width=1, fill='white')
    
    
    
    fen1.bind_all('<Right>', mouvement)
    fen1.bind_all('<Left>', mouvement2)
    fen1.bind_all('<Up>', mouvement3)
    fen1.bind_all('<Down >', mouvement4)
    
    
    
    
    
    fen1.mainloop()
    




    Si vous avez des problèmes à comprendre le code, n'hésitez pas à me le dire, je mettrais des commentaires.
    • Partager sur Facebook
    • Partager sur Twitter
    Anonyme
      22 août 2010 à 14:37:21

      En fait pour faire simple tu devrais créer une fonction te permettant de construire un carré avec les arguments x, y, dx et dy.

      Ensuite poser une condition, du genre

      Si 1er carré touche item
      alors créer carre avec les coordonnées ...

      Franchement ce genre de travail serait beaucoup plus simple avec une approche POO.

      • Partager sur Facebook
      • Partager sur Twitter
        22 août 2010 à 17:32:02

        Euh... C'est quoi exactement de la programmation orientée objet? Parce que je me suis documenté, mais je n'ai toujours pas de bonne définition sur ce sujet.
        • Partager sur Facebook
        • Partager sur Twitter
          22 août 2010 à 17:44:15

          La POO (Programmation Orientée Objet) est un concept informatique qui te fait travailler avec des objets, plutôt que des données 'brutes'. A chaque objet ses attributs et méthodes, ça permet une clarification du code.
          Par exemple, dans ton code, Tk() est un objet, et fen1 une instance de cet objet. Tu pourrais créer ton propre objet 'Serpent', avec ses méthodes 'tourner()', 'manger()', etc... en plus tu pourrais réutiliser cet objet pour créer d'autres serpents dans ton programme ;)
          Y a une introduction à la POO dans le cours python présent sur le site, mais aussi dans les cours c++ et java.
          Je te conseille de t'y mettre le plus rapidement possible, ça change très vite la vie (et en bien :) ).

          Bye !
          • Partager sur Facebook
          • Partager sur Twitter
            22 août 2010 à 17:55:58

            Ok merci pour la réponse(je me coucherai moins con ce soir).

            Pour en revenir au jeu, ce que tu m'a proposé fred1599, ça marche... Mais le problème est de réussir à faire suivre ce carré vers le premier.
            • Partager sur Facebook
            • Partager sur Twitter
            Anonyme
              22 août 2010 à 20:18:19

              Eh bien quand tu déplaces la tete du snake, les autres se déplacent exactement de la même façon.

              Exemple:

              Si tête avance de 10 vers la droite, eh bien le carré suivant aussi, etc...

              • Partager sur Facebook
              • Partager sur Twitter
                22 août 2010 à 22:12:32

                J'ai essayé de faire ce que tu m'a dit, mais le carré généré ne bouge pas d'un pouce malgré les conditions que j'ai faite...

                Je suis complètement pommé :'(

                def CARRE ():
                    global x, y, dx, dy, X, Y, dX, dY
                
                    X, Y, dX, dY = x, y, dx, dy
                    
                    can.create_rectangle(X, Y, X+10, Y+10, width=2, fill='black')
                  
                    if(a == 1):
                        X = X+dX
                
                    if (A == 1):
                        X = X-dX
                
                    if (z == 1):
                        Y = Y-dY
                
                    if (Z == 1):
                        Y = Y+dY
                





                • Partager sur Facebook
                • Partager sur Twitter
                  22 août 2010 à 23:33:02

                  Je trouve ton code assez indigeste, tu lis le tutoriel de Gérad Swinnen (désolé si j'écorche le nom) il me semble, c'est pour ça que tu utilises des flags et des globals un peu partout, et ca rend le code assez lourd à comprendre :x
                  Premièrement je te conseille d'aller voir ce qu'est une fonction lambda ce qui t'évitera cette redondance dans tes fonctions !

                  Ensuite, à ta place j'envisagerais le jeu ainsi :

                  Dans un snake "classique", à chaque mouvement tu as 4 possibilités :
                  - Le joueur a perdu
                  - Le joueur a gagné
                  - Le joueur a mangé une pomme (le serpent grandit)
                  - Le joueur a fait un simple mouvement

                  Pour moi le plus simple est de créer une liste contenant les positions (en tuple) de toutes les parties du corps, pourquoi ? Parce que c'est extremement simple à gérer :
                  - Si le serpent grandit, il suffit d'ajouter un nouveaux tuple à la liste (en première position)
                  - Si le serpent bouge, il suffit de supprimer le dernier élément et d'en ajouter un nouveau en tête de liste

                  Ensuite je te conseille d'envisager ton canevas comme une grille de 50 case par 50, je trouve ça beaucoup plus simple à gérer (avis perso, mais je pense que je ne suis pas le seul).

                  Grossièrement ça donnerait ça :
                  liste_coords = [(2,2)] # j'ai décidé de commencer avec la tête en case (2,2) sur ma grille
                  liste_dessin = [] # liste contenant les références des morceaux dessinés, pour pouvoir supprimer le dernier
                  liste_dessin.append(can.create_rectangle(...)) # je te laisse chercher comment on obtient les coords sur le canvas en fonctiond des coords sur la grille 
                  
                  pos = (2,2) # les coordonnées de la tête
                  
                  # gestion des mouvements ici (si touche droite, alors pos[1] += 1, etc... )
                  
                  # Ensuite on pourrait gérer ainsi :
                  if "manger_pomme":
                      liste_coords = [pos] + liste_coords
                      liste_dessin = [can.create_rectangle(pos)] + liste_dessin # pos à remplacer !
                  else:
                      liste_coords = [pos] + liste_coords[:-1] # on oublie la dernière coords !
                      can.delete(liste_dessin[-1]) # on efface le dernier carré
                      liste_dessin = [can.create_rectangle(pos)] + liste_dessin[-1] # pareil
                  

                  Evidemment ce n'est pas un code utilisable tel quel, c'est juste pour te montrer un peu une façon de faire parmis d'autres, à toi de voir si tu la comprends et si tu peux l'utiliser ;)

                  Sinon tu devrais vraiment commencer la POO avant de t'attaquer à faire ce genre de jeu, non pas que ce soit infaisable sans ou que cela te facilite forcément la tâche avec la POO, mais tu vas (je pense) prendre de mauvaise habitude hors POO (l'utilisation de beaucoup de global entre autres !)
                  • Partager sur Facebook
                  • Partager sur Twitter
                    24 août 2010 à 6:06:57

                    Bon, j'ai essayé de faire un test sur une autre fenêtre. Le but étant simplement de réussir à généré un autre carré et de faire suivre le premier.

                    Le carré ce déplace vers la gauche en appuyant juste sur entrer

                    from tkinter import *
                    
                    
                    
                    def avance2():
                        global X, y, x, carre2
                        
                        
                        carre2 = can.create_rectangle(X, y, X+10, y+10, width=2, fill='black')
                        Création = 0
                    
                         
                    def avance(evt):
                      global x, vx, W, Création, X, y, carre2, X0
                      
                      x = x-vx
                      can.coords(carre, x, y, x+10, y+10)
                    
                      
                      if (Création == 1):
                         avance2()
                    
                      X = x+15
                      can.coords(carre2, X, y, X+10, y+10)
                      
                      
                      
                    
                    fen = Tk()
                    
                    
                    
                    x, y = 250, 250
                    vx, vy = 7, 7
                    X = 0
                    Création = 1
                    
                    can = Canvas(fen,bg='dark grey',height=500, width=500)
                    can.pack()
                    
                    carre = can.create_rectangle(x, y, x+10, y+10, width=2, fill='black')
                    fen.bind('<Return>', avance)
                    
                    fen.mainloop()
                    



                    Vous remarquerez que le deuxième carré s'allonge...
                    • Partager sur Facebook
                    • Partager sur Twitter
                      25 août 2010 à 0:28:46

                      On pourrait également envisager une approche objet (enfin, « objet ») en créant une classe Block (un bloc du serpent) dont la première instance serait la tête et les autres, le reste du corps. De cette manière, on pourrait donner à chaque nouvelle instance la référence du bloc qui le précède. Le code serait alors bien moins lourd : il suffirait qu'à chaque mouvement, chaque instance de Block bouge vers la position de son prédécesseur (dont on connaît la référence !). De cette manière, le seul Block qu'il faudra bouger « à la main » sera la tête, les autres suivront. Et cela permettra en outre d'écrire une jolie méthode pour vérifier si la tête n'est pas à la position d'un des Block, en d'autres termes, que le joueur a perdu.
                      • Partager sur Facebook
                      • Partager sur Twitter
                        25 août 2010 à 0:38:17

                        Arg, j'ai pas encore étudié la POO et les classes...

                        Tu pourrais pas me donner un petit aperçu de ce que ça pourrait donner?

                        J'ai vraiment envie de finir ce code...
                        • Partager sur Facebook
                        • Partager sur Twitter
                        Anonyme
                          25 août 2010 à 11:07:05

                          Citation

                          J'ai vraiment envie de finir ce code...



                          Eh bien moi j'ai même pas envie de le lire :)

                          Citation

                          Tu pourrais pas me donner un petit aperçu de ce que ça pourrait donner?



                          Je pense que tu devrais commencer par les bases python en ce qui concerne la POO.

                          Essayer le plus possible de rendre ton code lisible par tous et d'éviter les répétitions (le papier est efficace pour cela).

                          Ensuite tu attaques ton projet.

                          Des exercices simples de POO sont dans le tuto swinnen. Attaque-les et n'hésite pas à poser tes questions, on se fera un plaisir de répondre.

                          • Partager sur Facebook
                          • Partager sur Twitter
                            25 août 2010 à 11:38:18

                            Voilà une approche différente (mais très commune pour ce genre de jeu) qui consiste à diviser l'écran en grille et de placer à chaque case un élément (serpent, lapin, caca…).
                            Ce code source est fonctionnel, tu as toutefois besoin du module pygame (cf. google) car tk n'est pas fait pour créer des jeux :
                            http://www.google.com/codesearch/p?hl= [...] x-EE/snake.py
                            • Partager sur Facebook
                            • Partager sur Twitter
                              25 août 2010 à 21:14:47

                              Petit message hors-sujet (enfin pas totalement non plus)
                              Pour la POO ie programmation orienté objet :
                              Le concept est assez simple, mais demande une petite gymnastique de l'esprit que tout programmeur python se doit d'effectuer un jour où l'autre dans sa vie (détrompez moi...).
                              Il faut savoir bien sur que tout ce qui est faisable en POO est faisable en procédurale (que des fonctions).

                              Mais alors, à quoi cela sert-il ? o_O

                              Pour te répondre je te pose une question à mon tour : à quoi servent les fonctions (programmation procédurale) que tu crées quand tu programmes ? Tu pourrais très bien faire la meme chose sans aucune fonction (bon courage si tu essais)... Mais tu ne le fait pas, pourquoi ?

                              Et bien tu veux mettre de l'ordre dans ton code, tu veux pouvoir utiliser 'deplace(mon_serpent)' plutot que de récrire tout le code, pas vrai ? Tu veux aussi pouvoir associer plusieurs fonctions sans problème, ect ect...

                              Sache que la POO cela sert à ça : mettre de l'ordre dans ton code, ect ect ...

                              Quand tu ranges ta chambre, tu va mettre dans ton placard les habits, les stylos dans ta trousse, les chaussettes dans un tiroir, les livres sur une étagère, ect ect... tu mets chaque chose à la place que TU (et personne d'autre) veux bien lui donner, n'est-ce pas ? (tu ne laisse pas tout en vrac par terre ?)

                              La POO, c'est le meme principe que quand tu range ta chambre. Les affaires, ce sont tes fonctions et tes variables. tes meubles, ce sont , ce qu'on appelle les classes.
                              Lors d'une feuille python vierges, tu n'as aucune affaire et que quelque meuble (que tu connais déjà). Ces meubles que tu as déjà sont : les listes, les string, les nombres, les tuples, les dictionnaires,... et j'en passe. Et ainsi tu peux déjà mettre tes affaires dans ces quelque meubles. Toutefois, imagine que tu veuille un objet où tu puisse ranger juste tes stylos et rien d'autre? tu ne vas pas les mettre par terre, et tu ne vas pas les mettres sur ton frigo... L'idée, c'est que tu vas acheter une trousse. On dit que tu vas creer une classe 'trousse' où tu puisse ranger tes stylos (ie tes fonctions).

                              En bref , les classes ce sont tes meubles; tes fonctions (ou méthodes) et tes variables (ou attributs) ce sont tes affaires.

                              Pour reprendre l'image de la trousse en python cela nous donnerais ça :


                              class Trousse(object):
                                 def stylos_bleu(self): return 'ce stylos ecrit bleu'
                                 def stylos_rouge(self): return 'ce stylos ecrit rouge'
                                 # ect...
                                 # le mot clef self veut dire : appartient à
                                 # ensuite tu creer ta trousse
                                 Matrousse = Trousse()
                                 print Matrousse.stylos_bleu()
                                 print Matrousse.stylos_rouge()
                                 # le mot clef self... c'est le point.  Et ça se lis, stylos_bleu appartient à Matrousse
                              


                              Et voila, tu viens de creer ta première classe. :D

                              J'espère que j'ai été claire...

                              Aller bon courage. ;)

                              Cordialement,
                              zazapeta
                              • Partager sur Facebook
                              • Partager sur Twitter
                                4 septembre 2010 à 3:02:34

                                Bonjour,

                                vu que je savais pas trop quoi faire, je me suis pris au jeu de faire un snake en poo.
                                Ça va peut-être t'aider à comprendre la poo. J'ai mis quelques commentaires dans le code.
                                J'ai codé en python 2.6 mais je pense qu'il suffi de remplacer "import Tkinter as tk" par "import tkinter as tk" (pas testé).


                                import Tkinter as tk
                                from random import randint
                                
                                class Block:
                                    def __init__(self, pos, item):
                                        self.pos = pos
                                        self.item = item
                                        
                                    def __str__(self):
                                        return str(self.pos)
                                        
                                
                                class Snake(tk.Tk):
                                    def __init__(self, canLen=(20, 20), blockSize=10, startSize=5, speed=200):
                                        tk.Tk.__init__(self)
                                        self.canLen = canLen
                                        self.blockSize = blockSize #la taille des blocks
                                        self.startSize = startSize #la taille du serpent au depard
                                        self.speed = speed #la vitesse en ms
                                        self.title("Serpent")
                                        self.can = tk.Canvas(self, bg='dark grey', width=canLen[0]*blockSize, height=canLen[1]*blockSize)
                                        self.can.pack(padx=5, pady=5)
                                        tk.Button(self, text="start", command=self.start).pack()
                                        self.bind("<KeyPress>", self.onKeyPress)
                                        
                                        
                                    def start(self):
                                        #supprime tous les items
                                        for item in self.can.find_all():
                                            self.can.delete(item)
                                        #pour stocker les coordonnees des blocks du serpend
                                        self.snakeData = []
                                        #la direction du serpent
                                        self.sens = "Right"
                                        self.createSnake()
                                        self.setApple()
                                        self.loop()
                                        
                                    
                                    def createSnake(self):
                                        #cree le serpent de depart au centre et de taille self.startSize
                                        pos = [self.canLen[0]/2 - self.startSize, self.canLen[1]/2]
                                        self.headPos = pos
                                        for i in range(self.startSize):
                                            blockItem = self.drawBlock(pos)
                                            self.snakeData.append(Block(pos, blockItem))
                                            pos = pos[0]+1, pos[1]
                                    
                                    
                                    def setApple(self):
                                        #dessine la pomme et stock sa position et son item dans self.applePos et self.appleItem
                                        pos = randint(0, self.canLen[0]-1), randint(0, self.canLen[1]-1)
                                        #si la position de la n'est pas dans le serpent
                                        if self.blockIsFree(pos):
                                            x1 = pos[0]*self.blockSize
                                            y1 = pos[1]*self.blockSize
                                            x2 = x1 + self.blockSize
                                            y2 = y1 + self.blockSize
                                            self.applePos = pos
                                            self.appleItem = self.can.create_oval(x1, y1, x2, y2, fill='red')
                                        #sinon on reessaye
                                        else:
                                            self.setApple()
                                    
                                    
                                    def drawBlock(self, pos):
                                        #dessine un block a la position donnee
                                        x1 = pos[0]*self.blockSize
                                        y1 = pos[1]*self.blockSize
                                        x2 = x1 + self.blockSize
                                        y2 = y1 + self.blockSize
                                        return self.can.create_rectangle(x1, y1, x2, y2, fill='black', outline="grey")
                                    
                                    
                                    def loop(self):
                                        #la boucle appele recursivement tous les "self.speed" ms
                                        #recupere la position du nouveau block en fonction de la direction
                                        posToAdd = {"Left": (-1, 0), "Right": (1, 0), "Up": (0, -1), "Down": (0, 1)}[self.sens]
                                        newBlockPos = self.snakeData[-1].pos[0]+posToAdd[0], self.snakeData[-1].pos[1]+posToAdd[1]
                                        #Si le serpent se mort la queue ou sort du caneva
                                        if self.isCollision(newBlockPos):
                                            #on arrete la boucle
                                            return
                                        #si le serpend mange la pomme
                                        if newBlockPos == self.applePos:
                                            #detruit la pomme et en cree une nouvelle
                                            self.can.delete(self.appleItem)
                                            self.setApple()
                                        #sinon on enleve le block situe au boud de la queue
                                        else:
                                            self.can.delete(self.snakeData[0].item)
                                            del self.snakeData[0]
                                        #cree et affiche le nouveau block
                                        newItem = self.drawBlock(newBlockPos)
                                        #stock le nouvel item et la nouvelle position
                                        self.snakeData.append(Block(newBlockPos, newItem))
                                        
                                        #c'est reparti apres self.speed ms
                                        self.after(self.speed, self.loop)
                                        
                                    
                                    def blockIsFree(self, pos):
                                        #pour savoir si la position est libre
                                        for data in self.snakeData:
                                            if data.pos == pos:
                                                return False
                                        return True
                                    
                                    
                                    def isCollision(self, pos):
                                        #pour savoir si le serpent se mort la queue ou sort du canevas
                                        if not (-1 < pos[0] < self.canLen[0]) or not (-1 < pos[1] < self.canLen[1]) or not self.blockIsFree(pos):
                                            return True
                                            
                                        return False
                                  
                                    
                                    def onKeyPress(self, e):
                                        #change le sens en fonction de la touche pressee
                                        if e.keysym in ("Left", "Right", "Up", "Down"):
                                            self.sens = e.keysym
                                            
                                
                                app = Snake()
                                app.mainloop()
                                

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  4 septembre 2010 à 12:40:52

                                  Merci pour cette approche poo j'en profite aussi pour y jetter un oeil !
                                  Je suis moi aussi sur le livre de swinnen et a peu près au meme point, c'est vrais que la poo est abordée 2 chapitres plus loin donc j'aurais fait cet exercice exactement de la meme manière !
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    4 septembre 2010 à 20:56:03

                                    J'ai testé ton code, il est vraiment très bien fait!
                                    Par contre, on peut faire planter le programme en appuyant
                                    dans la direction opposée du serpent (en arrière si il va en avant)
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      4 septembre 2010 à 21:23:47

                                      En faite le programme ne plante pas, mais considère que tu as perdu lorsque tu fais demi-tour.
                                      J'ai arrangé ça en utilisant un dictionnaire self.dictOpposite.
                                      J'ai également changé la gestion des évènements, en utilisant une queue. Auparavant seul la dernière touche enfoncé était pris en compte lorsque l'on appuyait sur 2 touches rapidement. Ce qui empêchait de pouvoir faire des 1/2 tours rapides, très utile dans ce genre de jeu.


                                      import Tkinter as tk
                                      from random import randint
                                      
                                      class Block:
                                          def __init__(self, pos, item):
                                              self.pos = pos
                                              self.item = item
                                              
                                      
                                      class Snake(tk.Tk):
                                          def __init__(self, canLen=(20, 20), blockSize=10, startSize=5, speed=200):
                                              tk.Tk.__init__(self)
                                              self.canLen = canLen
                                              self.blockSize = blockSize #la taille des blocks
                                              self.startSize = startSize #la taille du serpent au depard
                                              self.speed = speed #la vitesse en ms
                                              self.dictOpposite = {"Left": "Right", "Right": "Left", "Up": "Down", "Down": "Up"}
                                              self.title("Serpent")
                                              self.can = tk.Canvas(self, bg='dark grey', width=canLen[0]*blockSize, height=canLen[1]*blockSize)
                                              self.can.pack(padx=5, pady=5)
                                              tk.Button(self, text="start", command=self.start).pack()
                                              self.bind("<KeyPress>", self.onKeyPress)
                                              
                                              
                                          def start(self):
                                              #supprime tous les items
                                              for item in self.can.find_all():
                                                  self.can.delete(item)
                                              #pour stocker les coordonnees des blocks du serpend
                                              self.snakeData = []
                                              #la direction du serpent
                                              self.eventQueue = []
                                              self.sens = "Right"
                                              self.createSnake()
                                              self.setApple()
                                              self.loop()
                                              
                                          
                                          def createSnake(self):
                                              #cree le serpent de depart au centre et de taille self.startSize
                                              pos = [self.canLen[0]/2 - self.startSize, self.canLen[1]/2]
                                              self.headPos = pos
                                              for i in range(self.startSize):
                                                  blockItem = self.drawBlock(pos)
                                                  self.snakeData.append(Block(pos, blockItem))
                                                  pos = pos[0]+1, pos[1]
                                          
                                          
                                          def setApple(self):
                                              #dessine la pomme et stock sa position et son item dans self.applePos et self.appleItem
                                              pos = randint(0, self.canLen[0]-1), randint(0, self.canLen[1]-1)
                                              #si la position de la n'est pas dans le serpent
                                              if self.blockIsFree(pos):
                                                  x1 = pos[0]*self.blockSize
                                                  y1 = pos[1]*self.blockSize
                                                  x2 = x1 + self.blockSize
                                                  y2 = y1 + self.blockSize
                                                  self.applePos = pos
                                                  self.appleItem = self.can.create_oval(x1, y1, x2, y2, fill='red')
                                              #sinon on reessaye
                                              else:
                                                  self.setApple()
                                          
                                          
                                          def drawBlock(self, pos):
                                              #dessine un block a la position donnee
                                              x1 = pos[0]*self.blockSize
                                              y1 = pos[1]*self.blockSize
                                              x2 = x1 + self.blockSize
                                              y2 = y1 + self.blockSize
                                              return self.can.create_rectangle(x1, y1, x2, y2, fill='black', outline="grey")
                                          
                                          
                                          def loop(self):
                                              #la boucle appele recursivement tous les "self.speed" ms
                                              #recupere la position du nouveau block en fonction de la direction
                                              if self.eventQueue:
                                                  newSens = self.eventQueue[0]
                                                  if newSens != self.dictOpposite[self.sens]:
                                                      self.sens = self.eventQueue[0]
                                                  del self.eventQueue[0]
                                              posToAdd = {"Left": (-1, 0), "Right": (1, 0), "Up": (0, -1), "Down": (0, 1)}[self.sens]
                                              newBlockPos = self.snakeData[-1].pos[0]+posToAdd[0], self.snakeData[-1].pos[1]+posToAdd[1]
                                              #Si le serpent se mort la queue ou sort du caneva
                                              if self.isCollision(newBlockPos):
                                                  #on arrete la boucle
                                                  return
                                              #si le serpend mange la pomme
                                              if newBlockPos == self.applePos:
                                                  #detruit la pomme et en cree une nouvelle
                                                  self.can.delete(self.appleItem)
                                                  self.setApple()
                                              #sinon on enleve le block situe au boud de la queue
                                              else:
                                                  self.can.delete(self.snakeData[0].item)
                                                  del self.snakeData[0]
                                              #cree et affiche le nouveau block
                                              newItem = self.drawBlock(newBlockPos)
                                              #stock le nouvel item et la nouvelle position
                                              self.snakeData.append(Block(newBlockPos, newItem))
                                              
                                              #c'est reparti apres self.speed ms
                                              self.after(self.speed, self.loop)
                                              
                                          
                                          def blockIsFree(self, pos):
                                              #pour savoir si la position est libre
                                              for data in self.snakeData:
                                                  if data.pos == pos:
                                                      return False
                                              return True
                                          
                                          
                                          def isCollision(self, pos):
                                              #pour savoir si le serpent se mort la queue ou sort du canevas
                                              if not (-1 < pos[0] < self.canLen[0]) or not (-1 < pos[1] < self.canLen[1]) or not self.blockIsFree(pos):
                                                  return True
                                                  
                                              return False
                                        
                                          
                                          def onKeyPress(self, e):
                                              #change le sens en fonction de la touche pressee
                                              if e.keysym in ("Left", "Right", "Up", "Down"):
                                                  self.eventQueue.append(e.keysym)
                                                  
                                      
                                      app = Snake()
                                      app.mainloop()
                                      

                                      • Partager sur Facebook
                                      • Partager sur Twitter

                                      Le jeu du serpent.

                                      × 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