Jeux tkinter

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. 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.

    1. #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

      1. 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.