This commit is contained in:
Joachim Rey 2025-04-20 14:48:34 +02:00
parent 866a04ef80
commit c3cac03103
3 changed files with 452 additions and 0 deletions

BIN
data/fond.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
data/logo.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

452
main.py Executable file
View file

@ -0,0 +1,452 @@
import tkinter as tk
from tkinter import ttk
import tkinter.messagebox
from random import randint
class Snake:
"""
cree un serpent
Entree : int
Sortie : None
"""
def __init__(self, v, s, cs):
"""
Parametre le serpent
Entree : self, int
Sortie : None
"""
self.__cells_to_wait = 0
self.__velocity = v
self.__cells_size = cs
self.__direction = "Down"
self.__snake = [
canvas.create_rectangle(
245 + i,
150,
245 + i + cs,
150 + cs,
width=2,
outline="#081820",
fill="#E0F8D0",
)
for i in range(0, s * v, v)
]
canvas.itemconfigure(
self.__snake[0], fill="#081820"
) # change la couleur de la tete
def __getitem__(self, item):
"""
renvoit certaines informations sur la liste __snake
Entree : self, int
Sortie : list, int, class, None
"""
if item == 0:
return canvas.coords(self.__snake[0])
if item == 1:
return len(self.__snake)
if item == 3:
return self.__snake[0]
if item == 4:
return self.__snake
if item == 5:
return self.__snake[-1]
return None
def diy(self, x, color):
"""
change la couleur du serpent
Entree : self, int, str
Sortie : None
"""
if x >= 1:
canvas.itemconfig(self.__snake[x], fill=color)
canvas.after(50, lambda: self.diy(x - 1, color)) # prochaine cellule
return None
def move(self, color):
"""
fait avancer le serpent et informe si le serpent sort du cadre
Entree : self
Sortie : bool
"""
# for i in range(len(self.__snake) - 1, 0, -1): # bouge le corp du serpent
# canvas.move(self.__snake[i], canvas.coords(self.__snake[i - 1])[0] - canvas.coords(self.__snake[i])[0],
# canvas.coords(self.__snake[i - 1])[1] - canvas.coords(self.__snake[i])[1])
if self.__cells_to_wait <= 0:
canvas.delete(self.__snake.pop(-1))
else:
self.__cells_to_wait -= 1
# bouge la tête du serpent
head_coo = canvas.coords(self.__snake[0])
canvas.itemconfig(self.__snake[0], fill="#E0F8D0")
if self.__direction == "Up":
# canvas.move(self.__snake[0], 0, -self.__velocity)
self.__snake = [
canvas.create_rectangle(
head_coo[0],
head_coo[1] - self.__velocity,
head_coo[2],
head_coo[3] - self.__velocity,
width=2,
outline=color,
fill="#081820",
)
] + self.__snake
elif self.__direction == "Down":
# canvas.move(self.__snake[0], 0, self.__velocity)
self.__snake = [
canvas.create_rectangle(
head_coo[0],
head_coo[1] + self.__velocity,
head_coo[2],
head_coo[3] + self.__velocity,
width=2,
outline=color,
fill="#081820",
)
] + self.__snake
elif self.__direction == "Left":
# canvas.move(self.__snake[0], -self.__velocity, 0)
self.__snake = [
canvas.create_rectangle(
head_coo[0] - self.__velocity,
head_coo[1],
head_coo[2] - self.__velocity,
head_coo[3],
width=2,
outline=color,
fill="#081820",
)
] + self.__snake
elif self.__direction == "Right":
# canvas.move(self.__snake[0], self.__velocity, 0)
self.__snake = [
canvas.create_rectangle(
head_coo[0] + self.__velocity,
head_coo[1],
head_coo[2] + self.__velocity,
head_coo[3],
width=2,
outline=color,
fill="#081820",
)
] + self.__snake
return None
def change_dir(self, event):
"""
change la direction de la tête et empeche le retour arriere
Entree : self, event
Sortie : None
"""
head = canvas.coords(self[3])
cells = self.__snake
if event.keysym == "Up" and cells[1] in canvas.find_overlapping(
head[0], head[1] - self.__velocity, head[2], head[3] - self.__velocity
):
return None
if event.keysym == "Down" and cells[1] in canvas.find_overlapping(
head[0], head[1] + self.__velocity, head[2], head[3] + self.__velocity
):
return None
if event.keysym == "Left" and cells[1] in canvas.find_overlapping(
head[0] - self.__velocity, head[1], head[2] - self.__velocity, head[3]
):
return None
if event.keysym == "Right" and cells[1] in canvas.find_overlapping(
head[0] + self.__velocity, head[1], head[2] + self.__velocity, head[3]
):
return None
self.__direction = event.keysym # sinon, on applique le changement de direction
return None
def add_cells(self, x):
"""
ajoute x cellules au serpent
Entree : self, int
Sortie : None
"""
# for i in range(x):
# self.__snake.append(canvas.create_rectangle(canvas.coords(self.__snake[-1])[0],
# canvas.coords(self.__snake[-1])[1],
# canvas.coords(self.__snake[-1])[2],
# canvas.coords(self.__snake[-1])[3],
# width=2, outline='#081820', fill="#E0F8D0"))
self.__cells_to_wait = x
return None
def self_eater(self, pomme):
"""
verifie que le serpent ne rentre pas en contact avec lui même
Entree : self, instance de apple
Sortie : bool
"""
c_s = canvas.coords(self[3])
tup = canvas.find_overlapping(c_s[0], c_s[1], c_s[2], c_s[3])
if len(tup) > 2:
if pomme[3] in tup:
return False
return True
return False
class Apple:
"""
cree une pomme aux coordonnée x, y et lui donne un type
"""
def __init__(self, s):
"""
parametre la class
Entree : self, int
Sortie : None
"""
if randint(1, 10) == 10:
self.__color = "yellow"
else:
self.__color = "red"
y = randint(20, 450)
x = randint(20, 450)
while len(canvas.find_overlapping(x, y, x + 10, y + 10)) > 1:
y = randint(20, 450)
x = randint(20, 450)
self.__apple = canvas.create_oval(
x, y, x + s, y + s, fill=self.__color, width=2, outline="#081820"
)
def __getitem__(self, item):
"""
revoit des informations sur l'instance
Entree : self, int
Sortie : list, instance, str
"""
if item == 0:
return canvas.coords(self.__apple)
if item == 1:
return self.__color
if item == 3:
return self.__apple
return None
def delete_a(self):
"""
suprime la pomme
Entree : self
Sortie : None
"""
canvas.delete(self.__apple)
return None
def info():
"""
affiche une boite d'information
Entree : None
Sortie : None
"""
tkinter.messagebox.showinfo(
title=None,
message="Blockade, créé par Gremlin en 1976, est le premier jeu de type snake connu. "
"Rapidement aprés sa création, il est devenu un succés sur les bornes "
"d'arcade. Les premières"
"apparitions du terme 'snake' remonte plutôt à 1982 avec des clones tels que "
"'Snake Byte'.\n\nLe clone ci-présent a été fait par Joachim Rey.",
)
return None
def main():
"""
gere le jeu
Entree : None
Sortie : None
"""
def start(diff):
"""
commence le jeu
Entree : int
Sortie : None
"""
# reset le canva
canvas.delete("all")
canvas.create_image(0, 0, image=fond, anchor="nw")
canvas.create_window(260, 565, window=label)
canvas.create_rectangle(20, 20, 520, 520, outline="red")
# cree les parametre du jeu
if diff == 1 or diff == 0:
serpent = Snake(6, 6, 5)
diff = "facile"
elif diff == 2:
serpent = Snake(11, 6, 10)
diff = "normal"
else:
serpent = Snake(21, 6, 20)
diff = "HARDCORE"
pomme = Apple(10)
score = 0
# attache les touches aux actions
root.bind("<Up>", serpent.change_dir)
root.bind("<Down>", serpent.change_dir)
root.bind("<Right>", serpent.change_dir)
root.bind("<Left>", serpent.change_dir)
label.config(text=f"score: {score} Taille: {serpent[1]}")
# lance le jeu
game(serpent, pomme, score, diff)
return None
def game(serpent, pomme, score, diff):
"""
gere les deplacement du serpent, l'apparition de la pomme et la fin du jeu
Entree : instance de serpent, de pomme, int
Sortie : None
"""
c_p = canvas.coords(pomme[3])
h_color = "#081820"
if serpent[3] in canvas.find_overlapping(c_p[0], c_p[1], c_p[2], c_p[3]):
if pomme[1] == "red":
score += 1
serpent.add_cells(serpent[1] * 20 // 100)
h_color = "red"
else:
score += 5
serpent.add_cells(serpent[1] * 50 // 100)
h_color = "yellow"
pomme.delete_a()
pomme = Apple(10)
label.config(text=f"score: {score} Taille: {serpent[1]}")
if serpent.self_eater(pomme):
serpent.diy(serpent[1] - 1, "red")
rep = tkinter.messagebox.askretrycancel(
title=None, message="Oups, vous êtes devenu de la purée de serpent."
)
with open("data/save.txt", "r") as file:
save = file.read()
if save.split(";")[0] == "" or int(save.split(";")[0]) < score:
with open("data/save.txt", "w") as file:
file.write(f"{str(score)};{diff}")
if rep:
main()
return None
else:
root.destroy()
return None
else:
serpent.move(h_color)
canvas.after(60, lambda: game(serpent, pomme, score, diff))
return None
def diff_change(*args): # scale met par defaut un parametre
"""
change le texte de diff_affi
Entree : event
Sortie : None
"""
if round(diff.get()) == 1 or round(diff.get()) == 0:
diff_affi.configure(text="Difficulté: Facile", foreground="green")
elif round(diff.get()) == 2:
diff_affi.configure(text="Difficulté: Normal", foreground="black")
else:
diff_affi.configure(text="Difficulté: HARDCORE", foreground="red")
return None
# reset la canva
canvas.delete("test")
# tente de recuperer l'ancien meilleur score
try:
with open("data/save.txt", "r") as file:
save_s = file.read()
text_score = (
"Meilleur score:\n"
+ f"{save_s.split(';')[0]} en difficulté {save_s.split(';')[1]}"
)
except FileNotFoundError:
with open("data/save.txt", "w") as file:
file.write("0;None")
text_score = "Meilleur score:\nVous n'avez pas de scores pour le moment\n lancez une partie :) !"
# configure les boutons
best_score = ttk.Label(
canvas,
text=text_score,
font=("Helvetica", 14),
background="#E0F8D0",
justify="center",
)
label = ttk.Label(
root,
text="Bienvenu sur Blockade Py !",
font=("Helvetica", 14),
background="#E0F8D0",
)
diff = tk.DoubleVar()
diff_selec = ttk.Scale(
canvas, from_=1, to=3, orient="horizontal", command=diff_change, variable=diff
)
start_button = ttk.Button(
canvas,
text="Commencer",
command=lambda: start(round(diff.get())),
style="my.TButton",
)
info_button = ttk.Button(
canvas, text="?", command=info, style="info.TButton", width=3
)
diff_affi = ttk.Label(
root,
text="Difficulté: Facile",
font=("Helvetica", 14),
background="#E0F8D0",
foreground="green",
)
# affiche les widgets
canvas.create_window(270, 70, window=best_score)
canvas.create_window(270, 565, window=label)
canvas.create_window(499, 563, window=info_button)
canvas.create_window(270, 220, window=diff_affi)
canvas.create_window(270, 250, window=diff_selec)
canvas.create_window(270, 300, window=start_button)
canvas.create_image(0, 0, image=fond, anchor="nw")
return None
if __name__ == "__main__":
# création de la fenetre
root = tk.Tk()
root.title("Snack")
root.iconphoto(False, tk.PhotoImage(file="data/logo.png"))
root.resizable(False, False)
# definition du canva
fond = tk.PhotoImage(file="data/fond.png")
canvas = tk.Canvas(root, width=540, height=600, bg="black")
canvas.pack(fill="both", expand=True)
# style des boutons (ttk)
style = ttk.Style(root)
style.theme_use("clam")
style.configure("my.TButton", bordercolor="#081820", bg="#e0f8d0")
style.configure("info.Tbutton", borderwidth=0, bordercolor="#081820", bg="#e0f8d0")
# demarre le jeu
main()
# boucle de la fenetre
root.mainloop()