Core classes/modules:

Advanced:

Experimental/Broken:

How to animate an image

Download this image
shipsheet.png
import pygame as pg
pg.init()
screen = pg.display.set_mode((800,600))
shipsheet = pg.image.load('shipsheet.png').convert()


def strip_from_sheet(sheet, start, size, columns, rows):
    frames = []
    for j in range(rows):
        for i in range(columns):
            location = (start[0]+size[0]*i, start[1]+size[1]*j)
            frames.append(sheet.subsurface(pg.Rect(location, size)))
    return frames

class Ship:
    def __init__(self, sheet):
        self.frames = strip_from_sheet(sheet, (0,0), (122,164), 4, 4)
        self.frame_index = 0
        self.update()
        
    def update(self):
        self.image = self.frames[self.frame_index]
        
    def get_event(self, event):
        if event.type == pg.KEYDOWN:
            self.frame_index += 1
        
    def draw(self, screen):
        screen.blit(self.image, (0,0))
        
        
done = False
ship = Ship(shipsheet)
            
while not done:
    for event in pg.event.get():
        if event.type == pg.QUIT:
            done = True
        ship.get_event(event)
    ship.update()
    ship.draw(screen)
    pg.display.update()

This is animation in it's simplest form. The animation is based on key press as oppose to time. We have to tweak many things...such as make the white clear with alpha as well as assign directions for the ship but this will get us started. If you run this code it will animate through the sprite sheet until it comes with a list out of range. This is due to no clause to check for out of range.

Here we use the strip_from_sheet function we had in previous tutorials to cut out the ship spritesheet. Each individual sprites are of the same size and organized in a 4x4 pattern. This means instead of cutting them out in coordinates, we can loop through and cut them out. To do this we need to know the full spritesheet size as well as the size of each sprite. You can do this with pygame as well in a python interpreter.

Python 3.5.1+ (default, Mar 30 2016, 22:46:26) 
[GCC 5.3.1 20160330] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pygame as pg
>>> sheet = pg.image.load('shipsheet.png')
>>> sheet.get_rect().size
(490, 658)
>>> sheet.get_rect().width
490
>>> sheet.get_rect().width // 4
122
>>> sheet.get_rect().height // 4
164

So we load the spritesheet and we can see its full size. Since we know the sprites are aligned 4 by 4 in the spritesheet, if we divide the full spritesheet size by 4 we will get the size of each image. Which boils down to (122,164). So now we can use this to cut up the spritesheet into these segmants.

self.frames = strip_from_sheet(sheet, (0,0), (122,164), 4, 4)

So in the Ship class we get each sprite into a frames list using the frames_from_sheet function and plugging the values in. We are sending shipsheet to the class in its dunder init method. We load the spritesheet NOT in the class because if there are more than one ship you do not want to load the spritesheet every time you create a Ship object. The second argument is the starting location, which is usually (0,0) of the spritesheet..AKA the topleft. Next is the "size". This means the size of each individual sprites. WE only know this because of using the interpreter before at (122,164). The last two arguments ask for how many images in the columns and rows, which is 4 and 4. So now the self.frames in Ship class contain each sprite in a list. You can organize this list further based on direction. For example self.frames[0] through self.frames[3] are down animations.

Ship.image is always the image that we draw. We just change which image that is based on events. In our case this event is a keypress. So every time we press a key the index gets 1 added, which in the Ship.update gets updated to the image that we draw.

So this is the bare bones of animation. Not much, but we are going to make this ship animate by direction later.

Changing the background

So the next step we are going to do is get rid of that annoying white background. Now because our current background is black and there is a black shadow touching the white. It is a good idea to change the background color. Might as well do something blue-ish for the time being. You can simply do this just by filling the background with a blue color.

Because our spritesheet has no white in the images. We can chop ALL white out for transparency. We are going to set the colorkey to white (255,255,255). We are also going to make the background blue o nthe screen so you can see the ship shadow.

So here is the updated code. Only added two lines.


import pygame as pg
pg.init()
screen = pg.display.set_mode((800,600))
shipsheet = pg.image.load('shipsheet.png').convert()
shipsheet.set_colorkey((255,255,255))

def strip_from_sheet(sheet, start, size, columns, rows):
    frames = []
    for j in range(rows):
        for i in range(columns):
            location = (start[0]+size[0]*i, start[1]+size[1]*j)
            frames.append(sheet.subsurface(pg.Rect(location, size)))
    return frames

class Ship:
    def __init__(self, sheet):
        self.frames = strip_from_sheet(sheet, (0,0), (122,164), 4, 4)
        self.frame_index = 0
        self.update()
        
    def update(self):
        self.image = self.frames[self.frame_index]
        
    def get_event(self, event):
        if event.type == pg.KEYDOWN:
            self.frame_index += 1
        
    def draw(self, screen):
        screen.blit(self.image, (0,0))
        
        
done = False
ship = Ship(shipsheet)
            
while not done:
    for event in pg.event.get():
        if event.type == pg.QUIT:
            done = True
        ship.get_event(event)
    ship.update()
    screen.fill((0,0,220))
    ship.draw(screen)
    pg.display.update()


Organizing frames into direction

Not complete