# Pygame Shmup Part 3: Collisions (and shooting!)

###### Tags: pythontutorialgamedevpygame

This is part 3 of our “Shmup” project! In this lesson we’ll add collisions between the player and the enemies, as well as adding bullets for the player to shoot.

In this series of lessons we’ll build a complete game using Python and Pygame. It’s intended for beginning programmers who already understand the basics of Python and are looking to deepen their Python understanding and learn the fundamentals of programming games.

You can watch a video version of this lesson here:

# Collisions

Collisions are a fundamental part of game development. Collision detection means that you want to detect whether one object in the game world is touching another object. Collision response is deciding what you want to happen when the collision occurs - does Mario pick up the coin, does Link’s sword damage the enemy, etc.

In our game we currently have a number of enemy sprites flying down the screen towards our player, and we’d like to know when one of those sprites hits. For this stage of our game, we’ll just say that an enemy hitting the player means the game is over.

## Bounding boxes

Remember, each sprite in Pygame has a `rect` attribute that defines its coordinates and its size. A `Rect` object in Pygame is in the format `[x, y, width, height]`, where `x` and `y` represent the upper left corner of the rectangle. Another word for this rectangle is bounding box, because it represents the bounds of the object.

This kind of collision detection is called AABB, which stands for “Axis Aligned Bounding Box”, because the rectangles are aligned with the screen axes - they’re not tilted at an angle. AABB collision is very popular because it’s fast - the computer can compare the coordinates of rectangles very quickly, which is very helpful if you have a large number of objects to compare.

To detect a collision we need to look at the `rect` of the player and compare it with the `rect` of each of the mobs. Now we could do this by looping through the mobs and for each one performing this comparison:

In this picture, you can see that only rectangle #3 is colliding with the large black rectangle. #1 is overlapping in the x axis, but not the y; #2 is overlapping in y, but not in x. In order for two rectangles to be overlapping, their bounds must overlap in each axis. Writing this in code:

``````if mob.rect.right > player.rect.left and \
mob.rect.left < player.rect.right and \
mob.rect.bottom > player.rect.top and \
mob.rect.top < player.rect.bottom:
collide = True``````

Fortunately for us, Pygame has a built-in way of doing the above, by using the `spritecollide()` function.

# Colliding mobs with player

We’re going to add this command to the “update” section of our game loop:

``````#Update
all_sprites.update()

#check to see if a mob hit the player
hits = pygame.sprite.spritecollide(player, mobs, False)
if hits:
running = False``````

The `spritecollide()` function takes 3 arguments: the name of the sprite you want to check, the name of a group you want to compare against, and a True/False parameter called `dokill`. The `dokill` parameter lets you set whether the object should be deleted when it gets hit. If, for example, we were trying to see if the player picked up a coin, we would want to set this to `True` so the coin would disappear.

The result of the `spritecollide()` command is a list of the sprites that were hit (remember, it’s possible the player collided with more than one mob at a time). We’re assigning that list to the variable `hits`.

If the `hits` list is not empty, the `if` statement will be `True`, and we set `running` to `False` so the game will end.

# Shooting back

## Bullet sprite

Now we’re ready to add a new sprite: the bullet. This will be a sprite that is spawned when we shoot, appears at the top of the player sprite, and moves upwards at some fairly high speed. Defining a sprite should be starting to look familiar to you by now, so here’s the complete `Bullet` class:

``````class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((10, 20))
self.image.fill(YELLOW)
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = -10

def update(self):
self.rect.y += self.speedy
# kill if it moves off the top of the screen
if self.rect.bottom < 0:
self.kill()``````

In the `__init__()` method of the bullet sprite, we’re passing `x` and `y` values, so that we can tell the sprite where to appear. Since the player sprite can move, this will be set to where the player is at the time the player shoots. We set `speedy` to a negative value, so that it will be going upward.

Finally, we check to see if the bullet has gone off the top of the screen, and if so, we delete it.

## Keypress event

To keep things simple at first, we’re going to make it so that each time the player presses the spacebar, a bullet will be fired. We need to add that to the events checking:

``````for event in pygame.event.get():
# check for closing window
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shoot()``````

Our new code checks for a `KEYDOWN` event, and if there is one, checks to see if it was the `K_SPACE` key. If it was, we’re going to run the player sprite’s `shoot()` method.

## Spawning the bullet

First we need to add a new group to hold all of the bullets:

``bullets = pygame.sprite.Group()``

Now, we can add the following method to the `Player` class:

``````def shoot(self):
bullet = Bullet(self.rect.centerx, self.rect.top)

All the `shoot()` method does is spawn a bullet, using the top center of the player as the spawn point. Then we make sure to add the bullet to `all_sprites` (so it will be drawn and updated) and to `bullets`, which we’re going to use for the collisions.

#### Bullet collisions

Now we need to check whether a bullet hits a mob. The difference here is we have multiple bullets (in the `bullets` group) and multiple mobs (in the `mobs` group), so we can’t use `spritecollide()` like before because that only compares one sprite against a group. Instead, we’re going to use `groupcollide()`:

``````# Update
all_sprites.update()

# check to see if a bullet hit a mob
hits = pygame.sprite.groupcollide(mobs, bullets, True, True)
for hit in hits:
m = Mob()

The `groupcollide()` function is similar to `spritecollide()`, except that you name two groups to compare, and what you will get back is a list of mobs that were hit. There are two `dokill` options, one for each of the groups.

If we just delete the mobs, we’ll have a problem: running out of mobs! So what we do is loop through `hits` and for each mob that we destroy, another new one will be spawned.

Now it’s actually starting to feel like a game:

In the next lesson, we’ll learn how to add graphics to our game instead of using those plain colored rectangles.