By the end of this week, we'll hopefully have a functional Flappy Bird game that tracks how many pipes have passed and ends the game when a bird hits a pipe.
Step 1: Creating a Pipe
import pygame
import os
class Pipe:
pipes = []
bottom_pipe_image = pygame.image.load(os.path.join("../assets/pipe", "pipe-bottom.png"))
top_pipe_image = pygame.image.load(os.path.join("../assets/pipe", "pipe-top.png"))
def __init__(self, x, bottom_y, top_y):
self.bottom_pipe_rect = pygame.Rect(x, bottom_y, self.bottom_pipe_image.get_width(), self.bottom_pipe_image.get_height())
self.top_pipe_rect = pygame.Rect(x, top_y - self.top_pipe_image.get_height(), self.top_pipe_image.get_width(), self.top_pipe_image.get_height())
self.v = 180
self.pipes.append(self)
def update(self, dt):
self.bottom_pipe_rect.x -= self.v * dt
self.top_pipe_rect.x -= self.v * dt
if self.bottom_pipe_rect.x < -self.bottom_pipe_image.get_width():
self.pipes.remove(self)
def draw(self, screen):
# Bottom pipe
screen.blit(self.bottom_pipe_image, (self.bottom_pipe_rect.x, self.bottom_pipe_rect.y))
# Top pipe
screen.blit(self.top_pipe_image, (self.top_pipe_rect.x, self.top_pipe_rect.y))
Step 2: Add pipes to our game loop
def main():
FPS = 60
run = True
# Define a Pygame clock
clock = pygame.time.Clock()
# Initialize the background
bg = Background(SCREEN_WIDTH, SCREEN_HEIGHT)
# Initialize birds
Bird.birds = [Bird(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, "yellow")]
while run:
# Event handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
for bird in Bird.birds:
bird.jump()
**if len(Pipe.pipes) == 0:
bottom_y = random.randint(300, SCREEN_HEIGHT - 200)
top_y = random.randint(100, bottom_y - 200)
pipe = Pipe(SCREEN_WIDTH, bottom_y, top_y)**
# Updating and drawing
dt = 1 / 60
SCREEN.fill((255, 255, 255)) # Clear background
bg.draw(SCREEN)
bg.update(dt)
**for pipe in Pipe.pipes:
pipe.update(dt)
pipe.draw(SCREEN)**
for bird in Bird.birds:
bird.update(dt)
bird.draw(SCREEN)
pygame.display.update()
clock.tick(FPS)
Step 1: We want our bird to collide with a pipe if one of the pixels in the bird ever touches a pixel in a pipe. There are a couple ways to code this in Pygame, for example using the Rect objects of the Bird and the Pipes (see below). But, because we want our collisions to be as pixel-perfect as possible (and for other reasons we'll see later), we are going to implement this using masks.
[https://repl.it/@Rabbid76/PyGame-colliderect#main.py](https://lh6.googleusercontent.com/ojh5HwBITX848qhuJXY6lQq_i-Bvke2C-Uw7MQ1-DXFWY6AhflxWR9hCTZpOdYmJsyfjUwFAvmAToRntQPlTsfCPkEzyFFY6bnTW-kPM8XuR411AlCS-vt3jEzJVlhPmto8KPIb2=s0)
https://repl.it/@Rabbid76/PyGame-colliderect#main.py
<aside> 💡 Masks in Pygame are short for bitmasks, meaning all bits of opaque pixels are set to 1 and any transparent pixels are 0. We then check if the bird and pipe masks overlap at any point to see if a collision occurs.
</aside>