Pygame Sprite Animation v.2 – Better coding? Test it checking FPS on the screen

Hi, everybody! Let’s see how to animate a sprite with Python, using the module pygame. If you want to install pygame, go here to see how to do it with the last version of Python (3.9 at the moment).

Let’s try again the animation of a sprite (load images here) and put them in a directory called png) with a sligtly different approach since the last one was not optimized for a game. In the code the images are loaded when you change the action… but this is not efficient, because you need to load them each time. Wouldn’t it be better to upload all the images once and then using them in the loop just loaded? You will see the code in the second example. This one is the old, not efficient code. How to prove that the second is a better method? We will add the frame rate in the window. You will see it in the video at the end that will demonstrate that the second code is better.

Bad code

This code is not so good because it creates a sprite every time that you press a key and then adds it to a group. So each time the class is istanciated, the images are ordered in a list. That is why the frame rate slows down as you can see in the second video.

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__()
        im = glob.glob(f"png\\{action}*.png")
        lenim = len(im[0])
        self.images = [pygame.image.load(img) for img in im if len(img) == lenim]
        self.images2 = [pygame.image.load(img) for img in I’m 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("Game v.1")
    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()

Good 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, action):
        super(MySprite, self).__init__()
        im = glob.glob(f"png\\{action}*.png")
        lenim = len(im[0])
        self.images = [pygame.image.load(img) for img in glob.glob(f"png\\{action}*.png") if len(img) == lenim]
        self.images2 = [pygame.image.load(img) for img in glob.glob(f"png\\{action}*.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 create_sprites():
    idle = pygame.sprite.Group(MySprite("idle"))
    walk = pygame.sprite.Group(MySprite("walk"))
    run = pygame.sprite.Group(MySprite("run"))
    jump = pygame.sprite.Group(MySprite("jump"))
    dead = pygame.sprite.Group(MySprite("dead"))
    return idle, walk, run, jump, dead

def main():
    pygame.init()
    screen = pygame.display.set_mode(SIZE)
    pygame.display.set_caption("Game v.2")
    idle, walk, run, jump, dead = create_sprites()
    my_group = idle
    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_LEFT: my_group = walk
                if event.key == pygame.K_d: my_group = dead                
                if event.key == pygame.K_UP: my_group = jump
                if event.key == pygame.K_SPACE: my_group = idle
                if event.key == pygame.K_RIGHT: my_group = run
                if event.key == pygame.K_DOWN: my_group = 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()

Let’s test the frame rate of the two code

Pygame's Platform Game

Other Pygame's posts

In case you need to crop the sprite images

from PIL import Image
from glob import glob

width = 330
height = 500

images = [i for i in glob("*.png")]

for image in images:
	im = Image.open(image)
	im = im.crop((0, 0, width, height))
	print(im.width)
	im.save(image)

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.