Search code examples
pythonclasspygamecollision

PYGAME : How to collide 2 groups of sprites of 2 classes and "AttributeError: type object 'Player' has no attribute 'rect'"


I would like to collide cible and projectile, when they collide, they disapeared.To know if collision is detected i put a print. If you know the command to make the two collided ojbects disapeared it'd be cool :)

There is also an error :"AttributeError: type object 'Player' has no attribute 'rect'"

Here is my code :

#                     --- Import des bibliothèques utilisées (dont pygame) ---
import pygame
from pygame import*
from pygame.locals import *
pygame.init()
from random import *


#                                      --- Classe du jeu ---

class Jeux:

    def __init__(self):
        # generer notre joueur
        self.all_players = pygame.sprite.Group()
        self.player = Player()
        self.all_players.add(self.player)
        # groupe de cible
        self.all_cibles = pygame.sprite.Group()
        self.all_projectiles = pygame.sprite.Group()
        self.pressed = {}

        collisions = pygame.sprite.spritecollide(Cible, Projectile, False)
        if collisions:
            print('collision')

#                                     --- Classe du joueur ---

class Player(pygame.sprite.Sprite):

    def __init__(self):
        super().__init__()
        self.attack = 10
        self.velocity = 7
        """self.all_players = pygame.sprite.Group()
        self.all_projectiles = pygame.sprite.Group()"""
        self.all_cibles = pygame.sprite.Group()
        self.image = pygame.image.load("F:/ISN/game/ressource/vaisseau1.png")
        self.rect = self.image.get_rect()
        self.rect.x = 0
        self.rect.y = 600

    def launch_projectile(self):
        self.all_projectiles.add(Projectile(self))

    def launch_cible(self):
        self.all_cibles.add(Cible(self))

# fonction pour aller a droite
    def move_right(self):
        self.rect.x += self.velocity

# fonction pour aller a gauche
    def move_left(self):
        self.rect.x -= self.velocity


#                                 --- Classe du projectile ---

class Projectile(pygame.sprite.Sprite):
    def __init__(self, player, game):
        super().__init__()
        self.velocity = 7
        self.player = player
        self.projectile = projectile
        self.image = pygame.image.load("F:/ISN/game/ressource/projectile-png-2.png")
        self.image = pygame.transform.scale(self.image, (10, 20))
        self.rect = self.image.get_rect()
        self.all_projectiles.add(self.projectile)
        self.rect.x = player.rect.x + 59
        self.rect.y = player.rect.y

    # fonction servant à détruire le projectile quand il est hors de la fenêtre
    def remove_projectile(self):
        self.player.all_projectiles.remove(self)

    def move(self):
        self.rect.y -= self.velocity

    # vérifier si notre projectile n'est plus présent sur l'écran
        if self.rect.y < 0:
            # supprimer le projectile
            self.remove_projectile()


#                                 --- Classe de la cible ---

class Cible(pygame.sprite.Sprite):
    def __init__(self, game, player):
        super().__init__()
        self.game = game
        self.cible = cible
        self.image = pygame.image.load("F:/ISN/game/ressource/catalan.png")
        self.image = pygame.transform.scale(self.image, (40, 40))
        self.rect = self.image.get_rect()
        self.all_cibles.add(self.cible)
        self.rect.x = randint(50, 1000)
        self.rect.y = randint(0, 400)

    def remove_cible(self):
        self.player.all_cibles.remove(self)

    if pygame.sprite.spritecollide(Player, Projectile, False):
        print('Collide')



#                      --- Gestion des touches et de la fenêtre de jeu ---

clock = pygame.time.Clock()

# generer la fenetre du jeu
pygame.display.set_caption("SPACE INVADERS V2")
screen = pygame.display.set_mode((1080, 720))

# importer charger l'arriere plan
background = pygame.image.load("F:/ISN/game/ressource/BACKGROUND.jpg")

# charger notre jeu
game = Jeux()


running = True
# boucle tant que cette condition est vrai
while running:

    # appliquer l'arriere plan de notre jeu
    screen.blit(background, (0, 0))

    # appliquer l'image de notre joueur sur la fenetre de jeu
    screen.blit(game.player.image, game.player.rect)

    # afficher la cible 
    game.player.all_cibles.draw(screen)

    # recuperer les projectiles du joueur
    for projectile in game.player.all_projectiles:
        projectile.move()

    # appliquer l'ensemble des images de mon groupe de projectiles
    game.player.all_projectiles.draw(screen)

    # mouvements du joueur
    if game.pressed.get(pygame.K_RIGHT) and game.player.rect.x + game.player.rect.width < screen.get_width():
        game.player.move_right()
    elif game.pressed.get(pygame.K_LEFT) and game.player.rect.x > 0:
        game.player.move_left()

    # mettre a jour l'ecran
    pygame.display.flip()

    # si le joueur ferme cette fenetre
    for event in pygame.event.get():
        # que l'evenement est fermeture de fenetre
        if event.type == pygame.QUIT:
            running = False
            pygame.quit()
            print("Fermeture du jeu")
        # detecter si un joueur lache une touche du clavier
        elif event.type == pygame.KEYDOWN:
           game.pressed[event.key] = True
           if event.key == pygame.K_SPACE:
               game.player.launch_projectile()
           elif event.key == pygame.K_DOWN:
               game.player.launch_cible()
        elif event.type == pygame.KEYUP:
            game.pressed[event.key] = False

I don't know how to do, please help me


Solution

  • The 1st argument to pygame.sprite.spritecollide() has to be an instance of pygame.sprite.Sprite and the 2nd argument has to be an instance of pygame.sprite.Group.
    Thus pygame.sprite.spritecollide(Cible, Projectile, False) does not make any sense because Cible and Projectileare classes.

    self.all_cibles and self.all_projectiles are instances of pygame.sprite.Group. A collision of Groups can be evaluated by pygame.sprite.groupcollide(). e.g:

    collisions = pygame.sprite.groupcollide(
        self.all_projectiles, self.all_cibles, False, False)
    

    By passing True to the dokill1 respectively dokill2 argument, the Sprites can be removed from all Groups and thus destroyed.
    For instance, pass False to dokill1 and True to dokill2, thus projectiles will destroy cibles:

    collisions = pygame.sprite.groupcollide(
        self.all_projectiles, self.all_cibles, False, True)      
    

    If you want to do a collision test, then you have to do it in the main application loop. For instance:

    running = True
    # boucle tant que cette condition est vrai
    while running:
        # [...]
    
        collisions = pygame.sprite.groupcollide(game.all_projectiles, game.all_cibles, False, True)
        if collisions:
            print('collision')
    
        if pygame.sprite.spritecollide(game.player, game.all_projectiles, False):
            print('Collide')
    

    The complete code may look as follows:

    #                     --- Import des bibliothèques utilisées (dont pygame) ---
    import pygame
    from pygame import*
    from pygame.locals import *
    pygame.init()
    from random import *
    
    #                                      --- Classe du jeu ---
    class Jeux:
    
        def __init__(self):
            # generer notre joueur
            self.all_players = pygame.sprite.Group()
            self.player = Player()
            self.all_players.add(self.player)
            # groupe de cible
            self.all_cibles = pygame.sprite.Group()
            self.all_projectiles = pygame.sprite.Group()
            self.pressed = {}
    
    #                                     --- Classe du joueur ---
    class Player(pygame.sprite.Sprite):
    
        def __init__(self):
            super().__init__()
            self.attack = 10
            self.velocity = 7
            """self.all_players = pygame.sprite.Group()
            self.all_projectiles = pygame.sprite.Group()"""
            self.image = pygame.image.load("F:/ISN/game/ressource/vaisseau1.png")
            self.rect = self.image.get_rect()
            self.rect.x = 0
            self.rect.y = 600
    
        def launch_projectile(self):
            game.all_projectiles.add(Projectile(self, game))
    
        def launch_cible(self):
            game.all_cibles.add(Cible(self, game))
    
    # fonction pour aller a droite
        def move_right(self):
            self.rect.x += self.velocity
    
    # fonction pour aller a gauche
        def move_left(self):
            self.rect.x -= self.velocity
    
    
    #                                 --- Classe du projectile ---
    class Projectile(pygame.sprite.Sprite):
        def __init__(self, player, game):
            super().__init__()
            self.velocity = 7
            self.game = game
            self.player = player
            self.image = pygame.image.load("F:/ISN/game/ressource/projectile-png-2.png")
            self.image = pygame.transform.scale(self.image, (10, 20))
            self.rect = self.image.get_rect()
            self.game.all_projectiles.add(self)
            self.rect.x = player.rect.x + 59
            self.rect.y = player.rect.y
    
        # fonction servant à détruire le projectile quand il est hors de la fenêtre
        def remove_projectile(self):
            self.game.all_projectiles.remove(self)
    
        def move(self):
            self.rect.y -= self.velocity
    
        # vérifier si notre projectile n'est plus présent sur l'écran
            if self.rect.y < 0:
                # supprimer le projectile
                self.remove_projectile()
    
    
    #                                 --- Classe de la cible ---
    class Cible(pygame.sprite.Sprite):
        def __init__(self, player, game):
            super().__init__()
            self.game = game
            self.image = pygame.image.load("F:/ISN/game/ressource/catalan.png")
            self.image = pygame.transform.scale(self.image, (40, 40))
            self.rect = self.image.get_rect()
            self.game.all_cibles.add(self)
            self.rect.x = randint(50, 1000)
            self.rect.y = randint(0, 400)
    
        def remove_cible(self):
            self.game.all_cibles.remove(self)
    
    
    #                      --- Gestion des touches et de la fenêtre de jeu ---
    clock = pygame.time.Clock()
    
    # generer la fenetre du jeu
    pygame.display.set_caption("SPACE INVADERS V2")
    screen = pygame.display.set_mode((1080, 720))
    
    # importer charger l'arriere plan
    background = pygame.image.load("F:/ISN/game/ressource/BACKGROUND.jpg")
    
    # charger notre jeu
    game = Jeux()
    
    
    running = True
    # boucle tant que cette condition est vrai
    while running:
    
        # appliquer l'arriere plan de notre jeu
        screen.blit(background, (0, 0))
    
        # appliquer l'image de notre joueur sur la fenetre de jeu
        screen.blit(game.player.image, game.player.rect)
    
        # afficher la cible 
        game.all_cibles.draw(screen)
    
        # recuperer les projectiles du joueur
        for projectile in game.all_projectiles:
            projectile.move()
    
        # appliquer l'ensemble des images de mon groupe de projectiles
        game.all_projectiles.draw(screen)
    
        # mouvements du joueur
        if game.pressed.get(pygame.K_RIGHT) and game.player.rect.x + game.player.rect.width < screen.get_width():
            game.player.move_right()
        elif game.pressed.get(pygame.K_LEFT) and game.player.rect.x > 0:
            game.player.move_left()
    
        # mettre a jour l'ecran
        pygame.display.flip()
    
        # si le joueur ferme cette fenetre
        for event in pygame.event.get():
            # que l'evenement est fermeture de fenetre
            if event.type == pygame.QUIT:
                running = False
                pygame.quit()
                print("Fermeture du jeu")
            # detecter si un joueur lache une touche du clavier
            elif event.type == pygame.KEYDOWN:
               game.pressed[event.key] = True
               if event.key == pygame.K_SPACE:
                   game.player.launch_projectile()
               elif event.key == pygame.K_DOWN:
                   game.player.launch_cible()
            elif event.type == pygame.KEYUP:
                game.pressed[event.key] = False
    
        collisions = pygame.sprite.groupcollide(game.all_projectiles, game.all_cibles, False, True)
        if collisions:
            print('collision')
    
        if pygame.sprite.spritecollide(game.player, game.all_projectiles, False):
            print('Collide')