Zach Kramer
Zach Kramer

Reputation: 193

Create two moving images in pygame

I have an image of a vertical line, and want to create two of them. I want them to randomly spread apart and close the gap (while maintaining a minimum and maximum distance - I'm waiting to fix this first), while moving along the x-axis. The y coords don't move.

There are many examples of creating more complex sprites and games using pygame, but I can't find one simple enough to pinpoint what I'm supposed to do, so any help is appreciated. This code is based off of a simple example found here.

This is the very basic code that I have so far.

class Squeeze(pygame.sprite.Sprite):

    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.img_load()

    def update(self):
        self.rect.x += random.randint(-1, 1)
        if self.rect.x >= 1920:
            self.rect.x += -1
        if self.rect.x <= 0:
            self.rect.x += 1

    def img_load(self):
        self.image = pygame.Surface([SCREEN_WIDTH, SCREEN_HEIGHT])
        self.image.fill(BLACK)
        self.rect = self.image.get_rect()


pygame.init()

SCREEN_WIDTH = 1920
SCREEN_HEIGHT = 1080
screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
FPS = 60
wall = pygame.image.load('wall.png')
wall_list = pygame.sprite.Group()

BLACK = (0, 0, 0)
for i in range(2):
    wall = Squeeze()
    wall.rect.x = random.randrange(SCREEN_WIDTH)
    wall.rect.y = random.randrange(SCREEN_HEIGHT)
    wall_list.add(wall)

done = False
clock = pygame.time.Clock()

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

    screen.fill(BLACK)
    wall_list.update()
    wall_list.draw(screen)

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

pygame.quit()

I'm confused about the pygame.sprite.Group() deal. How do I get the two images to load and operate on them separately? Any other advice is appreciated as well.

Upvotes: 2

Views: 684

Answers (1)

elegent
elegent

Reputation: 4007

Basically a "sprite" is a visible game object in your game. Pygames pygame.sprite.Sprite class is known as the "base class" for all these objects.

Every time when creating the Squeeze class, you derive form Pygames build-in sprite base class:

class Squeeze(pygame.sprite.Sprite):
    def __init__(self):
        ...

Each object (or instance) of the pygame.sprite.Sprite class holds

  • an .update() method and
  • an .image and
  • an .rect attribute.

As the documentation states, "* ... derived classes will want to override the Sprite.update() and assign a Sprite.image and Sprite.rect attributes.*"
You did this by calling the your img_load() method in the __init__() method of your Squeeze class.

The problem is now that your .rect is assigned to the same size as your screen (self.image = pygame.Surface([SCREEN_WIDTH, SCREEN_HEIGHT])) and the .image attribute has the same color as your display screen, so you can´t see it.

Try to modify your img_load() method to

def img_load(self, img):
    self.image = img
    self.rect = self.image.get_rect()

As you can see, the modified img_load() method needs an image object -- which is passed to the img argument. So you also need to change your __init__() method:

def __init__(self, img):
    pygame.sprite.Sprite.__init__(self)
    self.img_load(img)

When now instantiating (e.g. creating an object of a class) a Squeeze object, you need to pass an image (in our case wall_img) to the constructor:

#... main programm

wall_img = pygame.image.load('wall.png') #load an image
wall_list = pygame.sprite.Group() #create a sprite group

BLACK = (0, 0, 0)
for i in range(2):
    wall = Squeeze(wall_img) #create a sprite
    wall.rect.x = random.randrange(SCREEN_WIDTH)
    wall.rect.y = random.randrange(SCREEN_HEIGHT)

    wall_list.add(wall) #add the sprite to the sprite group

The second build-in class you use is the pygame.sprite.Group class -- a container, which can hold and manage (modify) sprites it contains.

Calling the .update() method of a sprite group instance, Pygame automatically calls the update() methods of all sprites in this group. This means you can control a sprites behavior by implementing its update() method, as you did:

#update method of the Squeeze class
def update(self):
    #any logic which changes sprite
    self.rect.x += random.randint(-1, 1)
    if self.rect.x >= 1920:
        self.rect.x += -1
    if self.rect.x <= 0:
        self.rect.x += 1

By calling

wall_list.draw(screen)

your spites will be blitted onto the screen surface using the .image attribute for the source surface, and .rect for the position.

If you now wont to have different images you just need to pass other images (or surfaces) to the Squeeze constructor:

#... main programm

wall_imgs = [pygame.image.load('wall.png'),
             pygame.image.load('other_wall.png')] #load images in list
wall_list = pygame.sprite.Group() #create a sprite group

BLACK = (0, 0, 0)
for i in range(2):
    wall = Squeeze(wall_imgs[i]) #create a sprite
    wall.rect.x = random.randrange(SCREEN_WIDTH)
    wall.rect.y = random.randrange(SCREEN_HEIGHT)

    wall_list.add(wall) #add the sprite to the sprite group

I hope this helps you a little bit :)

Upvotes: 1

Related Questions