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)