It's cool to play zombie game in Python

Introduction to the game

In the past, the popular zombie game of plant vs. zombie, I wanted to find a python version of the game to learn, but I didn't find a more complete one, so I'll write one myself. Image resources are downloaded from github, because image resources are limited, only a few plants and zombies can be realized.
The functions are as follows:

 

Supported plant types: sunflower, pea shooter, ice shooter, nut, cherry bomb. New plants: Double pea shooter, triple pea shooter.
Supported zombie types: ordinary zombie, chess zombie, roadblock zombie, bucket zombie.
Use the json file to save the level information and set the time and location of zombies.
New lawn mower.
Here is a screenshot of the game:
In addition, you should pay attention to: whether you are for Python employment or hobbies, remember: project development experience is always the core. If you don't have the latest Python introduction to advanced practical video tutorials in 2020, you can go to the small Python exchange : you can find a lot of new Python tutorial projects under the transformation of "seven clothes, nine seven buses and five numbers" (homophony of numbers). You can also communicate with the old driver for advice!

Figure 2

 

 

Picture display switch


As can be seen from Figure 1 and Figure 2, the image display of zombies will be different when they walk and attack. This article will talk about how to switch the image display.
Take the roadblock zombies above as an example. There are several types of pictures below.

  • Walking with barricades
  • Attack with roadblocks
  • Walking without barricades (i.e. turning into ordinary zombie walking)
  • Attacks without roadblocks (i.e. attacks that become normal zombies)
  • Walking without head
  • Headless attack
  • death

Figure 3 is an example of these seven image types of roadblock zombies

 

Picture loading

The picture resources of zombies in plant wars are quite special. Each action of a picture type is a separate picture, as shown in Figure 4, the action picture of zombies attacking with roadblocks, with a total of 11 pictures, so the code to load the pictures should be modified accordingly.

 

 

Full code

github link of game implementation code Plants V.S. Zombies
Here is the download link of csdn Plants V.S. Zombies

Picture loading
In source\tool.py, the load? All? Gfx function traverses the resources\graphics directory and subdirectories.
A simple distinction is made in the code:

  • If it is a picture in the resources\graphics\subfolder \ directory, it is a separate picture, such as the interface picture in the resources\graphics\Screen directory
  • If it is a subdirectory in the resources\graphics\subfolder \ directory, all the pictures in this subdirectory or subdirectory belong to one picture type. For example, in the resources\graphics\Zombies\ConeheadZombie\ConeheadZombieAttack directory, there are action pictures of roadblock zombie attacking with roadblock, as shown in Figure 4.
 1 def load_all_gfx(directory, colorkey=c.WHITE, accept=('.png', '.jpg', '.bmp', '.gif')):
 2     graphics = {}
 3     for name1 in os.listdir(directory):
 4         # subfolders under the folder resources\graphics
 5         dir1 = os.path.join(directory, name1)
 6         if os.path.isdir(dir1):
 7             for name2 in os.listdir(dir1):
 8                 dir2 = os.path.join(dir1, name2)
 9                 if os.path.isdir(dir2):
10                 # e.g. subfolders under the folder resources\graphics\Zombies
11                     for name3 in os.listdir(dir2):
12                         dir3 = os.path.join(dir2, name3)
13                         # e.g. subfolders or pics under the folder resources\graphics\Zombies\ConeheadZombie
14                         if os.path.isdir(dir3):
15                             # e.g. it's the folder resources\graphics\Zombies\ConeheadZombie\ConeheadZombieAttack
16                             image_name, _ = os.path.splitext(name3)
17                             graphics[image_name] = load_image_frames(dir3, image_name, colorkey, accept)
18                         else:
19                             # e.g. pics under the folder resources\graphics\Plants\Peashooter
20                             image_name, _ = os.path.splitext(name2)
21                             graphics[image_name] = load_image_frames(dir2, image_name, colorkey, accept)
22                             break
23                 else:
24                 # e.g. pics under the folder resources\graphics\Screen
25                     name, ext = os.path.splitext(name2)
26                     if ext.lower() in accept:
27                         img = pg.image.load(dir2)
28                         if img.get_alpha():
29                             img = img.convert_alpha()
30                         else:
31                             img = img.convert()
32                             img.set_colorkey(colorkey)
33                         graphics[name] = img
34     return graphics
35 
36 GFX = load_all_gfx(os.path.join("resources","graphics"))Copy code
 

 

The load image frames function saves all the pictures in the directory in the tmp dictionary according to the index value in the picture name as key. For example, if the image name is "coneheadzombieatack_", its index value is 2.
Then add the image to the frame list according to the index value.

 

 
 1 def load_image_frames(directory, image_name, colorkey, accept):
 2     frame_list = []
 3     tmp = {}
 4     # image_name is "Peashooter", pic name is 'Peashooter_1', get the index 1
 5     index_start = len(image_name) + 1 
 6     frame_num = 0;
 7     for pic in os.listdir(directory):
 8         name, ext = os.path.splitext(pic)
 9         if ext.lower() in accept:
10             index = int(name[index_start:])
11             img = pg.image.load(os.path.join(directory, pic))
12             if img.get_alpha():
13                 img = img.convert_alpha()
14             else:
15                 img = img.convert()
16                 img.set_colorkey(colorkey)
17             tmp[index]= img
18             frame_num += 1
19 
20     for i in range(frame_num):
21         frame_list.append(tmp[i])
22     return frame_listCopy code
 

 

Picture display switch
In source\component\zombie.py, Zombie class is the parent class of all Zombie classes. The initialization function calls loadImages function to load all supported image types, and sets Sprite sprite class to display the required member variables image and rect.
The loadFrames function is called to specific subclasses to get pictures.

 1 class Zombie(pg.sprite.Sprite):
 2     def __init__(self, x, y, name, health, head_group=None, damage=1):
 3         pg.sprite.Sprite.__init__(self)
 4         
 5         self.name = name
 6         self.frames = []
 7         self.frame_index = 0
 8         self.loadImages()
 9         self.frame_num = len(self.frames)
10 
11         self.image = self.frames[self.frame_index]
12         self.rect = self.image.get_rect()
13         self.rect.centerx = x
14         self.rect.bottom = y
15         ...
16 
17     def loadFrames(self, frames, name, image_x):
18         frame_list = tool.GFX[name]
19         rect = frame_list[0].get_rect()
20         width, height = rect.w, rect.h
21         width -= image_x
22 
23         for frame in frame_list:
24             frames.append(tool.get_image(frame, image_x, 0, width, height))Copy code
 

 

The basic functions are implemented in the Zombie parent class. If the child class has special requirements, the function with the same name can be redefined.

Update function: each tick will call the entry function to update the location of zombies, switch status and update the image display.
handleState function: performs different functions based on the current state of the zombie.
Animation function: displays the next action of the picture type every specified animation interval time.

 1     def update(self, game_info):
 2         self.current_time = game_info[c.CURRENT_TIME]
 3         self.handleState()
 4         self.animation()
 5     
 6     def handleState(self):
 7         if self.state == c.WALK:
 8             self.walking()
 9         elif self.state == c.ATTACK:
10             self.attacking()
11         elif self.state == c.DIE:
12             self.dying()
13     
14     def animation(self):
15         if (self.current_time - self.animate_timer) > self.animate_interval:
16             self.frame_index += 1
17             if self.frame_index >= self.frame_num:
18                 if self.state == c.DIE:
19                     self.kill()
20                     return
21                 self.frame_index = 0
22             self.animate_timer = self.current_time
23         
24         self.image = self.frames[self.frame_index]Copy code
 

 

The following four functions are to modify the current status and image display of zombies.

  • setWalk function: change to walking state, the picture display will set different picture types according to different values.
  • setAttack function: modify to attack state, and the picture display will set different picture types according to different values.
  • setDie function: change to dead state.
  • changeFrames function: after modifying the picture type, you need to reset the values of the member variables frame_num, frame_index, image and rect.
 
 1  def setWalk(self):
 2         self.state = c.WALK
 3         self.animate_interval = 150
 4         
 5         if self.helmet:
 6             self.changeFrames(self.helmet_walk_frames)
 7         elif self.losHead:
 8             self.changeFrames(self.losthead_walk_frames)
 9         else:
10             self.changeFrames(self.walk_frames)
11 
12     def setAttack(self, plant):
13         self.plant = plant
14         self.state = c.ATTACK
15         self.animate_interval = 100
16         
17         if self.helmet:
18             self.changeFrames(self.helmet_attack_frames)
19         elif self.losHead:
20             self.changeFrames(self.losthead_attack_frames)
21         else:
22             self.changeFrames(self.attack_frames)
23     
24     def setDie(self):
25         self.state = c.DIE
26         self.animate_interval = 200
27         self.changeFrames(self.die_frames)
28     
29     def changeFrames(self, frames):
30         '''change image frames and modify rect position'''
31         self.frames = frames
32         self.frame_num = len(self.frames)
33         self.frame_index = 0
34         
35         bottom = self.rect.bottom
36         centerx = self.rect.centerx
37         self.image = self.frames[self.frame_index]
38         self.rect = self.image.get_rect()
39         self.rect.bottom = bottom
40         self.rect.centerx = centerxCopy code
 

 

The roadblock zombie class is relatively simple. You only need to implement the loadImages function and call the loadFrames function to load the image types supported by the zombie. The main difference here is that the names of different types of zombies will be different.

 
 1 class ConeHeadZombie(Zombie):
 2     def __init__(self, x, y, head_group):
 3         Zombie.__init__(self, x, y, c.CONEHEAD_ZOMBIE, c.CONEHEAD_HEALTH, head_group)
 4         self.helmet = True
 5 
 6     def loadImages(self):
 7         self.helmet_walk_frames = []
 8         self.helmet_attack_frames = []
 9         self.walk_frames = []
10         self.attack_frames = []
11         self.losthead_walk_frames = []
12         self.losthead_attack_frames = []
13         self.die_frames = []
14         
15         helmet_walk_name = self.name
16         helmet_attack_name = self.name + 'Attack'
17         walk_name = c.NORMAL_ZOMBIE
18         attack_name = c.NORMAL_ZOMBIE + 'Attack'
19         losthead_walk_name = c.NORMAL_ZOMBIE + 'LostHead'
20         losthead_attack_name = c.NORMAL_ZOMBIE + 'LostHeadAttack'
21         die_name = c.NORMAL_ZOMBIE + 'Die'
22 
23         frame_list = [self.helmet_walk_frames, self.helmet_attack_frames,
24                       self.walk_frames, self.attack_frames, self.losthead_walk_frames,
25                       self.losthead_attack_frames, self.die_frames]
26         name_list = [helmet_walk_name, helmet_attack_name,
27                      walk_name, attack_name, losthead_walk_name,
28                      losthead_attack_name, die_name]
29         
30         for i, name in enumerate(name_list):
31             self.loadFrames(frame_list[i], name, tool.ZOMBIE_RECT[name]['x'])
32 
33         self.frames = self.helmet_walk_frames

This is the Python code. Note: whether you are for Python employment or hobbies, remember: project development experience is always the core. If you don't have the latest Python introduction to the advanced practical video tutorial in 2020, you can go to the small Python exchange : you can find a lot of new Python tutorial projects under the transformation of "seven clothes, nine seven buses and five numbers" (homophony of numbers). You can also exchange and consult with the old drivers!

The text and pictures of this article come from the Internet and my own ideas. They are only for learning and communication. They have no commercial use. The copyright belongs to the original author. If you have any questions, please contact us in time for handling.

Tags: Python github JSON

Posted on Tue, 05 May 2020 13:51:01 -0400 by happyness