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()