Duck Duck
Duck Duck

Reputation: 154

How do I make clones of a Sprite in Pygame?

I am adding grass into a Scrolling Platform in Pygame & Python 2.7. The problem is, so far I've only got one strand of grass and I want there to be more. Basically I want there to be clones.

I've heard that Classes can make clones of Sprites, but I"m not exactly sure how classes work and how to even make one. All the tutorials I've found online have only made me more confused.

This part calls the grass_rotate function and also makes the grass_rect:

grass_rect = grass.get_rect(topleft = (grass_x, 480 - player_y + 460))
grass_rotate(screen, grass_rect, (grass_x, 480 - player_y + 460), grass_angle)

This is the grass_rotate function:

def grass_rotate(screen, grass_rect, topleft, grass_angle):
    rotated_grass = pygame.transform.rotate(grass, grass_angle)
    rotated_grass_rect = rotated_grass.get_rect(center = grass_rect.center)
    screen.blit(rotated_grass, rotated_grass_rect)

Upvotes: 2

Views: 2080

Answers (1)

Kingsley
Kingsley

Reputation: 14926

To answer your question, to make rotated "clones" of a sprite, I think it would be best to make a sprite object based on pygame.sprite.Sprite, with options for bitmap rotation.

First lets make a really simple sprite:

class Grass( pygame.sprite.Sprite ):
    """ Creates a tuft of grass at (x,y) """
    def __init__( self, image, x, y ):
        pygame.sprite.Sprite.__init__(self)
        self.image    = image
        self.rect     = self.image.get_rect()
        self.rect.center = ( x, y )

Because this is based on the sprite library, it automatically gets (inherits) the function Grass.draw() from pygame.sprite.Sprite.

EDIT: The above paragraph is false. Sprites do not inherit draw(), this is only part of Sprite Groups. it is necessary to implement your own draw(), iff not using Sprite Groups:

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

So to put it on the screen, we can just do:

grass_image = pygame.image.load( 'grass_clump.png' ).convert_alpha()
my_grass1 = Grass( grass_image, 10, 10 )
my_grass2 = Grass( grass_image, 50, 40 )

...

my_grass1.draw( window )
my_grass2.draw( window )

...

But we want to randomise the angle a bit, so each clump of grass is not so flat & regular. One way to do this is to create a rotated copy of the image when the Grass sprite is initialised (Grass.__init__()). PyGame already has a rotozoom function that does this.

So we basically have the same thing, except now we add an extra optional parameter for rotation. I've defaulted it to None, and without the parameter, the class is free to choose its own random angle.

### Creates a sprite that is rotated slightly to the left or right
class Grass( pygame.sprite.Sprite ):
    """ Creates a tuft of grass at a jaunty angle """
    def __init__( self, image, x, y, rotation=None ):
        pygame.sprite.Sprite.__init__(self)
        if ( rotation == None ):                                       # choose random angle if none
            angle = random.randrange( -15, 16 )                        # choose random angle if none
        self.image    = pygame.transform.rotozoom( image, angle, 1 )   # rotate the image
        self.rect     = self.image.get_rect()
        self.rect.center = ( x, y )

Now we need to put all this together. One of the very useful features of PyGame and Pygame's Sprite library is Sprite Groups. I don't want to go into huge detail here, but essentially it allows you act on a whole bunch of sprites at the same time, making the code much easier.

So now we want lots of clones of grass, so we just make 50 of them, and add to a new group:

### create lots of grass sprites, adding them to a group
grass_image = pygame.image.load( 'grass_clump_48.png' ).convert_alpha()
all_grass_sprites = pygame.sprite.Group()
for i in range( 50 ):
    new_x     = random.randrange( WINDOW_WIDTH )
    new_y     = random.randrange( WINDOW_HEIGHT )
    new_grass = Grass( grass_image, new_x, new_y )
    all_grass_sprites.add( new_grass )

To draw these to the window, you could loop through all sprites in the group with a for() statement. But that's not necessary, because the sprite group can do this for us already:

all_grass_sprites.draw( window )   # draws all the grass sprites

grass_sprites_clones

Too easy right?!

The clump of grass is from Open Clip Art (Public Domain Licensed.)

Here's the reference code:

import pygame
import random

# Window size
WINDOW_WIDTH    = 400
WINDOW_HEIGHT   = 400
WINDOW_SURFACE  = pygame.HWSURFACE|pygame.DOUBLEBUF

GREEN = ( 130, 220,   0 )  # background colour

### Creates a sprite that is rotated slightly to the left or right
class Grass( pygame.sprite.Sprite ):
    """ Creates a tuft of grass at a jaunty angle """
    def __init__( self, image, x, y, rotation=None ):
        pygame.sprite.Sprite.__init__(self)
        if ( rotation == None ):                                       # choose random angle if none
            angle = random.randrange( -15, 14 )                        # choose random angle if none
        self.image    = pygame.transform.rotozoom( image, angle, 1 )   # rotate the image
        self.rect     = self.image.get_rect()
        self.rect.center = ( x, y )


### Initialisation
pygame.init()
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), WINDOW_SURFACE )
pygame.display.set_caption("Grass Sprite Clones")

### create lots of grass sprites, adding them to a group
grass_image = pygame.image.load( 'grass_clump_48.png' ).convert_alpha()
all_grass_sprites = pygame.sprite.Group()
for i in range( 50 ):
    new_x     = random.randrange( WINDOW_WIDTH )
    new_y     = random.randrange( WINDOW_HEIGHT )
    new_grass = Grass( grass_image, new_x, new_y )
    all_grass_sprites.add( new_grass )

### Main Loop
clock = pygame.time.Clock()
done = False
while not done:

    # Handle user-input
    for event in pygame.event.get():
        if ( event.type == pygame.QUIT ):
            done = True
        elif ( event.type == pygame.MOUSEBUTTONUP ):
            # On mouse-click
            pass

    # Update the window, but not more than 60fps
    window.fill( GREEN )
    all_grass_sprites.draw( window )   # draws all the grass sprites
    pygame.display.flip()

    # Clamp FPS
    clock.tick(60)

pygame.quit()

Upvotes: 2

Related Questions