Pygame: Difference between revisions

From ICO wiki
Jump to navigationJump to search
No edit summary
 
(3 intermediate revisions by the same user not shown)
Line 1: Line 1:
Pygame is a library for programming games with Python. It handles event loop and simplifies drawing the scene.
Pygame is a library for programming games with Python. It handles event loop and simplifies drawing the scene.


==Installation==
=Installation=


Ubuntu users can simply apt-get the package:
Ubuntu users can simply apt-get the package:
Line 11: Line 11:


   pip3 install pygame-1.9.2a0-cp35-none-win_amd64.whl
   pip3 install pygame-1.9.2a0-cp35-none-win_amd64.whl
=Flappy Bird clones=


==Code example==
==Code example==
Line 127: Line 129:
import pygame
import pygame
from pygame.locals import *
from pygame.locals import *
 
   
   
def main_loop(screen):
def main_loop(screen):
Line 133: Line 135:
     bird = pygame.image.load("img/bird.png")
     bird = pygame.image.load("img/bird.png")
     background = pygame.image.load("img/bg.png")
     background = pygame.image.load("img/bg.png")
   
     pygame.display.set_caption('Floppy Bird')
     pygame.display.set_caption('Floppy Bird')
     pygame.mouse.set_visible(0)
     pygame.mouse.set_visible(0)
Line 139: Line 141:
     print "Pipe dimensions:", pipe.get_size()     
     print "Pipe dimensions:", pipe.get_size()     
     print "Background dimensions:", background.get_size()
     print "Background dimensions:", background.get_size()
    print "Bird dimensions:", bird.get_size()   
   
   
     y = 100 # Approximately in the vertical center of the screen
     bird_left = background.get_width() / 3
     vy = 0
     bird_top = background.get_height() / 2
    bird_velocity = 0
    level = [0,0,0,0,0,0,0,0,1,2,3,1,2,3,1,2,3]
   
   
     level = [0, 1, 0, 0, 2, 0, 0, 3,0, 1, 0, 0, 2, 0, 0, 3,0, 1, 0, 0, 2, 0, 0, 3,]
     flipped_pipe = pygame.transform.flip(pipe, 0, 1)
    antipipe = pygame.transform.flip(pipe, 0, 1)
     frames = 0 # Here we count frames
     frames = 0 # Here we count frames
     scene = pygame.Surface((240,180)) # This is where we compose the scene
     scene = pygame.Surface((240,180)) # This is where we compose the scene
Line 156: Line 159:
                 return
                 return
             elif event.type == KEYDOWN and event.key == K_SPACE:
             elif event.type == KEYDOWN and event.key == K_SPACE:
                 vy -= 0.02
                 bird_velocity -= 0.2
                 print "Space was pressed!"
                 print "Space was pressed!"
   
   
         vy += 0.0001
         bird_velocity += 0.001      # Gravity!
         y += vy
         bird_top += bird_velocity  # v = v0 + a*t
        frames += 1
          
          
        pipe_scroll = frames / 2
        background_scroll = frames / 10
          
          
       
         for index in range(0, 3):
         for i in range(0, 3):
             scene.blit(background, (index * background.get_width() - background_scroll % pipe.get_height(), 0))
             scene.blit(background, (i*148 - (frames/10) % 148, 0), (0, 0, 200, 300))
        frames += 1
         # This is basically the inverse of calculation of pipe_left below
       
         current_pipe = int((pipe_scroll + bird_left)/(pipe.get_width() * 3))
         # This is basically the inverse of calculation of px below
         current_pipe = int((frames/2-400+100)/32)
        print "current pipe is:", current_pipe
   
   
         for offset, pipe_height in enumerate(level):
         for pipe_index, pipe_height in enumerate(level):
             if pipe_height == 0: continue # Skip pipes whose height is 0
             if pipe_height == 0: continue # Skip pipes whose height is 0
             px = 400-frames/2 + offset * 32
             pipe_left = pipe_index * pipe.get_width() * 3 - pipe_scroll
             py = 180 - pipe_height * 32
             pipe_top  = 170 - pipe_height * 15
            scene.blit(pipe, (px, py), (0, 0, 32,160))
            scene.blit(antipipe, (px, py - 250), (0, 0, 32,160))
              
              
             # We initialized y = 100 above ;)
             scene.blit(pipe, (pipe_left, pipe_top))
              
             scene.blit(flipped_pipe, (pipe_left, pipe_top - 250))
             if offset == current_pipe: # Highlight the next pipe we could bump into
              
             # Highlight the next pipe we could bump into
                 if y > py:
             if pipe_index == current_pipe:
                 if bird_top > pipe_top:
                     #pygame.draw.rect(scene, (255,0,0), (px, py, 32, 160))
                     #pygame.draw.rect(scene, (255,0,0), (px, py, 32, 160))
                     print "Game over: You bumped into pipe below!"
                     print "Game over: You bumped into pipe below!"
                     return
                     return
                 if y < py-250:
                 if bird_top < pipe_top-250:
                     #pygame.draw.rect(scene, (255,0,0), (px, py-250, 32, 160))
                     #pygame.draw.rect(scene, (255,0,0), (px, py-250, 32, 160))
                     print "Game over: You bumped into pipe above!"
                     print "Game over: You bumped into pipe above!"
Line 195: Line 199:
             print "You win! You've passed all the roadblocks!"
             print "You win! You've passed all the roadblocks!"
             return
             return
           
         # This will return scene bitmap height and width in pixels
         if bird_top + bird.get_height() > scene.get_height():
        width, height = scene.get_size()
       
        if y > height:
             print "Game over: Bird fell down!"
             print "Game over: Bird fell down!"
             return
             return
         if y < 0:
         if bird_top < 0:
             print "Game over: You're aiming too high!"
             print "Game over: You're aiming too high!"
             return
             return
   
   
         scene.blit(bird, (100, int(y)), (18 * (int(frames/100) % 3), 0, 18, 13))
         scene.blit(bird, (bird_left, int(bird_top)), (18 * (int(frames/100) % 3), 0, 18, 13))
         pygame.transform.scale(scene, screen.get_size(), screen) # Here we scale it up and paste to screen
         pygame.transform.scale(scene, screen.get_size(), screen) # Here we scale it up and paste to screen
   
   
         pygame.display.flip()
         pygame.display.flip()
 
 
def game_over(screen, score):
def game_over(screen, score):
     while True:
     # This does nothing yet!
        # This does nothing yet!
    pass
        return
 
def __main__():
def __main__():
     pygame.init()
     pygame.init()
Line 224: Line 222:
     score = main_loop(screen)
     score = main_loop(screen)
     game_over(screen, score)
     game_over(screen, score)
 
if __name__ == "__main__":
if __name__ == "__main__":
     __main__()
     __main__()
</source>
==A perhaps easier to follow version==
<source lang="python">
import os, sys
import pygame
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((800,600))
pipe = pygame.image.load("img/pipe.png")
bird = pygame.image.load("img/bird.png")
background = pygame.image.load("img/bg.png")
pygame.display.set_caption('Floppy Bird')
pygame.mouse.set_visible(0)
print "Pipe dimensions:", pipe.get_size()   
print "Background dimensions:", background.get_size()
print "Bird dimensions:", bird.get_size()   
def game_loop():
    pipe_gap = 70
    bird_left = background.get_width() / 3
    bird_top = background.get_height() / 2
    bird_velocity = 0
    level = [0,0,0,0,0,0,0,0,1,2,3,1,2,3,1,2,3]
    flipped_pipe = pygame.transform.flip(pipe, 0, 1)
    frames = 0 # Here we count frames
    scene = pygame.Surface((240,180)) # This is where we compose the scene
    while True:
        scene.fill(0) # This fills the buffer with black pixels
        for event in pygame.event.get():
            if event.type == QUIT:
                return
            elif event.type == KEYDOWN and event.key == K_ESCAPE:
                return
            elif event.type == KEYDOWN and event.key == K_SPACE:
                bird_velocity -= 0.2
        bird_velocity += 0.001      # Gravity!
        bird_top += bird_velocity  # v = v0 + a*t
        frames += 1
       
        pipe_scroll = frames / 2
        background_scroll = frames / 10
       
        for index in range(0, 3):
            scene.blit(background, (index * background.get_width() - background_scroll % pipe.get_height(), 0))
        # This is basically the inverse of calculation of pipe_left below
        current_pipe = int((pipe_scroll + bird_left)/(pipe.get_width() * 3))
        for pipe_index, pipe_height in enumerate(level):
            if pipe_height == 0: continue # Skip pipes whose height is 0
            pipe_left = pipe_index * pipe.get_width() * 3 - pipe_scroll
            pipe_top  = 170 - pipe_height * 15
           
            scene.blit(pipe, (pipe_left, pipe_top))
            scene.blit(flipped_pipe, (pipe_left, pipe_top - pipe.get_height() - pipe_gap))
            # Highlight the next pipe we could bump into
            if pipe_index == current_pipe:
                if bird_top > pipe_top:
                    #pygame.draw.rect(scene, (255,0,0), (pipe_left, pipe_top, pipe.get_width(), pipe.get_height()))
                    print "Game over: You bumped into pipe below!"
                    return
                if bird_top < pipe_top - pipe_gap:
                    #pygame.draw.rect(scene, (255,0,0), (pipe_left, pipe_top  - pipe.get_height() - pipe_gap, pipe.get_width(), pipe.get_height()))
                    print "Game over: You bumped into pipe above!"
                    return
        if current_pipe > len(level):
            print "You win! You've passed all the roadblocks!"
            return
        if bird_top + bird.get_height() > scene.get_height():
            print "Game over: Bird fell down!"
            return
        if bird_top < 0:
            print "Game over: You're aiming too high!"
            return
        scene.blit(bird, (bird_left, int(bird_top)), (18 * (int(frames/100) % 3), 0, 18, 13))
        pygame.transform.scale(scene, screen.get_size(), screen) # Here we scale it up and paste to screen
        pygame.display.flip()
def game_over():
    font = pygame.font.SysFont("sans", 72)
    text = font.render("Game over!", True, (255, 0, 0))
    position = screen.get_width() / 2 - text.get_width() / 2, screen.get_height() / 2 - text.get_height() / 2
    screen.blit(text, position)
    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                return False
            elif event.type == KEYDOWN and event.key == K_ESCAPE:
                return False
            elif event.type == KEYDOWN and event.key == K_SPACE:
                return True
        pygame.display.flip()
again = True
while again:
    game_loop()
    again = game_over()
</source>
</source>

Latest revision as of 19:10, 24 March 2016

Pygame is a library for programming games with Python. It handles event loop and simplifies drawing the scene.

Installation

Ubuntu users can simply apt-get the package:

 apt-get install python-pygame

Windows users should download pygame .whl file corresponding to their Python runtime version. On Python 3.5 use following to install the module:

 pip3 install pygame-1.9.2a0-cp35-none-win_amd64.whl

Flappy Bird clones

Code example

An example pygame code:

import os, sys
import pygame
from pygame.locals import *

def __main__():
    pygame.init()
    pipe = pygame.image.load("img/pipe.png")
    bird = pygame.image.load("img/bird.png")
    background = pygame.image.load("img/bg.png")
    screen = pygame.display.set_mode((640,480))
    pygame.display.set_caption('Floppy Bird')
    pygame.mouse.set_visible(0)

    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                return
            elif event.type == KEYDOWN and event.key == K_ESCAPE:
                return
        screen.blit(background, (50, 50))
        screen.blit(bird, (100, 100))
        pygame.display.flip()

if __name__ == "__main__":
    __main__()

Download graphics:

wget http://enos.itcollege.ee/~lvosandi/floppy-gfx.zip
unzip floppy-gfx.zip


Execrises:

  • Implement panning of background
  • Draw the pipes on the screen, use pygame.transform.flip to flip the pipe image

Improved example

import os, sys
import pygame
from pygame.locals import *
 
def __main__():
    pygame.init()
    pipe = pygame.image.load("img/pipe.png")
    bird = pygame.image.load("img/bird.png")
    background = pygame.image.load("img/bg.png")
 
 
    screen = pygame.display.set_mode((800,600))
    pygame.display.set_caption('Floppy Bird')
    pygame.mouse.set_visible(0)
 
    print "Pipe dimensions:", pipe.get_size()    
    print "Background dimensions:", background.get_size()
 
    y = 0
    vy = 0
 
    level = [0, 1, 0, 0, 2, 0, 0, 3,0, 1, 0, 0, 2, 0, 0, 3,0, 1, 0, 0, 2, 0, 0, 3,]
 
    antipipe = pygame.transform.flip(pipe, 0, 1)
    frames = 0 # Here we count frames
    scene = pygame.Surface((240,180)) # This is where we compose the scene
    while True:
        scene.fill(0) # This fills the buffer with black pixels
        for event in pygame.event.get():
            if event.type == QUIT:
                return
            elif event.type == KEYDOWN and event.key == K_ESCAPE:
                return
            elif event.type == KEYDOWN and event.key == K_SPACE:
                vy -= 0.02
                print "Space was pressed!"

        vy += 0.0001
        y += vy
        for i in range(0, 3):
            scene.blit(background, (i*148 - (frames/10) % 148, 0), (0, 0, 200, 300))
        frames += 1
 
        for offset, pipe_height in enumerate(level):
            if pipe_height == 0: continue # Skip pipes whose height is 0
            scene.blit(pipe, (400-frames/2 + offset * 32, 180 - pipe_height * 32), (0, 0, 100,160))
            scene.blit(antipipe, (400-frames/2 + offset * 32, 180 - pipe_height * 32 - 250), (0, 0, 100,160))
 
        scene.blit(bird, (100, 100+int(y)), (18 * (int(frames/100) % 3), 0, 18, 13))
        pygame.transform.scale(scene, screen.get_size(), screen) # Here we scale it up and paste to screen
 
        pygame.display.flip()
 
if __name__ == "__main__":
    __main__()

Exercises:

  • Add collision detection
  • Add text overlays and scoring using pygame.font
  • Attempt to get fixed FPS

Almost there!

import os, sys
import pygame
from pygame.locals import *
 
 
def main_loop(screen):
    pipe = pygame.image.load("img/pipe.png")
    bird = pygame.image.load("img/bird.png")
    background = pygame.image.load("img/bg.png")
 
    pygame.display.set_caption('Floppy Bird')
    pygame.mouse.set_visible(0)
 
    print "Pipe dimensions:", pipe.get_size()    
    print "Background dimensions:", background.get_size()
    print "Bird dimensions:", bird.get_size()    
 
    bird_left = background.get_width() / 3
    bird_top = background.get_height() / 2
    bird_velocity = 0
    level = [0,0,0,0,0,0,0,0,1,2,3,1,2,3,1,2,3]
 
    flipped_pipe = pygame.transform.flip(pipe, 0, 1)
    frames = 0 # Here we count frames
    scene = pygame.Surface((240,180)) # This is where we compose the scene
    while True:
        scene.fill(0) # This fills the buffer with black pixels
        for event in pygame.event.get():
            if event.type == QUIT:
                return
            elif event.type == KEYDOWN and event.key == K_ESCAPE:
                return
            elif event.type == KEYDOWN and event.key == K_SPACE:
                bird_velocity -= 0.2
                print "Space was pressed!"
 
        bird_velocity += 0.001      # Gravity!
        bird_top += bird_velocity   # v = v0 + a*t
 
        frames += 1
        
        pipe_scroll = frames / 2
        background_scroll = frames / 10
        
        for index in range(0, 3):
            scene.blit(background, (index * background.get_width() - background_scroll % pipe.get_height(), 0))
 
        # This is basically the inverse of calculation of pipe_left below
        current_pipe = int((pipe_scroll + bird_left)/(pipe.get_width() * 3))
 
        for pipe_index, pipe_height in enumerate(level):
            if pipe_height == 0: continue # Skip pipes whose height is 0
            pipe_left = pipe_index * pipe.get_width() * 3 - pipe_scroll
            pipe_top  = 170 - pipe_height * 15
            
            scene.blit(pipe, (pipe_left, pipe_top))
            scene.blit(flipped_pipe, (pipe_left, pipe_top - 250))
 
            # Highlight the next pipe we could bump into
            if pipe_index == current_pipe:
 
                if bird_top > pipe_top:
                    #pygame.draw.rect(scene, (255,0,0), (px, py, 32, 160))
                    print "Game over: You bumped into pipe below!"
                    return
                if bird_top < pipe_top-250:
                    #pygame.draw.rect(scene, (255,0,0), (px, py-250, 32, 160))
                    print "Game over: You bumped into pipe above!"
                    return
 
        if current_pipe > len(level):
            print "You win! You've passed all the roadblocks!"
            return
 
        if bird_top + bird.get_height() > scene.get_height():
            print "Game over: Bird fell down!"
            return
        if bird_top < 0:
            print "Game over: You're aiming too high!"
            return
 
        scene.blit(bird, (bird_left, int(bird_top)), (18 * (int(frames/100) % 3), 0, 18, 13))
        pygame.transform.scale(scene, screen.get_size(), screen) # Here we scale it up and paste to screen
 
        pygame.display.flip()
 
 
def game_over(screen, score):
    # This does nothing yet!
    pass
 
def __main__():
    pygame.init()
    screen = pygame.display.set_mode((800,600))
    score = main_loop(screen)
    game_over(screen, score)
 
if __name__ == "__main__":
    __main__()


A perhaps easier to follow version

import os, sys
import pygame
from pygame.locals import *

pygame.init()
screen = pygame.display.set_mode((800,600))

pipe = pygame.image.load("img/pipe.png")
bird = pygame.image.load("img/bird.png")
background = pygame.image.load("img/bg.png")

pygame.display.set_caption('Floppy Bird')
pygame.mouse.set_visible(0)

print "Pipe dimensions:", pipe.get_size()    
print "Background dimensions:", background.get_size()
print "Bird dimensions:", bird.get_size()    
 
def game_loop():
    pipe_gap = 70
    bird_left = background.get_width() / 3
    bird_top = background.get_height() / 2
    bird_velocity = 0
    level = [0,0,0,0,0,0,0,0,1,2,3,1,2,3,1,2,3]
 
    flipped_pipe = pygame.transform.flip(pipe, 0, 1)
    frames = 0 # Here we count frames
    scene = pygame.Surface((240,180)) # This is where we compose the scene
    while True:
        scene.fill(0) # This fills the buffer with black pixels
        for event in pygame.event.get():
            if event.type == QUIT:
                return
            elif event.type == KEYDOWN and event.key == K_ESCAPE:
                return
            elif event.type == KEYDOWN and event.key == K_SPACE:
                bird_velocity -= 0.2
 
        bird_velocity += 0.001      # Gravity!
        bird_top += bird_velocity   # v = v0 + a*t
 
        frames += 1
        
        pipe_scroll = frames / 2
        background_scroll = frames / 10
        
        for index in range(0, 3):
            scene.blit(background, (index * background.get_width() - background_scroll % pipe.get_height(), 0))
 
        # This is basically the inverse of calculation of pipe_left below
        current_pipe = int((pipe_scroll + bird_left)/(pipe.get_width() * 3))
 
        for pipe_index, pipe_height in enumerate(level):
            if pipe_height == 0: continue # Skip pipes whose height is 0
            pipe_left = pipe_index * pipe.get_width() * 3 - pipe_scroll
            pipe_top  = 170 - pipe_height * 15
            
            scene.blit(pipe, (pipe_left, pipe_top))
            scene.blit(flipped_pipe, (pipe_left, pipe_top - pipe.get_height() - pipe_gap))
 
            # Highlight the next pipe we could bump into
            if pipe_index == current_pipe:
 
                if bird_top > pipe_top:
                    #pygame.draw.rect(scene, (255,0,0), (pipe_left, pipe_top, pipe.get_width(), pipe.get_height()))
                    print "Game over: You bumped into pipe below!"
                    return
                if bird_top < pipe_top - pipe_gap:
                    #pygame.draw.rect(scene, (255,0,0), (pipe_left, pipe_top  - pipe.get_height() - pipe_gap, pipe.get_width(), pipe.get_height()))
                    print "Game over: You bumped into pipe above!"
                    return
 
        if current_pipe > len(level):
            print "You win! You've passed all the roadblocks!"
            return
 
        if bird_top + bird.get_height() > scene.get_height():
            print "Game over: Bird fell down!"
            return
        if bird_top < 0:
            print "Game over: You're aiming too high!"
            return
 
        scene.blit(bird, (bird_left, int(bird_top)), (18 * (int(frames/100) % 3), 0, 18, 13))
        pygame.transform.scale(scene, screen.get_size(), screen) # Here we scale it up and paste to screen

        pygame.display.flip()
 
 
def game_over():
    font = pygame.font.SysFont("sans", 72)
    text = font.render("Game over!", True, (255, 0, 0))
    position = screen.get_width() / 2 - text.get_width() / 2, screen.get_height() / 2 - text.get_height() / 2
    screen.blit(text, position)
    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                return False
            elif event.type == KEYDOWN and event.key == K_ESCAPE:
                return False
            elif event.type == KEYDOWN and event.key == K_SPACE:
                return True
        pygame.display.flip()


again = True
while again:
    game_loop()
    again = game_over()