1

I am making a flappy bird clone game, using pygame. I want to draw pillars by using Sprite.draw. I made a Pillar class and initialized it with two rectangles p_upper and p_lower on the left side of the screen, coming towards the right side with the help of the update function of the sprite. But the screen is only showing the p_lower pillar. Can anyone help?

enter image description here

class Pillar(pygame.sprite.Sprite):
    # the "h" parameter is height of upper pillar upto gap
    # "w" is the width of the pillar
    # pillar is coming from left to right
    def __init__(self, w, h, gap):
        pygame.sprite.Sprite.__init__(self)

        self.image = pygame.Surface((w, h))
        self.image.fill(green)
        self.p_upper = self.rect = self.image.get_rect()
        self.p_upper.topleft = (-w, 0)

        self.image = pygame.Surface((w, HEIGHT - (h + gap)))
        self.image.fill(green)
        self.p_lower = self.rect = self.image.get_rect()
        self.p_lower.topleft = (-w, h + gap)

    def update(self):
        self.p_upper.x += 1
        self.p_lower.x += 1
skrx
  • 19,980
  • 5
  • 34
  • 48

2 Answers2

2

Because of the following two lines:

self.p_upper = self.rect = self.image.get_rect()

and...

self.p_lower = self.rect = self.image.get_rect()

These are both grabbing the same reference to the self.rect. The first line runs and assigns the rect reference to p_upper. Then the same reference is assigned to p_lower. Because it's the same reference, when you update the location of the lower rectangle, you're actually updating both.

Blake O'Hare
  • 1,863
  • 12
  • 16
  • but in the both lines the self.image is different, so the self.rect should also be different. – Tauheed Ahmad Feb 11 '18 at 10:19
  • Huh, just noticed that. Can I see the code for where you're drawing these? It's still suspicious that you're creating two images and then immediately discarding one of them (along with overwriting `self.rect`), and my hunch is that it's ultimately related. – Blake O'Hare Feb 11 '18 at 10:24
0

Using a sprite that consists of two rects and images isn't a good solution for this problem. I suggest to create two separate sprites with their own image and rect. To create two sprite instances at the same time and to add them to a sprite group, you can write a short function as you can see in this example:

import pygame as pg
from pygame.math import Vector2


green = pg.Color('green')
HEIGHT = 480

class Pillar(pg.sprite.Sprite):

    def __init__(self, x, y, w, h):
        pg.sprite.Sprite.__init__(self)
        self.image = pg.Surface((w, h))
        self.image.fill(green)
        self.rect = self.image.get_rect(topleft=(x, y))

    def update(self):
        self.rect.x += 1


def create_pillars(w, h, gap, sprite_group):
    sprite_group.add(Pillar(0, 0, w, h-gap))
    sprite_group.add(Pillar(0, HEIGHT-(h+gap), w, h+gap))


def main():
    screen = pg.display.set_mode((640, 480))
    clock = pg.time.Clock()
    all_sprites = pg.sprite.Group()
    create_pillars(50, 170, 0, all_sprites)

    done = False

    while not done:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                done = True
            elif event.type == pg.KEYDOWN:
                if event.key == pg.K_a:
                    create_pillars(50, 170, 15, all_sprites)
                elif event.key == pg.K_s:
                    create_pillars(50, 170, 30, all_sprites)
                elif event.key == pg.K_d:
                    create_pillars(50, 100, -60, all_sprites)

        all_sprites.update()
        screen.fill((30, 30, 30))
        all_sprites.draw(screen)

        pg.display.flip()
        clock.tick(30)


if __name__ == '__main__':
    pg.init()
    main()
    pg.quit()
skrx
  • 19,980
  • 5
  • 34
  • 48