Collisions
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(h, e, False, pygame.sprite.collide_mask):
print ("sprites have collided!")
else:
print("no collision")