Difference between revisions of "Collisions"

From TRCCompSci - AQA Computer Science
Jump to: navigation, search
(Per Pixel Collision)
Line 19: Line 19:
 
         self.rect = self.image.get_rect() # set rectangle for sprite
 
         self.rect = self.image.get_rect() # set rectangle for sprite
 
         self.rect.topleft = initial_position # set position to value passed into method
 
         self.rect.topleft = initial_position # set position to value passed into method
        self.going_down = True # Start going downwards
 
        self.next_update_time = 0 # update() hasn’t been called yet.
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Line 42: Line 40:
 
         self.rect = self.image.get_rect() # set rectangle for sprite
 
         self.rect = self.image.get_rect() # set rectangle for sprite
 
         self.rect.topleft = initial_position # set position to value passed into method
 
         self.rect.topleft = initial_position # set position to value passed into method
        self.going_down = True # Start going downwards
 
        self.next_update_time = 0 # update() hasn’t been called yet.
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  

Revision as of 10:21, 14 March 2018

Rectangular Collision

The sprite class has built in methods to handle collision detection, one of the methods is collide_rect. For this example we are going to create 2 sprite based classes first, one for the enemy and one for the player:

class HeroSprite(pygame.sprite.Sprite):
    image = None

    def update(self, new_position):
        self.rect.topleft = new_position

    def draw(self, screen):
        screen.blit(self.image, self.rect)

    def __init__(self, initial_position):
        pygame.sprite.Sprite.__init__(self) # run the init for the base class
        if HeroSprite.image is None:
            HeroSprite.image = pygame.image.load("hero.png") # load image for sprite
        self.image = HeroSprite.image # set image for the sprite
        self.rect = self.image.get_rect() # set rectangle for sprite
        self.rect.topleft = initial_position # set position to value passed into method

The code above will load the image for the sprite, set its position and its bounds (rect). We can create another for the enemy:

class EnemySprite(pygame.sprite.Sprite):
    image = None

    def update(self, new_position):
        self.rect.topleft = new_position

    def draw(self, screen):
        screen.blit(self.image, self.rect)

    def __init__(self, initial_position):
        pygame.sprite.Sprite.__init__(self) # run the init for the base class
        if EnemySprite.image is None:
            HEnemySprite.image = pygame.image.load("Enemy.png") # load image for sprite
        self.image = EnemySprite.image # set image for the sprite
        self.rect = self.image.get_rect() # set rectangle for sprite
        self.rect.topleft = initial_position # set position to value passed into method

Before the game loop you can now create an instance of each class, and run the init method for each:

e = EnemySprite
e.__init__(e, [100,100])

pos = [0,0]
h = HeroSprite
h.__init__(h, pos)

Now in the game loop we can make the player move (you can't have collisions if you can't move). h.update(h, pos) will change the position of the hero object:

for events in pygame.event.get(): #get all pygame events
        if events.type == pygame.KEYDOWN:
            if events.key == pygame.K_LEFT:
                pos[0]=pos[0]-10 # pos[0] should be first item in the tuple 
            elif events.key == pygame.K_RIGHT:
               pos[0]=pos[0]+10 # pos[0] should be first item in the tuple
            elif events.key == pygame.K_UP:
                pos[1]=pos[1]-10  # pos[1] should be second item in the tuple
            elif events.key == pygame.K_DOWN:
                pos[1]=pos[1]+10 # pos[1] should be second item in the tuple
            h.update(h, pos)

Now we have moved you can check if this position collides with another sprite:

for events in pygame.event.get(): #get all pygame events
        if events.type == pygame.KEYDOWN:
            if events.key == pygame.K_LEFT:
                pos[0]=pos[0]-10 # pos[0] should be first item in the tuple 
            elif events.key == pygame.K_RIGHT:
               pos[0]=pos[0]+10 # pos[0] should be first item in the tuple
            elif events.key == pygame.K_UP:
                pos[1]=pos[1]-10  # pos[1] should be second item in the tuple
            elif events.key == pygame.K_DOWN:
                pos[1]=pos[1]+10 # pos[1] should be second item in the tuple
            h.update(h, pos)

            if pygame.sprite.collide_rect(b, h):
                print("collision")
            else:
                print("no collision")

Remember for this to work we also need to blit each object to the screen and we also need to update the display:

h.draw(self, SCREEN)
e.draw(self, Screen)
pygame.display.update()

Per Pixel Collision

You can use masks in pygame, this will create an image of a single colour which essentially fills the non transparent parts of the sprite. Follow the instructions above to create a rectangular based collision example. in the init method for each sprite class add the following line:

    self.mask = pygame.mask.from_surface(self.image)

Now change the if statement which checks for a collision to use this instead:

if pygame.sprite.spritecollide(b1, b2, False, pygame.sprite.collide_mask):
    print ("sprites have collided!")
else:
    print("no collision")