How can I write something that changes my score in flappy bird every time the bird and the pipe x position are equal using pygame?

Viewed 489

I started to learn code during quarantine and decided to learn how to use pygame (because I only know the basics of python), I followed a tutorial on youtube called "learning pygame by making flappy bird". The tutorial is very good, but the guy forgot how the scoring worked in the game and wrote a timer to add 1 to the score. I've been trying for the past week or so to make the game recognize if the bird and the pipe x position are the same in order to add 1 point to the score, but I haven't been able to figure it out. I haven't written anything about the score changes yet, so if anyone can give a hand I'd appreciate it a lot. I'm sorry if the code is a little disorganized, as I said, I just started learning.

import pygame
import sys
import random


def draw_floor():
    screen.blit(floor_surface, (floor_x_pos, 440))
    screen.blit(floor_surface, (floor_x_pos + 288, 440))


def create_pipe():
    new_pipe_pos = random.choice(pipe_height)
    bottom_pipe = pipe_surface.get_rect(midtop=(400, new_pipe_pos))
    top_pipe = pipe_surface.get_rect(midbottom=(400, new_pipe_pos - 110))
    return top_pipe, bottom_pipe


def move_pipes(pipes):
    for pipe in pipes:
        pipe.centerx -= 3
    return pipes


def draw_pipes(pipes):
    for pipe in pipes:
        if pipe.bottom >= 400:
            screen.blit(pipe_surface, pipe)
        else:
            flip_pipe = pygame.transform.flip(pipe_surface, False, True)
            screen.blit(flip_pipe, pipe)


def check_collision(pipes):
    for pipe in pipes:
        if bird_rect.colliderect(pipe):
            return False
    if bird_rect.top <= - 100 or bird_rect.bottom >= 460:
        return False
    return True


def rotate_bird(bird):
    new_bird = pygame.transform.rotozoom(bird_surface, -bird_mvt * 3, 1)
    return new_bird


def bird_animation():
    new_bird = bird_frame[bird_index]
    new_bird_rect = new_bird.get_rect(center=(35, bird_rect.centery))
    return new_bird, new_bird_rect


def score_display():
    score_surface = game_font.render(str(score), True, (255, 255, 255))
    score_rect = score_surface.get_rect(center=(144, 35))
    screen.blit(score_surface, score_rect)


pygame.init()
screen = pygame.display.set_mode((288, 512))
pygame.display.set_caption('Flappy Bird')
clock = pygame.time.Clock()

# Variables
gravity = 0.25
bird_mvt = 0
game_active = True
score = 0
highscore = 0
game_font = pygame.font.Font('04B_19.TTF', 20)

bg_surface = pygame.image.load('background-day.png').convert()
floor_surface = pygame.image.load('base.png').convert()
floor_x_pos = 0

bird_upflap = pygame.image.load('yellowbird-upflap.png').convert_alpha()
bird_midflap = pygame.image.load('yellowbird-midflap.png').convert_alpha()
bird_downflap = pygame.image.load('yellowbird-downflap.png').convert_alpha()
bird_frame = [bird_downflap, bird_midflap, bird_upflap]
bird_index = 0
bird_surface = bird_frame[bird_index]
bird_rect = bird_surface.get_rect(center=(35, 256))

pipe_list = []
pipe_height = [256, 280, 144]
pipe_surface = pygame.image.load('pipe-green.png').convert()
SPAWNPIPE = pygame.USEREVENT
pygame.time.set_timer(SPAWNPIPE, 1500)

BIRDFLAP = pygame.USEREVENT + 1
pygame.time.set_timer(BIRDFLAP, 200)

# Game Loop
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE and game_active:
                bird_mvt = 0
                bird_mvt -= 8
            if event.key == pygame.K_SPACE and game_active is False:
                if event.key == pygame.K_SPACE:
                    game_active = True
                    pipe_list.clear()
                    bird_rect.center = (35, 256)
                    bird_mvt = 0
        if event.type == SPAWNPIPE:
            pipe_list.extend(create_pipe())
        if event.type == BIRDFLAP:
            if bird_index < 2:
                bird_index += 1
            else:
                bird_index = 0
            bird_surface, bird_rect = bird_animation()
    screen.blit(bg_surface, (0, 0))

    if game_active:
        # Bird
        bird_mvt += gravity
        rotated_bird = rotate_bird(bird_surface)
        bird_rect.centery += bird_mvt
        screen.blit(rotated_bird, bird_rect)
        game_active = check_collision(pipe_list)

        # Pipes
        pipe_list = move_pipes(pipe_list)
        draw_pipes(pipe_list)
        score_display()

    # Floor
    floor_x_pos -= 1
    draw_floor()
    clock.tick(100)
    if floor_x_pos <= -288:
        floor_x_pos = 0
    pygame.display.update()
1 Answers

So the points made in comments above are 100% spot on and the right way to go about it. In your game, you have a simplification that you can take advantage of that will probably work with your skill level.

Your game is continuously scrolling at a constant rate.... You appear to be moving the pipes leftward by 3 units each frame. So, your challenge is more specific. You just need to keep track of when one of the pipes "passes" the bird's x coord.

Note: in a more complicated game, you may have several checks as mentioned above...

For your build, you have a list of pipes, and the instance variable centerx. So, you could make a quick function to check all the pipes--similar to your move_pipes function to see if centers is within 1 movement of the bird's x coordinate. In pseudocode:

for pipe in pipes:
    if bird.x - step_size < pipe.centerx <= bird.x:
        # add to score

Assuming step_size is probably a global variable for the movement amount, which you would use in the other code to to ensure it is accurate. whatever you have for the bird's x coord will work, which is fixed in your game.

Also... You'll note that you are continuing to add to your list of pipes. If you get good at your game, this will eventually cause some sluggishness because pygame will still attempt to draw these things even if they are out of the viewable window. (It will do the math, but you won't see anything). You need not worry about the size of the list, which could go to millions without problems, but you could limit drawing them by checking the x coord in your draw function... similar to what you are doing now for the y coordinate....

if pipe.centerx < -10:
    pass
else:
    if pipe.bottom ...:
          # draw stuff
    else:
          # draw other stuff
Related