Didgeridude
Didgeridude

Reputation: 123

Pygame Combine Sprites

I am trying to build a game in which combining images (pygame sprites) is an essential tool.

I have set up my code such that I can move sprites across x,y with the mouse and rotate them. The sprites are blitted to the display surface and so this motion can be seen on screen.

Once the user has arranged two sprites as they wish within a square zone, I need them to be able to save this whole zone as a new sprite.

I cannot see a way currently on pygame to capture a region of the display and store this as a sprite. Is this possible? What functions should I use for this purpose?

Upvotes: 3

Views: 2954

Answers (1)

skrx
skrx

Reputation: 20438

You could check which sprites collide with the square area and pass them to a Combined sprite class, combine the rects with the union_ip method and create a new surface with the necessary size to blit the surfaces of the single sprites onto it. (Press C to combine the sprites.)

import pygame as pg


BLUE = pg.Color('dodgerblue1')
SIENNA = pg.Color('sienna1')
GREEN = pg.Color('green')


class Entity(pg.sprite.Sprite):

    def __init__(self, pos, color):
        super().__init__()
        self.image = pg.Surface((42, 68))
        self.image.fill(color)
        self.rect = self.image.get_rect(topleft=pos)

    def move(self, velocity):
        self.rect.move_ip(velocity)


class Combined(pg.sprite.Sprite):

    def __init__(self, sprites):
        super().__init__()
        # Combine the rects of the separate sprites.
        self.rect = sprites[0].rect.copy()
        for sprite in sprites[1:]:
            self.rect.union_ip(sprite.rect)

        # Create a new transparent image with the combined size.
        self.image = pg.Surface(self.rect.size, pg.SRCALPHA)
        # Now blit all sprites onto the new surface.
        for sprite in sprites:
            self.image.blit(sprite.image, (sprite.rect.x-self.rect.left,
                                           sprite.rect.y-self.rect.top))

    def move(self, velocity):
        self.rect.move_ip(velocity)


def main():
    pg.init()
    screen = pg.display.set_mode((640, 480))
    clock = pg.time.Clock()
    entity = Entity((50, 80), BLUE)
    entity2 = Entity((50, 180), SIENNA)
    all_sprites = pg.sprite.Group(entity, entity2)
    area = pg.Rect(200, 50, 200, 200)
    selected = None

    while True:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                return
            elif event.type == pg.MOUSEBUTTONDOWN:
                for sprite in all_sprites:
                    if sprite.rect.collidepoint(event.pos):
                        selected = sprite
            elif event.type == pg.MOUSEBUTTONUP:
                selected = None
            elif event.type == pg.MOUSEMOTION:
                if selected:
                    selected.move(event.rel)
            elif event.type == pg.KEYDOWN:
                if event.key == pg.K_c:
                    # A 'list comprehension' to find the colliding sprites.
                    colliding_sprites = [sprite for sprite in all_sprites
                                         if sprite.rect.colliderect(area)]
                    combined = Combined(colliding_sprites)
                    all_sprites.add(combined)
                    # Kill the colliding sprites if they should be removed.
                    # for sprite in colliding_sprites:
                    #     sprite.kill()

        all_sprites.update()
        screen.fill((30, 30, 30))
        pg.draw.rect(screen, SIENNA, area, 2)
        all_sprites.draw(screen)
        for sprite in all_sprites:  # Outlines.
            pg.draw.rect(screen, GREEN, sprite.rect, 1)

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

if __name__ == '__main__':
    main()
    pg.quit()

Alternatively, you could try to add the combined sprites to another sprite group or a list and blit and move them together.

Upvotes: 1

Related Questions