Difference between revisions of "Collisions"

From TRCCompSci - AQA Computer Science
Jump to: navigation, search
(Created page with "==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 sp...")
 
(Rectangular Collision)
Line 8: Line 8:
 
     def update(self, new_position):
 
     def update(self, new_position):
 
         self.rect.topleft = new_position
 
         self.rect.topleft = new_position
 +
 +
    def draw(self, screen):
 +
        screen.blit(self.image, self.rect)
  
 
     def __init__(self, initial_position):
 
     def __init__(self, initial_position):
Line 28: Line 31:
 
     def update(self, new_position):
 
     def update(self, new_position):
 
         self.rect.topleft = new_position
 
         self.rect.topleft = new_position
 +
 +
    def draw(self, screen):
 +
        screen.blit(self.image, self.rect)
  
 
     def __init__(self, initial_position):
 
     def __init__(self, initial_position):
Line 51: Line 57:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Now in the game loop we can make the player move (you can't have collisions if you can't move):
+
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:
 +
 
 +
<syntaxhighlight lang=python>
 +
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)
 +
</syntaxhighlight>
 +
 
 +
Now we have moved you can check if this position collides with another sprite:
  
 
<syntaxhighlight lang=python>
 
<syntaxhighlight lang=python>
Line 64: Line 86:
 
             elif events.key == pygame.K_DOWN:
 
             elif events.key == pygame.K_DOWN:
 
                 pos[1]=pos[1]+10 # pos[1] should be second item in the tuple
 
                 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")
 +
</syntaxhighlight>
 +
 +
Remember for this to work we also need to blit each object to the screen and we also need to update the display:
 +
 +
<syntaxhighlight lang=python>
 +
h.draw(self, SCREEN)
 +
e.draw(self, Screen)
 +
pygame.display.update()
 +
</syntaxhighlight>
 +
 +
==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:
  
        h.update(h, pos)
+
<syntaxhighlight lang=python>
 +
        self.mask = pygame.mask.from_surface(self.image)
 +
</syntaxhighlight>
 +
 
 +
Now change the if statement which checks for a collision to use this instead:
 +
 
 +
<syntaxhighlight lang=python>
 +
if pygame.sprite.spritecollide(b1, b2, False, pygame.sprite.collide_mask):
 +
    print ("sprites have collided!")
 +
else:
 +
    print("no collision")
 
</syntaxhighlight>
 
</syntaxhighlight>

Revision as of 11:17, 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
        self.going_down = True # Start going downwards
        self.next_update_time = 0 # update() hasn’t been called yet.

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
        self.going_down = True # Start going downwards
        self.next_update_time = 0 # update() hasn’t been called yet.

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")