Jeux tkinter

Manubg -  
 ykl -

Bonjour,

Quelqu'un peut m'aide, je n'arrive pas a faire entre en collision mon joueur et les ennemie voila mon code 

import tkinter as tk
class Joueur:
    
    def __init__(self, canvas, rayon= 20, posx=100, posy=100, image_path="image22.png"):
        self.canvas = canvas
        self.rayon = rayon
        self.x = posx
        self.y = posy
        self.speedx = 1
        self.speedy = 0
        self.image = tk.PhotoImage(file=image_path)
        self.image = self.image.subsample(3, 3)
        self.id = self.canvas.create_image(posx, posy, image=self.image)
        self.lives = 100
        self.life_bar_width = 100
        self.life_bar_height = 10
        self.life_bar_id = None
        self.create_life_bar()  # Crée la barre de vie
       
       
    def move(self):
        self.canvas.move(self.id, self.speedx, self.speedy)
        # update position
        x, y = self.canvas.coords(self.id)
        self.x, self.y = x, y
        self.check_collisions()
        
        
    def create_life_bar(self):
        x1 = 10  # Position x du coin supérieur gauche de la barre de vie
        y1 = 10  # Position y du coin supérieur gauche de la barre de vie
        x2 = x1 + self.life_bar_width  # Position x du coin inférieur droit de la barre de vie
        y2 = y1 + self.life_bar_height  # Position y du coin inférieur droit de la barre de vie
        self.life_bar_id = self.canvas.create_rectangle(x1, y1, x2, y2, fill='red')
        
   
    
    def update_life_bar(self):
        x1, y1, x2, y2 = self.canvas.coords(self.life_bar_id)
        new_width = (self.lives / 100) * self.life_bar_width
        self.canvas.coords(self.life_bar_id, x1, y1, x1 + new_width, y2)

    def check_collisions(self):
        coords = self.canvas.coords(self.id)
        if len(coords) >= 4:
            collisions = self.canvas.find_overlapping(coords[0], coords[1], coords[2], coords[3])
            collisions = list(collisions)
            collisions.remove(self.id)
            if Obstacle.id in collisions:  # Vérifie la collision avec l'obstacle
                self.lives -= 1
                self.update_life_bar()  # Met à jour la barre de vie
            return collisions   
        else:
            return []

    """def check_collisions(self):
        coords = self.canvas.coords(self.id)
        # trouver les IDs des objets partageant au moins un point avec la balle
        # (attention, la balle fera partie des objets trouvés)
        collisions = self.canvas.find_overlapping(coords[0], coords[1], coords[2], coords[3])
        # transformer en liste pour exclure la balle elle-même
        collisions = list(collisions)
        collisions.remove(self.id)
        return collisions"""


class Obstacle:
    def __init__(self, canvas, width=20, posx=100, posy=100, image_path="ennemi.png"):
        self.canvas = canvas
        self.width = width
        self.x = posx
        self.y = posy
        self.speedx = -15
        self.speedy = 0
        self.image = tk.PhotoImage(file=image_path)
        self.id = self.canvas.create_image(posx, posy, image=self.image)
        
     
    
    

    def move(self):
        self.canvas.move(self.id, self.speedx, self.speedy)
        # update position
        x, y = self.canvas.coords(self.id)
        self.x, self.y = x, y


if __name__ == "__main__":
    #import tkinter as tk
    app = tk.Tk()

    ecran = tk.Frame(app)
    ecran.pack()
    app = tk.Tk()
    canvas = tk.Canvas(ecran, width=600, height=600, bg="lightgray")
    canvas.pack()
   
    

    ennemi= Joueur(canvas, posx=200, posy=150)
    ennemi.move()
    
   
   
    app.mainloop()


Windows / Chrome 113.0.0.0

3 réponses

  1. ykl
     

    Salut.

    Où sont les collisions dans ton code ? Il n'y a qu'un item, le joueur...

    Tu utilises la bonne méthode du canvas, find_overlapping, sauf que lorsque tu fais :

    if Obstacle.id in collisions:  # Vérifie la collision avec l'obstacle


    Forcément ça ne peut pas aller, la classe Obstacle n'a pas de variable id, revoir la différence entre variable de classe et attribut d'objet.

    En sus, la collision doit être testée ailleurs que dans la classe Joueur, mais au niveau où le joueur a été instancié, car c'est là que devra se décider ce qu'il doit être fait entre les protagonistes.

    0
  2. Manubg
     
    #code de lancement
    
    import tkinter as tk
    
    from random import randint
    
    from characters import Joueur, Obstacle
    
    class App(tk.Tk):
        def __init__(self):
            tk.Tk.__init__(self)
        
            self.title("Robot Survivor")
            self.width = 1000 # largeur des écrans/fenêtres
            self.height = 800  # hauteur des écrans/fenêtres
            self.geometry("%ix%i" % (self.width, self.height))
    
            
            """
            Premier écran
            """
            
            self.frame_intro = tk.Frame(self, width=self.width, height=self.height)
            self.frame_intro.pack()
             
            # Chargement de l'image
            img_path = "accueil.png"  # Chemin relatif de l'image par rapport au script Python
            img = tk.PhotoImage(file=img_path)
            
            # Créer un widget Label pour afficher l'image
            self.label_image = tk.Label(self.frame_intro, image=img)
            self.label_image.image = img  # Garde une référence à l'image pour éviter sa suppression par le garbage collector
            self.label_image.place(relx=0.5, rely=0.5, anchor="center")
            
            
                    
            # Créer un titre et le placer dans le premier écran avec la méthode "place"
            self.titre_accueil = tk.Label(self.frame_intro, text="Robot survivor", font=("Courier", 44, "bold"))
            self.titre_accueil.place(relx=0.1, rely=0.3, anchor="w")
           
            
            # Créer deux boutons et les placer dans le premier écran avec la méthode "place"
          
    
            self.btn1 = tk.Button(self.frame_intro,text="JOUER",command=self.MenuToGame, bg="green")
            self.btn1.place(relx=0.5, rely=0.7, anchor="center")
                        
            self.btn2 = tk.Button(self.frame_intro,text="MEILLEUR SCORE",command=self.MenuToStats, bg="green")
            self.btn2.place(relx=0.5, rely=0.8, anchor="center")
            
            self.btn3 = tk.Button(self.frame_intro,text="QUITTER",command=self.destroy, bg="red")
            self.btn3.place(relx=0.5, rely=0.9, anchor ="center")
            
            
            """
            2e écran
            """
            
            # Cette fois, on crée le Frame, mais on ne l'affiche pas encore (on ne le "pack" pas encore)
            self.frame_game = tk.Frame(self, width=self.width, height=self.height)
            
           
            #creation canvas
            self.canvas = tk.Canvas(self.frame_game, width=self.width-100, height=self.height*3/4, bg="grey")
            self.canvas.place(relx=0.5, rely=0.05, anchor=tk.N)
    
            # Charger l'image d'arrière-plan
            self.background_image = tk.PhotoImage(file="background2.png")
    
            # Créer l'image d'arrière-plan dans le canvas
            self.canvas.create_image((self.width-100)/2, (self.height*3/4)/2, anchor=tk.CENTER, image=self.background_image)
            
            self.home_img = tk.PhotoImage(file='./home-page-icon.png')
            self.home_img = self.home_img.subsample(5,5) # Diminuer la taille de l'image par un facteur 5
            self.btn2 = tk.Button(self.frame_game,text="Menu",command=self.GameToMenu, image=self.home_img)
            self.btn2.place(relx=0.5, rely=0.9, anchor="center")
            
            # au lancement du jeu, l'animation n'est pas activée
            #self.animation_on = False
        
            
            
            """
           3e écran
           """
           
           
            self.frame_gameover = tk.Frame(self, width=self.width, height=self.height)
            
            # Créer de fausses gameover et les placer dans le troisème écran avec la méthode "place"
            self.text_gameover = tk.Label(self.frame_gameover, text="Game over")
            self.text_gameover.place(relx=0.5, rely=0.5, anchor="center")
    
            # Créer un bouton "menu", placé au centre de l'écran avec la méthode "place"
            self.btn4 = tk.Button(self.frame_gameover,text="Menu",command=self.GameoverToMenu, image=self.home_img)
            self.btn4.place(relx=0.5, rely=0.9, anchor="center")
        
    
        def MenuToGame(self):
            self.frame_intro.pack_forget()
            self.frame_game.pack()
            # Remplir la scène de jeu
            self.initialize_game()
            # Lancer l'animation du jeu quand on rentre dans le jeu
            self.animation_on = True
            self.animate()
    
        def MenuToStats(self):
            self.frame_intro.pack_forget()
            self.frame_stats.pack()
    
        def GameToMenu(self):
            self.frame_game.pack_forget()
            self.frame_intro.pack()
            # Arrêter l'animation quand on retourne au menu
            self.animation_on = False
            # Remettre le niveau à zéro
            self.reset_game()
    
        def GameToGameover(self):
            self.frame_game.pack_forget()
            self.frame_gameover.pack()
            # Arrêter l'animation quand on retourne au menu
            self.animation_on = False
            # Remettre le niveau à zéro
            self.reset_game()
            
        def GameoverToMenu(self):
            self.frame_gameover.pack_forget()
            self.frame_intro.pack()
    
        def StatsToMenu(self):
            self.frame_stats.pack_forget()
            self.frame_intro.pack()
    
        def animate(self):
            if self.animation_on:
                # vérifier les collisions
                collisions = self.joueur.check_collisions()
                if collisions:
                    self.GameToGameover()
                    return
    
    
                # bouger le joueur
                self.joueur.move()
                # bouger les obstacles
                for obstacle in self.obstacles:
                    obstacle.move()
    
                # si les obstacles sont sortis de l'écran à gauche, les repositionner à droite
                for obstacle in self.obstacles:
                    if obstacle.x < -10:
                        self.delete_obstacles()
                        self.create_obstacles()
                        break
    
                self.after(20, self.animate)
    
        def initialize_game(self):
            #Ajoute les personnages et les obstacles dans le canvas de jeu
            # Création du joueur (cercle)
            self.joueur = Joueur(self.canvas)
            # Création de deux obstacles (cubes) hors de l'écran selon x et
            # à des positions aléatoires selon y
            self.create_obstacles()
    
            # Création des bindings pour les contrôles
            self.bind("<KeyPress>", self.change_player_direction)
            
            
        
        
    
        def create_obstacles(self):
            self.obstacles = []
            self.obstacles.append(Obstacle(self.canvas, posx=self.width+100, posy=randint(20, self.height-70)))
            self.obstacles.append(Obstacle(self.canvas, posx=self.width+100, posy=randint(20, self.height-70)))
    
        def reset_game(self):
            #Efface les personnages et les obstacles du canvas de jeu
            self.delete_player()
            self.delete_obstacles()
    
            # Suppression des bindings pour les contrôles
            self.unbind_all("<KeyPress>")
    
        def delete_obstacles(self):
            # Effacement des objets affichés sur le canvas
            for obstacle in self.obstacles:
                self.canvas.delete(obstacle.id)
            # Suppression des variables associées
            self.obstacles = []
    
        def delete_player(self):
            # Effacement des objets affichés sur le canvas
            self.canvas.delete(self.joueur.id)
            # Suppression des variables associées
            del self.joueur
    
        def change_player_direction(self, event):
            if event.keysym == "Up":
                self.joueur.speedx = 0
                self.joueur.speedy = -5
            elif event.keysym == "Down":
                self.joueur.speedx = 0
                self.joueur.speedy = 5
            elif event.keysym == "Right":
                self.joueur.speedx = 5
                self.joueur.speedy = 0
            elif event.keysym == "Left":
                self.joueur.speedx = -5
                self.joueur.speedy = 0
    
    if __name__ == "__main__":
        root = App()
        root.mainloop()
    
    
    #code du joueur et l'obstacle
    
    
    
    import tkinter as tk
    class Joueur:
        
        def __init__(self, canvas, rayon= 20, posx=100, posy=100, image_path="image22.png"):
            self.canvas = canvas
            self.rayon = rayon
            self.x = posx
            self.y = posy
            self.speedx = 1
            self.speedy = 0
            self.image = tk.PhotoImage(file=image_path)
            self.image = self.image.subsample(3, 3)
            self.id = self.canvas.create_image(posx, posy, image=self.image)
            self.lives = 100
            self.life_bar_width = 100
            self.life_bar_height = 10
            self.life_bar_id = None
            self.create_life_bar()  # Crée la barre de vie
            
            
        
        def move(self):
            self.canvas.move(self.id, self.speedx, self.speedy)
            # update position
            x, y = self.canvas.coords(self.id)
            self.x, self.y = x, y
            self.check_collisions()
            
            
        def create_life_bar(self):
            x1 = 10  # Position x du coin supérieur gauche de la barre de vie
            y1 = 10  # Position y du coin supérieur gauche de la barre de vie
            x2 = x1 + self.life_bar_width  # Position x du coin inférieur droit de la barre de vie
            y2 = y1 + self.life_bar_height  # Position y du coin inférieur droit de la barre de vie
            self.life_bar_id = self.canvas.create_rectangle(x1, y1, x2, y2, fill='red')
            
        
        def update_life_bar(self):
            x1, y1, x2, y2 = self.canvas.coords(self.life_bar_id)
            new_width = (self.lives / 100) * self.life_bar_width
            self.canvas.coords(self.life_bar_id, x1, y1, x1 + new_width, y2)
    
        
    
    
    
    
    
        def check_collisions(self):
            coords = self.canvas.coords(self.id)
            if len(coords) < 4:
                return
                collisions = self.canvas.find_overlapping(*self.canvas.bbox(self.id))
                collisions = list(collisions)
                collisions.remove(self.id)
    
            for obstacle_id in collisions:
                for obstacle in self.obstacles:
                    if obstacle_id == obstacle.id:
                        self.lives -= 1
                        self.update_life_bar()
    
            return collisions
    
    
    
        """def check_collisions(self):
            coords = self.canvas.coords(self.id)
            # trouver les IDs des objets partageant au moins un point avec la balle
            # (attention, la balle fera partie des objets trouvés)
            collisions = self.canvas.find_overlapping(*self.canvas.bbox(self.id))
            #(coords[0], coords[1], coords[2], coords[3])
            # transformer en liste pour exclure la balle elle-même
            collisions = list(collisions)
            collisions.remove(self.id)
            return collisions"""
    
    
    
    
    class Obstacle:
        def __init__(self, canvas, width=20, posx=100, posy=100, image_path="ennemi.png"):
            self.canvas = canvas
            self.width = width
            self.x = posx
            self.y = posy
            self.speedx = -15
            self.speedy = 0
            self.image = tk.PhotoImage(file=image_path)
            self.id = self.canvas.create_image(posx, posy, image=self.image)
            
        
        def move(self):
            self.canvas.move(self.id, self.speedx, self.speedy)
            # update position
            x, y = self.canvas.coords(self.id)
            self.x, self.y = x, y
    
    
    
    if __name__ == "__main__":
        #import tkinter as tk
        app = tk.Tk()
    
        ecran = tk.Frame(app)
        ecran.pack()
        canvas = tk.Canvas(ecran, width=600, height=600, bg="lightgray")
        canvas.pack()
       
        
    
        ennemi= Joueur(canvas, posx=200, posy=150)
        ennemi.move()
       
        
     
       
        app.mainloop()
    
    
    

    je suis debutant en programmation tu peux m'aide a  faire entre en collision mon joueur et les ennemi

    0
  3. ykl
     

    Salut.

    Comme je t'ai signalé, Obstacle.id n'existe pas, tu n'obtiens pas l'erreur car tu n'entres pas dans le test if len(coords) >= 4

    Canvas.coords de l'id d'une image retourne 2 valeurs (point central).

    Voici un exemple plus succinct détectant la collision entre ennemis et joueur (nécessite 2 images png,  joueur et ennemi).

    import random
    import tkinter as tk
    from collections import namedtuple
    
    
    class Entity:
        def __init__(self, canvas, image, x, y, **kw):
            self.canvas = canvas
            self.id = canvas.create_image(x, y, image=image)
            self._alive = True
            self._size = image.width(), image.height()
    
        alive = property(lambda self: self._alive)
        size = property(lambda self: self._size)
        width = property(lambda self: self._size[0])
        height = property(lambda self: self._size[1])
    
        def move(self, dx, dy):
            self.canvas.move(self.id, dx, dy)
    
        def destroy(self):
            self.canvas.delete(self.id)
            self._alive = False
    
        def collide_with(self, *entities_id):
            for iid in self.canvas.find_overlapping(*self.canvas.bbox(self.id)):
                if iid in entities_id:
                    return True
            return False
    
    
    class Player(Entity):
        def __init__(self, *args):
            super().__init__(*args)
    
    
    class Ennemy(Entity):
        def __init__(self, *args):
            super().__init__(*args)
    
    
    class App(tk.Tk):
        def __init__(self):
            super().__init__()
            self.images_init()
            self.player_motions = dict(Up=(0, -8), Down=(0, 8), Left=(-8, 0), Right=(8, 0))
            self.title("Robot Survivor")
            self.canvas = tk.Canvas(self, width=800, height=600, bg='lightGrey')
            self.canvas.grid()
            self.canvas.focus_set()
    
            self.player = Player(self.canvas, self.images.player, 100, 100)
            self.canvas.event_add('<<player>>', '<Up>', '<Down>', '<Left>', '<Right>')
            self.canvas.bind('<<player>>', self.player_manage)
            self.ennemies = []
            self.ennemies_manage()
    
        def player_manage(self, evt):
            self.player.move(*self.player_motions[evt.keysym])
    
        def images_init(self):
            cls = namedtuple('Images', ('player', 'ennemy'))
            self.images = cls(
                player=tk.PhotoImage(file='joueur.png'), ennemy=tk.PhotoImage(file='ennemi.png')
            )
    
        def ennemies_manage(self):
            if self.ennemies:
                for ennemy in self.ennemies:
                    if ennemy.alive:
                        ennemy.move(-5, 0)
                        if ennemy.collide_with(self.player.id):
                            ennemy.destroy()
                            # Et faire les autres actions (dégâts au joueur, points en moins, etc)
    
                # Recherche d'un ennemi vivant
                for ennemy in self.ennemies:
                    if ennemy.alive:
                        break
                else:
                    # Signifie qu'il n'y a plus d'ennemis en vie
                    # car le joueur peut en percuter 2
                    ennemy = -1
    
                if ennemy == -1 or self.canvas.coords(ennemy.id)[0] < ennemy.width / -2:
                    # Tous les ennemis seront supprimés puisqu'ils sont sur le même x
                    for ennemy in self.ennemies:
                        ennemy.destroy()
                    self.ennemies.clear()
            else:
                y = random.randrange(50, int(self.canvas['height']) - 200)
                for y in (y, y + random.randrange(50, 150)):
                    ennemy = Ennemy(self.canvas, self.images.ennemy, int(self.canvas['width']), y)
                    self.ennemies.append(ennemy)
            self.canvas.after(20, self.ennemies_manage)
    
        run = property(lambda self: self.mainloop)
    
    
    app = App()
    app.run()

    Dans ce code il est inutile de tester si le joueur entre en collision avec les obstacles car le pas de déplacement est assez petit.

    Mais on peut aussi dans player_manage tester également les collisions induites par le joueur.

    0