One skill a day: How easy it is to make games with Python

Original link: https://www.kingname.info/2022/05/22/learn-pygame/

After I posted the picture of my 520 official account, many students asked me how to make this game, is it difficult? I will use two articles to introduce, if you use Python to make games.

This game is made using PyGame, and the texture material is found from itch.io. I have never used PyGame before. This time I am learning and using it now. The reference tutorial is PyGame: A Primer on Game Programming in Python .

Making games with PyGame is very simple. Our first article today will let you implement a pig that can move on the map.

basic framework

First of all, no matter what game you are doing, don’t worry about 3721, copy and paste the following code into your editor first. All games require these lines of code:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 import pygame


def main () :
pygame.init()
pygame.display.set_caption( 'Unheard Code: A game made by Qingnan' ) # Game title
win = pygame.display.set_mode(( 800 , 600 )) # Window size, width 800 height 600
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT: # Stop the program when you click the x in the upper left or upper right corner to close the window
running = False


main()

The operation effect is shown in the following figure:

Load material

Now, let’s randomly find two pictures, one for the background and one for the protagonist. Don’t worry too much about the size, it’s almost fine, because we can dynamically adjust it with code. The following two pictures are the materials I found casually. Please pay attention to the place enclosed by the red frame in the picture, which is the size of these two pictures.

We use the following code to load the image:

 1
 img_surf = pygame.image.load( 'image address' ).convert_alpha()

The .convert_alpha() is to preserve the transparent background of the png image. If the image you loaded is not a png image, you can change convert_alpha() to convert() .

If you want to modify the image size, use the following code:

 1
 img_surf = pygame.transform.scale(img_surf, (width, height))

To display the image in the window, use the following two lines of code:

 1
2
 win.blit(material object, (the abscissa of the upper left corner of the material, the ordinate of the upper left corner of the material))
pygame.display.flip()

The complete code is as follows:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
twenty one
twenty two
 import pygame


def main () :
pygame.init()
pygame.display.set_caption( 'Unheard Code: A game made by Qingnan' ) # Game title
win = pygame.display.set_mode(( 800 , 600 )) # window size
bg_small = pygame.image.load( 'bg.png' ).convert_alpha()
bg_big = pygame.transform.scale(bg_small, ( 800 , 600 ))
pig = pygame.image.load( 'pig_in_car.png' ).convert_alpha()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT: # Stop the program when you click the x in the upper left or upper right corner to close the window
running = False

win.blit(bg_big, ( 0 , 0 )) # The background image is loaded first, and the coordinates are (left, top)
win.blit(pig, ( 200 , 300 ))
pygame.display.flip()


main()

The operation effect is shown in the following figure:

It should be noted that win.blit and pygame.display.flip() are placed inside the while loop. where the first parameter of win.blit is the material object we just loaded. The second parameter is a tuple, marking the coordinates of the upper left corner of the image on the canvas. The upper left corner of the entire canvas corresponds to the coordinates (0, 0) . Since the size of the background image is also (800, 600) , the upper left corner of the background image is placed (0, 0) , which can just cover the entire canvas.

Where can I find materials?

What we are doing is a pixel style game, you can find materials on itch.io :

This site improves a lot of game material, and most of the material is free for personal non-commercial use. After you find the material you like, you can download it directly, and you don’t even need to log in during the whole process (more conscience than domestic junk material websites).

Why does my material look like this?

After you download the material, you may find a very strange thing, how come all the materials are drawn on one picture?

In fact, this is the industry practice. The person who makes the material will arrange each type of material on a picture. When you want to use it, you need to cut it yourself. For example, all plants on one map, all statues on one map, and foundation textures on one map.

The background image we used for the demo above looks like a green image at first glance, but it actually contains multiple foundation elements. Please note the part I framed in red:

In the official game, we have to take out every basic element and put it together again. When reorganizing, some elements need to be copied and reused, and some elements need to be rotated and scaled. Finally combined into the following map that looks好看:

Generally speaking, the size of pixel style material is mostly 16x16 , 32x32 , 64x64 , 128x128 . Material authors normally provide cropping instructions. If not provided, you can also look at it with the naked eye and take a guess.

For example, I want to cut out the red framed goddess from the statue material:

So, I can write code like this:

 1
2
 img_surf = pygame.image.load( 'Statue material.png' ).convert_alpha()
goddess= img_surf.subsurface(( the abscissa of the upper left corner of the goddess, the ordinate of the upper left corner of the goddess, the width of the goddess, the height of the goddess))

The operation effect is shown in the following figure:

Some students may ask: Why are the coordinates of the goddess like this? I can only say that this coordinate is what I have tried many times and tried out.

Use sprites to manage objects

Except for the background image, every element we add is an object, such as the pig and the goddess above. In principle, the above code is enough for you to make the game beautiful. If you want to add something, just keep loading the picture material, and then put it in the right place.

But we can use object-oriented design methods to make the code easier to maintain and simpler. In PyGame, there is a class called Sprite . We can implement a class for each object, inherit Sprite , and then set the material of the object to the .surf property and the position of the object to the .rect property. For example, the above code, let’s modify it:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
twenty one
twenty two
twenty three
twenty four
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
 import pygame


class Bg (pygame.sprite.Sprite) :
def __init__ (self) :
super(Bg, self).__init__()
bg_small = pygame.image.load( 'bg.png' ).convert_alpha()
grass_land = bg_small.subsurface(( 0 , 0 , 128 , 128 ))
self.surf = pygame.transform.scale(grass_land, ( 800 , 600 ))
self.rect = self.surf.get_rect(left= 0 , top= 0 ) # upper left corner positioning


class Pig (pygame.sprite.Sprite) :
def __init__ (self) :
super(Pig, self).__init__()
self.surf = pygame.image.load( 'pig_in_car.png' ).convert_alpha()
self.rect = self.surf.get_rect(center=( 400 , 300 )) # center positioning


class Goddess (pygame.sprite.Sprite) :
def __init__ (self) :
super(Goddess, self).__init__()
building = pygame.image.load( 'building.png' ).convert_alpha()
self.surf = building.subsurface((( 7 * 64 - 10 , 0 , 50 , 100 )))
self.rect = self.surf.get_rect(center=( 500 , 430 )) # The center of the goddess is placed on the canvas (500, 430)


def main () :
pygame.init()
pygame.display.set_caption( 'Unheard Code: A game made by Qingnan' ) # Game title
win = pygame.display.set_mode(( 800 , 600 )) # window size

bg = Bg()
goddess = goddess()
pig = Pig()
all_sprites = [bg, goddess, pig] # Pay attention to the order of addition, the layer of the object added later is above the layer of the object added first

running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT: # Stop the program when you click the x in the upper left or upper right corner to close the window
running = False

for sprite in all_sprites:
win.blit(sprite.surf, sprite.rect)
pygame.display.flip()


if __name__ == '__main__' :
main()

The operation effect is shown in the following figure:

Note all_sprites = [bg, goddess, pig] in the code, here I am using a list. Later there will be a more advanced data structure SpriteGroup to store them. Using a list is enough today.

素材对象.get_rect() will return a coordinate positioning object, which has multiple properties, such as .left , .width , .center , .top , .height . In the case of no parameters, the default .left=0 .top=0 , .top=0 , PyGame will automatically calculate .width , .height and .center according to the size of this object. We can actively set it in the form of incoming parameters. When you set the upper left corner, it can automatically calculate the coordinates of the center point; when you pass in the center coordinates, it can automatically calculate the coordinates of the upper left corner.

In theory, within each class, the material object can have any name, not necessarily .surf . The coordinate positioning object does not have to use .rect , as long as you correspond to it in win.blit . But if you use .surf and .rect will give you a lot of benefits. This point we will talk about the place where the object collides. So I suggest you just use both names.

make the pig move

Since it is a game, you must press the keyboard to make the protagonist move. Otherwise, what’s the difference with a painting? Everyone pay attention to the while running loop in the main() function. If you add a line of code to the loop: print(111) , you will find that when you run the game, 111 will be continuously printed out.

In essence, PyGame is to continuously draw pictures through win.blit . Since this while loop runs many times per second, if every time it runs, we let the second parameter of win.blit , that is, the coordinates of the material object have Subtle differences, then to the human eye, the material object is moving.

Our goal is to hold down the up, down, left, and right arrow keys on the keyboard, and the piglet moves in 4 different directions. In PyGame, get the key that the keyboard presses and hold, and use the following code to achieve:

 1
 keys = pygame.key.get_pressed()

It returns an object that looks like a list (but not a list). When we want to judge whether a key is pressed, we only need to judge if keys[想要判断的键] , and if it returns True , it means that the key is pressed. Press and hold. Based on this principle, let’s write two pieces of code. First modify the Pig class and add a .update method:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
twenty one
twenty two
twenty three
twenty four
25
 class Pig (pygame.sprite.Sprite) :
def __init__ (self) :
super(Pig, self).__init__()
self.surf = pygame.image.load( 'pig_in_car.png' ).convert_alpha()
self.rect = self.surf.get_rect(center=( 400 , 300 )) # center positioning

def update (self, keys) :
if keys[pygame.K_LEFT]:
self.rect.move_ip(( -5 , 0 )) # abscissa to the left
elif keys[pygame.K_RIGHT]:
self.rect.move_ip(( 5 , 0 )) # abscissa to the right
elif keys[pygame.K_UP]:
self.rect.move_ip(( 0 , -5 )) #The ordinate is up
elif keys[pygame.K_DOWN]:
self.rect.move_ip(( 0 , 5 )) # ordinate down

# Prevent piggy from going outside the screen
if self.rect.left < 0 :
self.rect.left = 0
if self.rect.right > 800 :
self.rect.right = 800
if self.rect.top < 0 :
self.rect.top = 0
if self.rect.bottom > 600 :
self.rect.bottom = 600

The .update method receives a parameter keys , which is the list-like object returned by the key we pressed. Then determine which direction key was pressed. Based on the pressed key, the .rect coordinate positioning object modifies the value of the corresponding direction. rect.move_ip The ip here is the abbreviation of inplace , which is to modify the .rect attribute itself. Its argument is a tuple corresponding to the abscissa and ordinate. If the horizontal and vertical coordinates are less than 0, it means to the left or up, and if it is greater than 0, it means to the right or down.

The original main() function only needs to add two lines of code before win.blit :

 1
2
 keys = pygame.key.get_pressed()
pig.update(keys)

The complete code is as follows:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
twenty one
twenty two
twenty three
twenty four
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
 import pygame


class Bg (pygame.sprite.Sprite) :
def __init__ (self) :
super(Bg, self).__init__()
bg_small = pygame.image.load( 'bg.png' ).convert_alpha()
grass_land = bg_small.subsurface(( 0 , 0 , 128 , 128 ))
self.surf = pygame.transform.scale(grass_land, ( 800 , 600 ))
self.rect = self.surf.get_rect(left= 0 , top= 0 ) # upper left corner positioning


class Pig (pygame.sprite.Sprite) :
def __init__ (self) :
super(Pig, self).__init__()
self.surf = pygame.image.load( 'pig_in_car.png' ).convert_alpha()
self.rect = self.surf.get_rect(center=( 400 , 300 )) # center positioning

def update (self, keys) :
if keys[pygame.K_LEFT]:
self.rect.move_ip(( -5 , 0 ))
elif keys[pygame.K_RIGHT]:
self.rect.move_ip(( 5 , 0 ))
elif keys[pygame.K_UP]:
self.rect.move_ip(( 0 , -5 ))
elif keys[pygame.K_DOWN]:
self.rect.move_ip(( 0 , 5 ))

# Prevent piggy from going outside the screen
if self.rect.left < 0 :
self.rect.left = 0
if self.rect.right > 800 :
self.rect.right = 800
if self.rect.top < 0 :
self.rect.top = 0
if self.rect.bottom > 600 :
self.rect.bottom = 600


class Goddess (pygame.sprite.Sprite) :
def __init__ (self) :
super(Goddess, self).__init__()
building = pygame.image.load( 'building.png' ).convert_alpha()
self.surf = building.subsurface((( 7 * 64 - 10 , 0 , 50 , 100 )))
self.rect = self.surf.get_rect(center=( 500 , 430 )) # The center of the goddess is placed on the canvas (500, 430)


def main () :
pygame.init()
pygame.display.set_caption( 'Unheard Code: A game made by Qingnan' ) # Game title
win = pygame.display.set_mode(( 800 , 600 )) # window size

bg = Bg()
goddess = goddess()
pig = Pig()
all_sprites = [bg, goddess, pig] # Pay attention to the order of addition, the layer of the object added later is above the layer of the object added first

running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT: # Stop the program when you click the x in the upper left or upper right corner to close the window
running = False

keys = pygame.key.get_pressed()
pig.update(keys)
for sprite in all_sprites:
win.blit(sprite.surf, sprite.rect)
pygame.display.flip()


if __name__ == '__main__' :
main()

The final running effect is shown in the following video:

Summarize

PyGame is really very simple to make games. As long as you can load the materials, you can make a game that can still be seen. Today we learned how to add material and how to capture keyboard events.

PyGame can read Gif images, but you will find that after loading, the Gif will not move. In the next article, let’s talk about how to make the character you control move, such as controlling a small doll, when it moves, its feet also move. And object collision detection.

This article is reprinted from: https://www.kingname.info/2022/05/22/learn-pygame/
This site is for inclusion only, and the copyright belongs to the original author.

Leave a Comment