Pygame : Working with Sprites and animations




We already know how to load and display images in pygame now. But those are only images. You can do nothing more than displaying those images using a surface object. For making games we need more than simply displaying. And here comes the Sprite module.

By using this module to its full potential, you can easily manage and draw your game objects. The sprite classes are very optimized, so it's likely your game will run faster with the sprite module than without.
This module not only allow you to draw the images, but also do many operations on them like animations, grouping etc.. Also it provides collision detection power to your game development process. You need not write the whole collision detection code by yourself.

The sprite module provides two classes:
  1. Sprite
  2. Group
The Sprite class is designed to be a base class for all your game objects while the Group class is container for the sprites. For example if you are creating a menu for your game, all the buttons in the menu are sprites. And the menu itself is a sprite group.

In this post let’s see an example of sprite class:
Let’s animate the ship in our previous example with some water ripples around it. Like in following video



In the above video what we see our ship is not moving right now but having the water around it is moving. To create this animation we’ll use the sprite module of pygame. Till now our ship was only an image but now we’ll turn it into a game object. To do so we’ll have to create a class Ship extending class pygame.sprite.Sprite as follows:

class Ship(pygame.sprite.Sprite):
def __init__(self):
super(Ship, self).__init__()


In sprite class we need to assign the image of sprite as “self.image = image_to_assign”
now, we have to display a ship, and a set of water ripple frames around it. That means our main image is ship and we have to blit the water ripples along with the ship.
So we’ll assign self.image=ship and create an array for animation frames as “self.animFrames” and store the ripple images in this array. In this way we have what we need to create our animation.

Now we have to display this animation. Here, if we display all the ripple frames at a time, we can’t call it animation; we want to animate it show frame by frame. That means we’ll need a timer and an index to store current frame. And also a position to display our sprite and its animation. So let’s modify our sprite class:

class Ship(pygame.sprite.Sprite):
    index = 0

    def __init__(self, texture, animFrames, x=0, y=0, width=1, height=1):
        super(Ship, self).__init__()
        self.image = texture
        self.animFrames = animFrames
        self.currentFrame = self.animFrames[0]
        self.x = x
        self.y = y
        self.rect = self.image.get_rect()
        self.width = self.rect.width
        self.height = self.rect.height

Here we are providing texture of ship and animation frames as well as the rect details to sprite from parameters.

To keep the animation updating let’s write the update method:

def update(self):
    if self.isAnimating:
        self.animate()

and to implement the animation functionality, let’s add the following methods:

def startAnimation(self):
    self.isAnimating = True

def animate(self):
    self.index += 1
    if self.index >= len(self.animFrames):
        self.index = 0
    self.currentFrame = self.animFrames[self.index]
    time.sleep(0.01)

def stopAnimation(self):
    self.isAnimating = False


Here the time.sleep provides us the delay of displaying the next animation frame. Now we have done everything our update method is properly updating the sprite according to animation but to display the animation on the screen, we’ll have to use the draw method of sprite class:

def draw(self, surface):
    surface.blit(self.currentFrame, (self.x-self.width, self.y-self.height*0.2))
    surface.blit(self.image, ((self.x), (self.y)))


Here we are drawing the animation frame first and on top of the animation frame we are drawing the ship. Because we want the water ripple under the ship.

Now we have successfully created the Ship class we only have to instantiate it on our previous window and run the code

so as usual first load images:

We already have loaded the ship. We only need to load animation frames

shipAnimFrames_str = ["ripple0.png", "ripple1.png", "ripple2.png", "ripple3.png", "ripple4.png"]

shipAnimFrames = []
i = 0
while < len(shipAnimFrames_str):
    shipAnimFrames.append((pygame.image.load(shipAnimFrames_str[i])))
    i += 1

ShipSprite = Ship(ship, shipAnimFrames, winWidth*0.45, winHeight*0.75)
ShipSprite.startAnimation()

and inside the game loop
call the update() and draw() of ShipSprite
as
ShipSprite.update()
ShipSprite.draw()


save the code and run it to get output like above.


The complete code for the above is as follows:



Similarly you can use the background image also as sprite rather than a surface. By making it sprite you can convert this whole code into an endless travel for your ship as shown in following video.


You can get the complete source code for this endless travel in the following repo. In the coming post let’s see what more we can do with sprites like collision detection, grouping, other animations etc.. so stay tuned.

No comments:

Post a Comment

Your comments and suggestions are valuable and are always welcome and will be helpful to me to create a good quality content. Please leave your thoughts