Search code examples
pythonpygamesprite

Why We Have to Use self.rect and self.image to Determine Rect and Surf on Sprites?


I'm new at pygame, so I don't know so much about sprites. I wanted to make my code more clean so I used a sprite. And to display my image with rect I wrote:

    self.frame_index = 0
    self.surf = self.frames[self.frame_index]
    self.frame_rect = self.surf.get_rect(midtop = (self.x_pos, self.y_pos))

But it raised AttributeError: 'Enemy' object has no attribute 'image' error. Enemy is my class' name. When I used self.image and self.rect instead of self.surf and self.frame_rect my code worked properly.

My main question is: Why we have to use self.rect and self.image when we use a sprite to determine our surface and rect?


Solution

  • My main question is: Why we have to use self.rect and self.image when we use a sprite to determine our surface and rect?

    This is related to the pygame.sprite.Group. Groups are used to manage Sprites. pygame.sprite.Group.draw() and pygame.sprite.Group.update() are methods which are provided by pygame.sprite.Group.

    The former delegates the to the update method of the contained pygame.sprite.Sprites - you have to implement the method. See pygame.sprite.Group.update():

    Calls the update() method on all Sprites in the Group [...]

    The later uses the image and rect attributes of the contained pygame.sprite.Sprites to draw the objects - you have to ensure that the pygame.sprite.Sprites have the required attributes. See pygame.sprite.Group.draw():

    Draws the contained Sprites to the Surface argument. This uses the Sprite.image attribute for the source surface, and Sprite.rect. [...]


    Minimal example:

    import pygame
    
    pygame.init()
    window = pygame.display.set_mode((400, 400))
    clock = pygame.time.Clock()
    
    class Player(pygame.sprite.Sprite):
        
        def __init__(self, center_pos):
            super().__init__() 
            self.image = pygame.Surface((40, 40))
            self.image.fill((0, 255, 0))
            self.rect = self.image.get_rect(center = center_pos)
        
        def update(self, surf):
            keys = pygame.key.get_pressed()
            self.rect.x += (keys[pygame.K_d]-keys[pygame.K_a]) * 5
            self.rect.y += (keys[pygame.K_s]-keys[pygame.K_w]) * 5
            self.rect.clamp_ip(surf.get_rect())
    
    all_sprites = pygame.sprite.Group([Player(window.get_rect().center)])
    
    run = True
    while run:
        clock.tick(60)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
    
        all_sprites.update(window)
    
        window.fill(0)
        all_sprites.draw(window)
        pygame.display.flip()
    
    pygame.quit()
    exit()