tushortz
tushortz

Reputation: 5015

pygame sprite and draw method not working as expected

Please any help would be greatly appreciated. I am writing a game with Pygame and after creating all the classes and methods I need. When I run the game I see five alien characters of my game showing up from the left side of the screen joined together before I actually see what i wanted my code to display (aliens moving at random positions down the screen).

here is my code:

class Alien():
    def __init__(self, image):
        self.x = random.randrange(20,width - 20)
        self.y = random.randrange(-200, -20)
        self.speed = random.randint(1, 5)
        self.image = pygame.image.load(os.path.join("../images", image)).convert_alpha()
        self.rect = self.image.get_rect()

    def move_down(self):
        self.rect.y += self.speed

    def draw(self, screen):
        screen.blit(self.image, self.rect)

its implementation

for i in range (20):
    aliens = Alien("alien.png")
    enemies.append(aliens)

done = False
while done == False:

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True

    screen.fill(white)

    for i in range(len(enemies)):
        enemies[i].move_down()
        enemies[i].draw(screen)
        enemies[i].check_landed()

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

note: I have removed some code for clarity. result

pygame sprite result

Upvotes: 2

Views: 1192

Answers (1)

sloth
sloth

Reputation: 101042

You store the position of the aliens in the fields self.x and self.y, but to draw them, you actually don't use self.x and self.y, but self.rect.

You create self.rect by calling self.image.get_rect(), and when you call get_rect() on a Surface, the position of the Rect is always (0, 0).

So the x coordinate is always 0, hence they are all on the left side of the screen.

I suggest rewriting your code to:

class Alien():
    # pass the Surface to the instance instead of the filename
    # this way, you only load the image once, not once for each alien
    def __init__(self, image):
        self.speed = random.randint(1, 5)
        self.image = image
        # since we're going to use a Rect of drawing, let's use the
        # same Rect to store the correct position of the alien
        self.rect = self.image.get_rect(top=random.randrange(-200, -20), left=random.randrange(20,width - 20))

    def move_down(self):
        # the Rect class has a lot of handy functions like move_ip
        self.rect.move_ip(0, self.speed)

    def draw(self, screen):
        screen.blit(self.image, self.rect)

# load the image once. In more complex games, you usually
# want to abstract the loading/storing of images         
alienimage = pygame.image.load(os.path.join("../images", 'alien.png')).convert_alpha()
for _ in range (20):
    aliens = Alien(alienimage)
    enemies.append(aliens)

done = False
while done == False:

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True

    screen.fill(white)

    # just use a "regular" for loop to loop through all enemies
    for enemy in enemies:
        enemy.move_down()
        enemy.draw(screen)
        enemy.check_landed()

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

You could go further and use the Sprite- and Group-class to further generalize your code, but that's another topic.

Upvotes: 2

Related Questions