title: group collide does not work on platform scroller with Pygame
body: <p>I following this <a href="http://programarcadegames.com/python_examples/show_file.php?file=platform_scroller.py" rel="nofollow noreferrer">tutorial</a> and I have added <code>class Opponent()</code> to <code>class Platform()</code> as shown <a href="https://stackoverflow.com/questions/30833327/adding-enemies-to-a-pygame-platformer">here</a>. Next I have been trying to add <strong>groupcollide_and_loop_for</strong> to the complete code so that the opponent is removed when hit by the bullet. I have been looking at this <a href="https://stackoverflow.com/questions/14356730/the-method-for-the-use-of-about-pygame-sprite-groupcollide">question</a> about using groupcollide within <code>class Opponent()</code> itself. I tried several ways to call <code>groupcollide</code> inside <code>def main</code> in <code>while not done</code> but I didn't get any results or any errors, it just didn't work.</p>
  
  <p>groupcollide_and_loop_for:</p>
  
  <pre><code>    collided_opponents = pygame.sprite.groupcollide(opponents, bullet_list, False, True)
      for opponent, bullets in collided_opponents.items():
          for bullet in bullets:
              score += 1  # Increment the score.
              opponent.lives -= 1  # Decrement the lives.
              pygame.display.set_caption(str(score))
  </code></pre>
  
  <h2>Deploy the groupcollide and for loop above to the code below:</h2>
  
  <pre><code>import pygame
  
  # Global constants
  bulletpicture = pygame.image.load("bullet.png") 
  # Colors
  BLACK = (0, 0, 0)
  WHITE = (255, 255, 255)
  GREEN = (0, 255, 0)
  RED = (255, 0, 0)
  BLUE = (0, 0, 255)
  
  # Screen dimensions
  SCREEN_WIDTH = 800
  SCREEN_HEIGHT = 600
  
  
  class Player(pygame.sprite.Sprite):
      """
      This class represents the bar at the bottom that the player controls.
      """
  
      # -- Methods
      def __init__(self):
          """ Constructor function """
  
          # Call the parent's constructor
          super().__init__()
  
          # Create an image of the block, and fill it with a color.
          # This could also be an image loaded from the disk.
          width = 40
          height = 60
          self.image = pygame.Surface([width, height])
          self.image.fill(RED)
  
          # Set a referance to the image rect.
          self.rect = self.image.get_rect()
  
          # Set speed vector of player
          self.change_x = 0
          self.change_y = 0
  
          # List of sprites we can bump against
          self.level = None
  
      def update(self):
          """ Move the player. """
          # Gravity
          self.calc_grav()
  
          # Move left/right
          self.rect.x += self.change_x
  
          # See if we hit anything
          block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
          for block in block_hit_list:
              # If we are moving right,
              # set our right side to the left side of the item we hit
              if self.change_x &gt; 0:
                  self.rect.right = block.rect.left
              elif self.change_x &lt; 0:
                  # Otherwise if we are moving left, do the opposite.
                  self.rect.left = block.rect.right
  
          # Move up/down
          self.rect.y += self.change_y
  
          # Check and see if we hit anything
          block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
          for block in block_hit_list:
  
              # Reset our position based on the top/bottom of the object.
              if self.change_y &gt; 0:
                  self.rect.bottom = block.rect.top
              elif self.change_y &lt; 0:
                  self.rect.top = block.rect.bottom
  
              # Stop our vertical movement
              self.change_y = 0
  
      def calc_grav(self):
          """ Calculate effect of gravity. """
          if self.change_y == 0:
              self.change_y = 1
          else:
              self.change_y += .35
  
          # See if we are on the ground.
          if self.rect.y &gt;= SCREEN_HEIGHT - self.rect.height and self.change_y &gt;= 0:
              self.change_y = 0
              self.rect.y = SCREEN_HEIGHT - self.rect.height
  
      def jump(self):
          """ Called when user hits 'jump' button. """
  
          # move down a bit and see if there is a platform below us.
          # Move down 2 pixels because it doesn't work well if we only move down 1
          # when working with a platform moving down.
          self.rect.y += 2
          platform_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
          self.rect.y -= 2
  
          # If it is ok to jump, set our speed upwards
          if len(platform_hit_list) &gt; 0 or self.rect.bottom &gt;= SCREEN_HEIGHT:
              self.change_y = -10
  
      # Player-controlled movement:
      def go_left(self):
          """ Called when the user hits the left arrow. """
          self.change_x = -6
  
      def go_right(self):
          """ Called when the user hits the right arrow. """
          self.change_x = 6
  
      def stop(self):
          """ Called when the user lets off the keyboard. """
          self.change_x = 0
  
  
  class Platform(pygame.sprite.Sprite):
      """ Platform the user can jump on """
  
      def __init__(self, width, height):
          """ Platform constructor. Assumes constructed with user passing in
              an array of 5 numbers like what's defined at the top of this code.
              """
          super().__init__()
  
          self.image = pygame.Surface([width, height])
          self.image.fill(GREEN)
  
          self.rect = self.image.get_rect()
  
  
  class Level():
      """ This is a generic super-class used to define a level.
          Create a child class for each level with level-specific
          info. """
  
      def __init__(self, player):
          """ Constructor. Pass in a handle to player. Needed for when moving
              platforms collide with the player. """
          self.platform_list = pygame.sprite.Group()
          self.enemy_list = pygame.sprite.Group()
          self.player = player
  
          # How far this world has been scrolled left/right
          self.world_shift = 0
  
      # Update everythign on this level
      def update(self):
          """ Update everything in this level."""
          self.platform_list.update()
          self.enemy_list.update()
  
      def draw(self, screen):
          """ Draw everything on this level. """
  
          # Draw the background
          screen.fill(BLUE)
  
          # Draw all the sprite lists that we have
          self.platform_list.draw(screen)
          self.enemy_list.draw(screen)
  
      def shift_world(self, shift_x):
          """ When the user moves left/right and we need to scroll
          everything: """
  
          # Keep track of the shift amount
          self.world_shift += shift_x
  
          # Go through all the sprite lists and shift
          for platform in self.platform_list:
              platform.rect.x += shift_x
  
          for enemy in self.enemy_list:
              enemy.rect.x += shift_x
  
  class Bullet(pygame.sprite.Sprite):
      """This class represents the bullet."""
  
      def __init__(self,x,y):
          super().__init__()
          self.image = bulletpicture
  
          self.image.set_colorkey(BLACK) 
          self.rect = self.image.get_rect()
          self.rect.x = x
          self.rect.y = y
      def update(self):
          """Move the bullet."""
          self.rect.y -= 5
          # Remove the bullet if it flies up off the screen
          if self.rect.y &lt; -12:
              self.kill()  # Remove the sprite from all sprite groups.
  
  
  
  class Opponent(pygame.sprite.Sprite):
  
      def __init__(self):
  
          super().__init__()
          self.image = pygame.image.load("cowboy.png") #.convert()
          self.rect = self.image.get_rect()
          self.lives = 1
          self.rect.x = 50
          self.rect.y = 280
          self.change_x = 1
          self.change_y = 0
          # List of sprites we can bump against
          self.level = None
  
          pass
      def update(self):
          if self.lives &lt;= 0:
              self.kill()  # Remove the sprite from all sprite groups.
          self.rect.x += self.change_x
          if self.rect.x &gt; 280:
             self.change_x *= -1
             self.rect.x += self.change_x
          if self.rect.x &lt; 0:
             self.change_x *= -1
             self.rect.x += self.change_x
          pass
  
  
  # Create platforms for the level
  class Level_01(Level):
      """ Definition for level 1. """
  
      def __init__(self, player):
          """ Create level 1. """
  
          # Call the parent constructor
          Level.__init__(self, player)
  
          self.level_limit = -1000
  
          # Array with width, height, x, and y of platform
          level = [[210, 70, 500, 500],
                   [210, 70, 800, 400],
                   [210, 70, 1000, 500],
                   [210, 70, 1120, 280],
                   ]
  
          # Go through the array above and add platforms
          for platform in level:
              block = Platform(platform[0], platform[1])
              block.rect.x = platform[2]
              block.rect.y = platform[3]
              block.player = self.player
              self.platform_list.add(block)
  
          for enemy in level:
              opponent = Opponent()
              opponent.rect.x = 150
              opponent.rect.y = 280
              opponent.player = self.player
              self.enemy_list.add(opponent)
  
  # Create platforms for the level
  class Level_02(Level):
      """ Definition for level 2. """
  
      def __init__(self, player):
          """ Create level 1. """
  
          # Call the parent constructor
          Level.__init__(self, player)
  
          self.level_limit = -1000
  
          # Array with type of platform, and x, y location of the platform.
          level = [[210, 30, 450, 570],
                   [210, 30, 850, 420],
                   [210, 30, 1000, 520],
                   [210, 30, 1120, 280],
                   ]
  
          # Go through the array above and add platforms
          for platform in level:
              block = Platform(platform[0], platform[1])
              block.rect.x = platform[2]
              block.rect.y = platform[3]
              block.player = self.player
              self.platform_list.add(block)
  
  
  def main():
      """ Main Program """
      pygame.init()
  
      # Set the height and width of the screen
      size = [SCREEN_WIDTH, SCREEN_HEIGHT]
      screen = pygame.display.set_mode(size)
  
      pygame.display.set_caption("Side-scrolling Platformer")
  
      # Create the player
      player = Player()
  
      # Create all the levels
      level_list = []
      level_list.append(Level_01(player))
      level_list.append(Level_02(player))
  
      # Set the current level
      current_level_no = 0
      current_level = level_list[current_level_no]
  
      active_sprite_list = pygame.sprite.Group()
      player.level = current_level
  
      player.rect.x = 340
      player.rect.y = SCREEN_HEIGHT - player.rect.height
      active_sprite_list.add(player)
  
      # --- NEW
      bullet_list = pygame.sprite.Group()
      player_list = pygame.sprite.Group()
      player_list.add(player)
      opponent = Opponent()
      opponents = pygame.sprite.Group()
      opponents.add(opponent)
      score = 0
  
  
      # Loop until the user clicks the close button.
      done = False
  
      # Used to manage how fast the screen updates
      clock = pygame.time.Clock()
  
      # -------- Main Program Loop -----------
      while not done:
          for event in pygame.event.get():
              if event.type == pygame.QUIT:
                  done = True
              elif event.type == pygame.MOUSEBUTTONDOWN:
                   # Click a mouse button to instantiate a bullet.
                   bullet = Bullet(player.rect.x,player.rect.y)
                   bullet_list.add(bullet)
                   active_sprite_list.add(bullet)
  
              if event.type == pygame.KEYDOWN:
                  if event.key == pygame.K_LEFT:
                      player.go_left()
                  if event.key == pygame.K_RIGHT:
                      player.go_right()
                  if event.key == pygame.K_UP:
                      player.jump()
  
              if event.type == pygame.KEYUP:
                  if event.key == pygame.K_LEFT and player.change_x &lt; 0:
                      player.stop()
                  if event.key == pygame.K_RIGHT and player.change_x &gt; 0:
                      player.stop()
  
          # Update the player.
          active_sprite_list.update()
   #  ----- The code commented below is what I tried in many ways
          #collided_opponents = pygame.sprite.groupcollide(opponents, bullet_list, False, True)
          #for opponent, bullets in collided_opponents.items():
          #    for bullet in bullets:
          #        score += 1  # Increment the score.
          #        opponent.lives -= 1  # Decrement the lives.
          #        pygame.display.set_caption(str(score))
  
          # Update items in the level
          current_level.update()
  
          # If the player gets near the right side, shift the world left (-x)
          if player.rect.right &gt;= 500:
              diff = player.rect.right - 500
              player.rect.right = 500
              current_level.shift_world(-diff)
  
          # If the player gets near the left side, shift the world right (+x)
          if player.rect.left &lt;= 120:
              diff = 120 - player.rect.left
              player.rect.left = 120
              current_level.shift_world(diff)
  
          # If the player gets to the end of the level, go to the next level
          current_position = player.rect.x + current_level.world_shift
          if current_position &lt; current_level.level_limit:
              player.rect.x = 120
              if current_level_no &lt; len(level_list)-1:
                  current_level_no += 1
                  current_level = level_list[current_level_no]
                  player.level = current_level
  
          # ALL CODE TO DRAW SHOULD GO BELOW THIS COMMENT
          current_level.draw(screen)
          active_sprite_list.draw(screen)
  
          # ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT
  
          # Limit to 60 frames per second
          clock.tick(60)
  
          # Go ahead and update the screen with what we've drawn.
          pygame.display.flip()
  
      # Be IDLE friendly. If you forget this line, the program will 'hang'
      # on exit.
      pygame.quit()
  
  if __name__ == "__main__":
      main()
  </code></pre>