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()
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.
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)
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)
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.
Désolé Josmiley, je n'avais pas vu ton message
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.
#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])
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.
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. )
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...
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.