Jeux tkinter

Fermé
Manubg - Modifié le 18 mai 2023 à 20:39
 ykl - 20 mai 2023 à 12:12

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

A voir également:

3 réponses

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

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