Animation on Pygame 2 – free characters and more actions

Today we are gonna take a look at some free sprites on gameart2d.com and we will animate those sprites in different action with pygame. We saw how to animate one action in the last post about this topic, now we are going to go further animating different actions for the same character.

We’ve seen some code to show a sprite in action with this code here in a post:

import pygame
import glob
 
SIZE = WIDTH, HEIGHT = 600, 600 #the width and height of our screen
FPS = 20 #Frames per second
 
class MySprite(pygame.sprite.Sprite):
    def __init__(self):
        super(MySprite, self).__init__()
        fld = "png"
        self.images = [pygame.image.load(img) for img in glob.glob(fld + "\\*.png")]
        self.index = 0
        self.rect = pygame.Rect(5, 5, 150, 198)

    def update(self):
        if self.index >= len(self.images):
            self.index = 0
        self.image = self.images[self.index]
        self.index += 1
 
def main():
    pygame.init()
    screen = pygame.display.set_mode(SIZE)
    pygame.display.set_caption("Trace")
    my_sprite = MySprite()
    my_group = pygame.sprite.Group(my_sprite)
    clock = pygame.time.Clock()
    loop = 1
    while loop:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                loop = 0
 
        my_group.update()
        screen.fill((0,0,0))
        my_group.draw(screen)
        pygame.display.update()
        clock.tick(FPS)
    pygame.quit()
 
if __name__ == '__main__':
    main()

The output can be something like this:

It is neat, isn’t it? With…

self.images = [pygame.image.load(img) for img in glob.glob(fld + "\\*.png")]

We can load all the images in the folder fld (‘png’) in this case.

fld = "png"

We had 2 problems though. If you read this post, you saw that I renamed all the png files to make the 10th .png file to follow the 9th instead of following the 1st.

Let me explain, as the computer sees the names of the files like strings the sequence is:

run1.png run10.png run11.png run2.png …

instead of

run1.png run2.png …

That’s because run1 and run11 comes in sequence before run2 if we read them as characters.

So, to avoid this I choose to make a program to change the first 9 numbers into run01, run02… so the right sequence was preserved.

Now I want to make something different, I do not want to change the name of the file, but just check the length of the file names and put the shortest in a list (1 to 9) and the longest in another (10 …) and then join the two list in the right order without changing their name. This is the final code (you can see exactly what I didi in the live coding below)

        serie = 'jump'
        im = glob.glob(f"png\\{serie}*.png")
        lenim = len(im[0])
        self.images = [pygame.image.load(img) for img in glob.glob(f"png\\{serie}*.png") if len(img) == lenim]
        self.images2 = [pygame.image.load(img) for img in glob.glob(f"png\\{serie}*.png") if len(img) > lenim]
        self.images.extend(self.images2)

What if there are more actions instead of just walk?

As you can see in the code above, I have used the variable serie with ‘jump’. This was made because in the example with the boy free character png animation files I had in the same directory more sprites with more actions. To have the choice to see only the sprite of a type of action I just have to change the name of the action (that is in the files name in common for each action, of course) to see that animation. All will be clear in the video below.

The live coding video

The entire code

import pygame
import glob
 
SIZE = WIDTH, HEIGHT = 600, 600 #the width and height of our screen
FPS = 20 #Frames per second
 
class MySprite(pygame.sprite.Sprite):
    def __init__(self):
        super(MySprite, self).__init__()
        serie = 'jump'
        im = glob.glob(f"png\\{serie}*.png")
        lenim = len(im[0])
        self.images = [pygame.image.load(img) for img in glob.glob(f"png\\{serie}*.png") if len(img) == lenim]
        self.images2 = [pygame.image.load(img) for img in glob.glob(f"png\\{serie}*.png") if len(img) > lenim]
        self.images.extend(self.images2)
        self.index = 0
        self.rect = pygame.Rect(5, 5, 150, 198)

    def update(self):
        if self.index >= len(self.images):
            self.index = 0
        self.image = self.images[self.index]
        self.index += 1
 
def main():
    pygame.init()
    screen = pygame.display.set_mode(SIZE)
    pygame.display.set_caption("Trace")
    my_sprite = MySprite()
    my_group = pygame.sprite.Group(my_sprite)
    clock = pygame.time.Clock()
    loop = 1
    while loop:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                loop = 0
 
        my_group.update()
        screen.fill((0,0,0))
        my_group.draw(screen)
        pygame.display.update()
        clock.tick(FPS)
    pygame.quit()
 
if __name__ == '__main__':
    main()

Interacting with the animation through keys

With this code we can control the animation with these keys:

  • i for idle
  • w for walk
  • r for run
  • j for jump
  • d for falling
import pygame
import glob
 
SIZE = WIDTH, HEIGHT = 600, 600 #the width and height of our screen
FPS = 20 #Frames per second
 
class MySprite(pygame.sprite.Sprite):
    def __init__(self, action):
        super(MySprite, self).__init__()
        serie = action
        im = glob.glob(f"png\\{serie}*.png")
        lenim = len(im[0])
        self.images = [pygame.image.load(img) for img in glob.glob(f"png\\{serie}*.png") if len(img) == lenim]
        self.images2 = [pygame.image.load(img) for img in glob.glob(f"png\\{serie}*.png") if len(img) > lenim]
        self.images.extend(self.images2)
        self.index = 0
        self.rect = pygame.Rect(5, 5, 150, 198)

    def update(self):
        if self.index >= len(self.images):
            self.index = 0
        self.image = self.images[self.index]
        self.index += 1

def action(action):
    my_sprite = MySprite(action)
    my_group = pygame.sprite.Group(my_sprite)
    return my_group

def main():
    pygame.init()
    screen = pygame.display.set_mode(SIZE)
    pygame.display.set_caption("Press i w r j d or arrows and space")
    my_sprite = MySprite("idle")
    my_group = pygame.sprite.Group(my_sprite)
    clock = pygame.time.Clock()
    loop = 1
    while loop:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                loop = 0
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_w or event.key == pygame.K_LEFT:
                    my_group = action("walk")
                if event.key == pygame.K_d:
                    my_group = action("dead")                
                if event.key == pygame.K_j or event.key == pygame.K_UP:
                    my_group = action("jump")
                if event.key == pygame.K_i or event.key == pygame.K_SPACE:
                    my_group = action("idle")
                if event.key == pygame.K_r or event.key == pygame.K_RIGHT:
                    my_group = action("run")
                if event.key == pygame.K_d or event.key == pygame.K_DOWN:
                    my_group = action("dead")

 
        my_group.update()
        screen.fill((0,0,0))
        my_group.draw(screen)
        pygame.display.update()
        clock.tick(FPS)
    pygame.quit()
 
if __name__ == '__main__':
    main()

 

Pygame's Platform Game

Other Pygame's posts

Published by pythonprogramming

Started with basic on the spectrum, loved javascript in the 90ies and python in the 2000, now I am back with python, still making some javascript stuff when needed.