You are on page 1of 34

11/30/22

Pygame!

pygame

+ The Pygame library is probably the most well-known python


library for game development.
+ It’s not the most advanced or high-level library, but it’s simple
and easy to learn (comparatively).
+ Other advanced game libraries are Panda3D .
+ Pygame is a must for entry point into game development.

1
11/30/22

Our game

We will build a retro game where you’re moving a


car sideways to avoid the incoming cars.
This is the inspiration.

This will be the final scenario

2
11/30/22

Part I

We need to import the libraries

+ import pygame
+ from pygame.locals import *

3
11/30/22

Init

+ pygame.init()

+ This line is compulsory to add anytime you want to use


the Pygame library. It must be added before any other
pygame function, else an initialization error may occur.

The Game Loop

+ Every game needs a “Game Loop”.


+ The Game Loop is where all the game events occur,
update and get drawn to the screen.
+ Once the initial setup and initialization of variables is
done, the Game Loop begins where the program keeps
updating the screen until an event of type QUIT occurs.

4
11/30/22

Game loop

+ while True:
+ # Code
+ # Code
+ …
+ pygame.display.update()

pygame.display.update()

+ The changes are not implemented until


the display.update() has been called.
+ Since games are constantly changing values, the update
function is in the game loop, constantly updating.

10

5
11/30/22

Quitting the
Game loop
+ Every game loop must
have a way to quit the
loop, or some action
that triggers the end
point (such as clicking
the quit button).
+ Or your game will run
indefinitely.

11

Quitting the Game loop

+ while True:
+ pygame.display.update()
+ for event in pygame.event.get():
+ if event.type == QUIT:
+ pygame.quit()
+ sys.exit()

12

6
11/30/22

Quitting the Game loop

+ pygame.quit() and sys.exit() are called to close the


pygame window and the python script respectively
+ Simply using sys.exit() may lead to an error.

13

Event Objects

+ An “Event” occurs when the user performs a specific action,


such as clicking his mouse or pressing a keyboard button.
+ Pygame records each and every event that occurs.
+ To loop into the events, we must call
the pygame.event.get() function, which returns a list
of pygame.event.Event objects.

14

7
11/30/22

Event objects

+ One of the many attributes (or properties) held by event


objects is type. The type attribute tells us what kind of
event the object represents.
+ If the previous example, we used event.type == QUIT to
determine whether the game was to be closed or not.

15

Display Screen

+ For every game, we create a window of a fixed size by


passing a tuple containing the width and height.
+ This tuple is then passe into
the display.set_mode() function.

+ DISPLAYSURF = pygame.display.set_mode((300,300))

16

8
11/30/22

Display Screen

+ The third parameter is the co-ordinate for the origin point of


the circle. (200, 50) means the center of the circle will be at
the 200th X co-ordinate and the 50th Y co-ordinate.
+ pygame.draw.circle(DISPLAYSURF, BLACK, (200,50), 30)
+ Remember, both of these values start from the top-left hand
side. X values increase from left to right, and Y values increase
from top to bottom.

17

Colors

+ Colors are a critical part of any game development.


+ Pygame uses the typical RGB system of colors.
+ The values for each color range from 0 – 255, a total of
256 values. You can find the total number of possible
color combinations by evaluating 256 x 256 x 256, which
results in a value well over 16 million.

18

9
11/30/22

Colors

+ color1 = pygame.Color(0, 0, 0) # Black


+ color2 = pygame.Color(255, 255, 255) # White
+ color3 = pygame.Color(128, 128, 128) # Grey
+ color4 = pygame.Color(255, 0, 0) # Red

19

Drawing Functions

+ Drawing functions are used to create objects in Pygame.


+ Due to their similarities, they often share some
parameters which they use to create the required shape.
+ We will not use every function in detail. But we will
present a general overview of what these parameters
are.

20

10
11/30/22

Parameters

+ surface parameter is the surface object on which pygame will draw the shape.
+ color parameter is the designated color of the assigned shape.
+ The pointlist parameter is a tuple containing co-ordinates or “points”. For instance,
for a rectangle you will pass a tuple with 4 co-ordinate pairs inside it.
+ width is an optional parameter that determines the size of the outline of the
shape. Takes integer values.
+ start_point and end_point represent a set of co-ordinates. The line begins at one
set of co-ordinates and ends at another. Likewise, center_point is the origin point
of a circle.

21

Pygame drawing functions

+ pygame.draw.polygon(surface, color, pointlist, width)


+ pygame.draw.line(surface, color, start_point, end_point, width)
+ pygame.draw.lines(surface, color, closed, pointlist, width)
+ pygame.draw.circle(surface, color, center_point, radius, width)
+ pygame.draw.ellipse(surface, color, bounding_rectangle, width)
+ pygame.draw.rect(surface, color, rectangle_tuple, width)

22

11
11/30/22

Frames per second

+ By default, if we do not create a limitation the computer will


execute the game loop as many times as in can within a
second. To limit it we use the tick(fps) method where fps is an
integer. The tick() method belongs to
the pygame.time.Clock class and must be used with an object
of this class.
+ FPS = pygame.time.Clock()
+ FPS.tick(60)

23

Putting together the concepts

+ This isn’t a game, but we’re just going to be creating


some random shapes, using colors, fills and setting up a
display just to get you a little familiar with things before
we proceed.

24

12
11/30/22

+ import pygame, sys


+ from pygame.locals import *
+ pygame.init() # Initialize program
+ FPS = 30 # Assign FPS a value
+ FramePerSec = pygame.time.Clock() # Setting up color objects
+ BLUE = (0, 0, 255)
+ RED = (255, 0, 0)
+ GREEN = (0, 255, 0)
+ BLACK = (0, 0, 0)
+ WHITE = (255, 255, 255)
+ # Setup a 300x300 pixel display with caption
+ DISPLAYSURF = pygame.display.set_mode((300,300))
+ DISPLAYSURF.fill(WHITE)
+ pygame.display.set_caption("Example")

25

+ # Creating Lines and Shapes


+ pygame.draw.line(DISPLAYSURF, BLUE, (150,130), (130,170))
+ pygame.draw.line(DISPLAYSURF, BLUE, (150,130), (170,170))
+ pygame.draw.line(DISPLAYSURF, GREEN, (130,170), (170,170))
+ pygame.draw.circle(DISPLAYSURF, BLACK, (100,50), 30)
+ pygame.draw.circle(DISPLAYSURF, BLACK, (200,50), 30)
+ pygame.draw.rect(DISPLAYSURF, RED, (100, 200, 100, 50), 2)
+ pygame.draw.rect(DISPLAYSURF, BLACK, (110, 260, 80, 5))
+
+ while True: # Beginning Game Loop
+ pygame.display.update()
+ for event in pygame.event.get():
+ if event.type == QUIT:
+ pygame.quit()
+ sys.exit()
+ FramePerSec.tick(FPS)

26

13
11/30/22

Game Creation – Part 1

+ Whether it’s GUI, Pygame or any other large application, the


Classes approach (OOP) is almost always the best idea.
+ The approach we used earlier was fine because our program
was small, and there wasn’t anything that required repetition
or needed to be reused.
+ Using Classes, we’ll be using methods to store blocks of code
that are to be repeated several times throughout the game.

27

Get the Beta Version from Materials


on InforEstudante
+ It’s not yet complete, but the foundation has been set.
+ Then we will explain and test every part of the equation.

28

14
11/30/22

Player

+ class Player(pygame.sprite.Sprite):
+ def __init__(self):
+ super().__init__()
+ self.image = pygame.image.load("Player.png")
+ self.rect = self.image.get_rect()
+ self.rect.center = (160, 520)

29

Player

+ The benefit of using classes here is that we can spawn


multiple entities from the same block of code.
+ This doesn’t apply to the Player Class, since most games
will only have one player.
+ But it does apply to the Enemy Class as most games will
have multiple enemies.

30

15
11/30/22

Player

+ Passing pygame.sprite.Sprite into the parameters,makes


the Player Class it’s child class.
+ Passing super().init() then calls the init() function of
the Sprite class. super().__init__() is a whole different
concept related to Classes in Python.

31

Player – image.load()

+ image.load() function to which we pass the file path of our


image.
+ Note, this does not define the borders for our Player Sprite.
+ This is instead done using the get_rect() function.
+ This function is able to automatically create a rectangle of the
same size as the image.
+ This will be using this in Collision Detection.

32

16
11/30/22

Player

+ The last line, self.rect.center, defines a starting position


for the Rect.
+ Later we’ll use the Rect’s coordinates to draw the image
to the exact same location.

+ Position (160,520)

33

Movement

+ We need a method from the Player class that controls the


movement of the player.
+ When this function is called, the checks to see if any keys
are pressed down or not.

34

17
11/30/22

+ def update(self):
+ pressed_keys = pygame.key.get_pressed()
+ #if pressed_keys[K_UP]:
+ #self.rect.move_ip(0, -5)
+ #if pressed_keys[K_DOWN]:
+ #self.rect.move_ip(0,5)
+
+ if self.rect.left > 0:
+ if pressed_keys[K_LEFT]:
+ self.rect.move_ip(-5, 0)
+ if self.rect.right < (SCREEN_WIDTH):
+ if pressed_keys[K_RIGHT]:
+ self.rect.move_ip(5, 0)

35

Movement

+ The two if statements, if self.rect.left > 0: and if


self.rect.left > 0: ensure that the player isn’t able to move
off screen.
+ Two of the if statements are commented out because
this is a side scroller game. We don’t need up and down
movement here. We only included them to show you
how it would be done.

36

18
11/30/22

Draw the image after movement

+ def draw(self, surface):


+ surface.blit(self.image, self.rect)

+ the blit() takes two inputs, the first the surface to be drawn to and second,
the object.
+ Normally we would write surface.blit(self.surf, self.rect) since we’re
drawing the rectangle to the surface we’ve defined.
+ But since we’re using an image, we pass self.image instead of self.surf.

37

Surfaces

+ Surfaces play an important role in Pygame.


+ We can not cover all the details in this course.
+ Therefore, you should read it if you’ve had any difficulty
understanding surfaces, the blit() function or anything
related to it.

38

19
11/30/22

Enemy

+ class Enemy(pygame.sprite.Sprite):
+ def __init__(self):
+ super().__init__()
+ self.image = pygame.image.load("Enemy.png")
+ self.rect = self.image.get_rect()
+ self.rect.center = (random.randint(40,SCREEN_WIDTH-40), 0)

39

Player vs Enemy

+ The only change is with the last line, where we included


randomized starting points.
+ (It would be pretty boring if the Enemy appeared from
the same location each time)

40

20
11/30/22

Move the Enemy

+ def move(self):
+ self.rect.move_ip(0,10)
+ if (self.rect.top > 600):
+ self.rect.top = 0
+ self.rect.center = (random.randint(30, 370), 0)

41

Move the Enemy

+ We need a method to move the enemy


+ We can call the move_ip() function, moving the Enemy object
down by 10 pixels.
+ Next it checks to see if the top of the Enemy has reached the
end of the screen.
+ If True, it resets it back to the top of screen and at a random
location on the X axis.

42

21
11/30/22

Game Loop

+ First, during the game loop we need to update and move functions
for both the Enemy and Player class are called.
+ Second, we refresh the screen using
the DISPLAY.fill(WHITE) function.
+ Third, we call the draw functions for both the Player and Enemy
objects, drawing them to the screen.
+ Finally, the pygame.display.update() command updates the screen
with all the commands that have occurred up-till this point, and
the tick() makes sure it repeats only 60 times per second.

43

Game loop

+ P1.update()
+ E1.move()
+ DISPLAYSURF.fill(WHITE)
+ P1.draw(DISPLAYSURF)
+ E1.draw(DISPLAYSURF)
+ pygame.display.update()
+ FramePerSec.tick(FPS)

44

22
11/30/22

Part II – Sprite
groups, User
events, Colision
detection

45

Pygame – Part II

+ In the current version, our game is boring.


+ No variation on enemies’ speed.
+ No game over when colliding with enemy.

+ So, please kindly check betaVersion2 in InforEstudante

46

23
11/30/22

Creating Sprites Groups

+ enemies = pygame.sprite.Group()
+ enemies.add(E1)
+ all_sprites = pygame.sprite.Group()
+ all_sprites.add(P1)
+ all_sprites.add(E1)

47

Creating Sprites Groups

+ A Sprite group is sort of like a classification. It’s much easier to


deal with 2 or 3 groups, rather than having to deal with
dozens or even hundreds of sprites. Keeping them in one
group allows us to easily access every sprite in that group.
+ We will create two groups one called enemy and the other
called all_sprites.
+ To add a Sprite to a group, you just have to use
the add() function.

48

24
11/30/22

User events

+ Pygame gives us the option to create custom events called


“User events”.
+ We can create an event called INC_SPEED.
+ We need to call the pygame.USEREVENT and added one into
it (to ensure that it will have a unique ID).
+ Next we use the Pygame time module’s set_timer() function to
call the INC_SPEED event object every 1000 milliseconds, or
1 second.

49

User events

+ INC_SPEED = pygame.USEREVENT + 1
+ pygame.time.set_timer(INC_SPEED, 1000)

50

25
11/30/22

Handle User Events

+ In the for loop where we iterate over every event that


occurs, we insert an if statement to check for the
INC_SPEED event occurring.
+ If it does, we increase the SPEED variable by 2.
+ This variable us used by the Enemy class to determine its
speed.

51

Handle User Events

+ while True:
+ for event in pygame.event.get():
+ if event.type == INC_SPEED:
+ SPEED += 2

52

26
11/30/22

Collision detection in pygame

+ The spritecollideany() function takes two parameters, the first must be a regular
Sprite, like P1 or E1.
+ The second must be a Sprite group, such as Enemies or all_sprites.
+ This function compares the sprite passed in the first parameter, to see if it’s
touching any of the sprites in the group passed in parameter two.
+ In our case, it checks to see whether our Player has collided with any of the sprites
in the enemies group.
+ The benefit of this function is that even if there are 1000 enemy sprites, we don’t
have to check collisions with them individually, and instead just use this function.

53

Collision detection in pygame

+ Finally, the collision holds True, we kill all the sprites


using the kill() function, fill the screen with red, wait two
seconds and close the entire program.
+ (Calling kill() will remove the sprite from the group,
hence it will no longer be drawn to the screen. If you
don’t use groups, and try kill() on a sprite, you might not
get the desired effect.

54

27
11/30/22

Collision detection in pygame

+ for entity in all_sprites:


+ DISPLAYSURF.blit(entity.image, entity.rect)
+ entity.move()

+ Yet another benefit of the grouping system, we can now call the “move”
functions for all the sprites and redraw them in just 3 lines of code.
+ We’ve removed the two draw() functions from both the Player and Enemy
class in our code.

55

Part III –
backgrounds, sound, fonts and
a scoring system

56

28
11/30/22

Pygame – Part III

+ Now, we’re going to


cover backgrounds, sound, fonts and a scoring system.
+ These are all important features in a game, to make it a
complete product.
+ Please get BetaVersion III from InforEstudante

57

Fonts

+ We can create two different fonts, font and font_small which


both have the same font family, but different font sizes.
+ Next, we use the render() function to create the graphics for
the Font of our choice.
+ We also must pass in the text we wish to be displayed and the
color we want it to be in.
+ In this case, “Game Over” and BLACK respectively.

58

29
11/30/22

Fonts

+ #Setting up Fonts
+ font = pygame.font.SysFont("Verdana", 60)
+ font_small = pygame.font.SysFont("Verdana", 20)
+ game_over = font.render("Game Over", True, BLACK)

59

Fonts

+ The low soze font will be used for scoring purposes.


+ We didn’t do this earlier because this font is meant to be rendered
inside Game loop as it has a continuously changing value.
+ We moved the game_over font rendering out of the loop to avoid
unnecessary performance loss.
+ Finally, we display both fonts using the blit() function. In it’s first
parameter we pass the rendered font and in the second we pass a
pair of co-ordinates which mark the origin point of the font.

60

30
11/30/22

Game Loop

+ #Game Loop
+ while True:
+
+ scores = font_small.render(str(SCORE), True, BLACK)
+ DISPLAYSURF.blit(scores, (10,10))
+ ...
+ if pygame.sprite.spritecollideany(P1, enemies):
+ ...
+ DISPLAYSURF.blit(game_over, (30,250))

61

Background

+ There are two steps to creating a background.


+ First you load the image (outside the game loop for performance)
and then proceed to draw the image using the blit() function.
The blit() function must be in the game loop as it needs to re draw
itself as the other objects move.
+ What’s also important, is that the background is the first thing that’s
drawn.
+ Pygame has a layer system, where if you aren’t careful, you will draw
the background over all the other sprites.

62

31
11/30/22

Background

+ background = pygame.image.load("AnimatedStreet.png")
+ ...
+ while True:
+ ...
+ DISPLAYSURF.blit(background, (0,0))
+ ...
+ #Moves and Re-draws all Sprites
+ for entity in all_sprites:
+ DISPLAYSURF.blit(entity.image, entity.rect)
+ entity.move()

63

Sound

+ Here we are using a simple one line function from


the Pygame Mixer library to play a crash sound once
collision has occurred.
+ Pygame.mixer.Sound() is used to load the sound into
Pygame, while play() is used to actually “play” it.

64

32
11/30/22

Sound

+ #To be run if collision occurs between Player and Enemy


+ if pygame.sprite.spritecollideany(P1, enemies):
+ pygame.mixer.Sound('crash.wav').play()
+ time.sleep(0.5)
+
+ DISPLAYSURF.fill(RED)
+ DISPLAYSURF.blit(game_over, (30,250))

65

Result

66

33
11/30/22

Disclaimer

+ This tutorial is based on the materials provided in Python


pygame – The Full Tutorial available on
https://coderslegacy.com/python/python-pygame-
tutorial/

67

34

You might also like