Use Python to implement Plant Wars Zombie Code!

Keywords: Python github JSON

Preface

The text and pictures in this article are from the Internet. They are for study and communication only. They do not have any commercial use. The copyright is owned by the original author. If you have any questions, please contact us in time for processing.

Author: marble_xu

GitHub address: https://github.com/marblexu/PythonPlantsVsZombies

PS: If you need Python learning materials for your child, click on the link below to get them

http://note.youdao.com/noteshare?id=3054cce4add8a909e784ad934f956cef

Functional introduction

Recently, new plants and zombies have been added to this plant Wars zombie game because of limited Online Photo resources and the fact that fewer plants and zombies can be added. Progress is as follows.

The functions are as follows:

  • Supported plant types: Sunflower, Pea Shooter, Ice Shooter, Nuts, Cherry Bomb.New plants added: double pea shooter, triple pea shooter, cannibals, small mushrooms, potato mines, zucchini.

  • Supported types of zombies: ordinary zombies, chess zombies, roadblock zombies, barrel zombies.Add a new newspaper reading zombie.

  • Use a json file to save level information and set the time and location of zombies.

  • Increase the selection of plants on the field at the beginning of each level.

  • Add a weeder.

Here is a screenshot of the game:

Plant Card Selection and Planting

As shown in the diagram, there are 45 squares (five rows, nine columns each) in which plants can be planted in the game.

This article is about:

  • Implementation of the upper plant card bar.

  • Click on the plant card and switch the mouse to a picture of the plant.

  • As the mouse moves, determine which square is currently in and display translucent plants as a hint.

code implementation

The names and attributes of all the plant cards are stored in separate lists, with each list index corresponding to a plant.

For example, list index 0 is the sun flower:

  • card_name_list[0] is the name of the sunflower card used to get a picture of the sunflower card.

  • plant_name_list[0] is the name of the sunflower used to get a picture of the sunflower card.

  • plant_sun_list[0] is the number of suns it takes to grow sunflowers.

  • plant_frozen_time_list[0] is the cooling time of the sunflower.

Plant Cards

Each plant card is a separate Card class used to display this plant.

  • CheMouseClick function: Determines whether the mouse clicks on the card;

  • canClick: Determine if the card can be planted (if there are enough points and it is still cool);

  • update function: Set the transparency of the picture to indicate whether the card is selectable.

Card Column Class

The MenuBar class shows the plant card bar in Figure 3:

  • self.sun_value: The number of solar points currently collected;

  • self.card_list: list of plant cards;

  • setupCards function: Traverse through the initialization init function to pass in the list of selected plant cards for this level, create the Card class in turn, and set the display position of each card;

  • Check CardClick function: Check if the mouse clicked on a plant card on the card bar, and returns the result if a plantable card is selected.

Code:

  1 import pygame as pg
  2 from .. import tool
  3 from .. import constants as c
  4   5 PANEL_Y_START = 87
  6 PANEL_X_START = 22
  7 PANEL_Y_INTERNAL = 74
  8 PANEL_X_INTERNAL = 53
  9 CARD_LIST_NUM = 8
 10  11 card_name_list = [c.CARD_SUNFLOWER, c.CARD_PEASHOOTER, c.CARD_SNOWPEASHOOTER, c.CARD_WALLNUT,
 12                   c.CARD_CHERRYBOMB, c.CARD_THREEPEASHOOTER, c.CARD_REPEATERPEA, c.CARD_CHOMPER,
 13                   c.CARD_PUFFSHROOM, c.CARD_POTATOMINE, c.CARD_SQUASH, c.CARD_SPIKEWEED,
 14                   c.CARD_JALAPENO, c.CARD_SCAREDYSHROOM, c.CARD_SUNSHROOM, c.CARD_ICESHROOM]
 15 plant_name_list = [c.SUNFLOWER, c.PEASHOOTER, c.SNOWPEASHOOTER, c.WALLNUT,
 16                    c.CHERRYBOMB, c.THREEPEASHOOTER, c.REPEATERPEA, c.CHOMPER,
 17                    c.PUFFSHROOM, c.POTATOMINE, c.SQUASH, c.SPIKEWEED,
 18                    c.JALAPENO, c.SCAREDYSHROOM, c.SUNSHROOM, c.ICESHROOM]
 19 plant_sun_list = [50, 100, 175, 50, 150, 325, 200, 150, 0, 25, 50, 100, 125, 25, 25, 75]
 20 plant_frozen_time_list = [7500, 7500, 7500, 30000, 50000, 7500, 7500, 7500, 7500, 30000,
 21                           30000, 7500, 50000, 7500, 7500, 50000]
 22 all_card_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
 23  24 def getSunValueImage(sun_value):
 25     font = pg.font.SysFont(None, 22)
 26     width = 32
 27     msg_image = font.render(str(sun_value), True, c.NAVYBLUE, c.LIGHTYELLOW)
 28     msg_rect = msg_image.get_rect()
 29     msg_w = msg_rect.width
 30  31     image = pg.Surface([width, 17])
 32     x = width - msg_w
 33  34     image.fill(c.LIGHTYELLOW)
 35     image.blit(msg_image, (x, 0), (0, 0, msg_rect.w, msg_rect.h))
 36     image.set_colorkey(c.BLACK)
 37     return image
 38  39 class Card():
 40     def __init__(self, x, y, name_index, scale=0.78):
 41         self.loadFrame(card_name_list[name_index], scale)
 42         self.rect = self.orig_image.get_rect()
 43         self.rect.x = x
 44         self.rect.y = y
 45         
 46         self.name_index = name_index
 47         self.sun_cost = plant_sun_list[name_index]
 48         self.frozen_time = plant_frozen_time_list[name_index]
 49         self.frozen_timer = -self.frozen_time
 50         self.refresh_timer = 0
 51         self.select = True
 52  53     def loadFrame(self, name, scale):
 54         frame = tool.GFX[name]
 55         rect = frame.get_rect()
 56         width, height = rect.w, rect.h
 57  58         self.orig_image = tool.get_image(frame, 0, 0, width, height, c.BLACK, scale)
 59         self.image = self.orig_image
 60  61     def checkMouseClick(self, mouse_pos):
 62         x, y = mouse_pos
 63         if(x >= self.rect.x and x <= self.rect.right and
 64            y >= self.rect.y and y <= self.rect.bottom):
 65             return True
 66         return False
 67  68     def canClick(self, sun_value, current_time):
 69         if self.sun_cost <= sun_value and (current_time - self.frozen_timer) > self.frozen_time:
 70             return True
 71         return False
 72  73     def canSelect(self):
 74         return self.select
 75  76     def setSelect(self, can_select):
 77         self.select = can_select
 78         if can_select:
 79             self.image.set_alpha(255)
 80         else:
 81             self.image.set_alpha(128)
 82  83     def setFrozenTime(self, current_time):
 84         self.frozen_timer = current_time
 85  86     def createShowImage(self, sun_value, current_time):
 87         '''create a card image to show cool down status
 88            or disable status when have not enough sun value'''
 89         time = current_time - self.frozen_timer
 90         if time < self.frozen_time: #cool down status
 91             image = pg.Surface([self.rect.w, self.rect.h])
 92             frozen_image = self.orig_image.copy()
 93             frozen_image.set_alpha(128)
 94             frozen_height = (self.frozen_time - time)/self.frozen_time * self.rect.h
 95             
 96             image.blit(frozen_image, (0,0), (0, 0, self.rect.w, frozen_height))
 97             image.blit(self.orig_image, (0,frozen_height),
 98                        (0, frozen_height, self.rect.w, self.rect.h - frozen_height))
 99         elif self.sun_cost > sun_value: #disable status
100             image = self.orig_image.copy()
101             image.set_alpha(192)
102         else:
103             image = self.orig_image
104         return image
105 106     def update(self, sun_value, current_time):
107         if (current_time - self.refresh_timer) >= 250:
108             self.image = self.createShowImage(sun_value, current_time)
109             self.refresh_timer = current_time
110 111     def draw(self, surface):
112         surface.blit(self.image, self.rect)
113 114 class MenuBar():
115     def __init__(self, card_list, sun_value):
116         self.loadFrame(c.MENUBAR_BACKGROUND)
117         self.rect = self.image.get_rect()
118         self.rect.x = 10
119         self.rect.y = 0
120         
121         self.sun_value = sun_value
122         self.card_offset_x = 32
123         self.setupCards(card_list)
124 125     def loadFrame(self, name):
126         frame = tool.GFX[name]
127         rect = frame.get_rect()
128         frame_rect = (rect.x, rect.y, rect.w, rect.h)
129 130         self.image = tool.get_image(tool.GFX[name], *frame_rect, c.WHITE, 1)
131 132     def update(self, current_time):
133         self.current_time = current_time
134         for card in self.card_list:
135             card.update(self.sun_value, self.current_time)
136 137     def createImage(self, x, y, num):
138         if num == 1:
139             return
140         img = self.image
141         rect = self.image.get_rect()
142         width = rect.w
143         height = rect.h
144         self.image = pg.Surface((width * num, height)).convert()
145         self.rect = self.image.get_rect()
146         self.rect.x = x
147         self.rect.y = y
148         for i in range(num):
149             x = i * width
150             self.image.blit(img, (x,0))
151         self.image.set_colorkey(c.BLACK)
152     
153     def setupCards(self, card_list):
154         self.card_list = []
155         x = self.card_offset_x
156         y = 8
157         for index in card_list:
158             x += 55
159             self.card_list.append(Card(x, y, index))
160 161     def checkCardClick(self, mouse_pos):
162         result = None
163         for card in self.card_list:
164             if card.checkMouseClick(mouse_pos):
165                 if card.canClick(self.sun_value, self.current_time):
166                     result = (plant_name_list[card.name_index], card.sun_cost)
167                 break
168         return result
169     
170     def checkMenuBarClick(self, mouse_pos):
171         x, y = mouse_pos
172         if(x >= self.rect.x and x <= self.rect.right and
173            y >= self.rect.y and y <= self.rect.bottom):
174             return True
175         return False
176 177     def decreaseSunValue(self, value):
178         self.sun_value -= value
179 180     def increaseSunValue(self, value):
181         self.sun_value += value
182 183     def setCardFrozenTime(self, plant_name):
184         for card in self.card_list:
185             if plant_name_list[card.name_index] == plant_name:
186                 card.setFrozenTime(self.current_time)
187                 break
188 189     def drawSunValue(self):
190         self.value_image = getSunValueImage(self.sun_value)
191         self.value_rect = self.value_image.get_rect()
192         self.value_rect.x = 21
193         self.value_rect.y = self.rect.bottom - 21
194         
195         self.image.blit(self.value_image, self.value_rect)
196 197     def draw(self, surface):
198         self.drawSunValue()
199         surface.blit(self.image, self.rect)
200         for card in self.card_list:
201             card.draw(surface)
202 203 class Panel():
204     def __init__(self, card_list, sun_value):
205         self.loadImages(sun_value)
206         self.selected_cards = []
207         self.selected_num = 0
208         self.setupCards(card_list)
209 210     def loadFrame(self, name):
211         frame = tool.GFX[name]
212         rect = frame.get_rect()
213         frame_rect = (rect.x, rect.y, rect.w, rect.h)
214 215         return tool.get_image(tool.GFX[name], *frame_rect, c.WHITE, 1)
216 217     def loadImages(self, sun_value):
218         self.menu_image = self.loadFrame(c.MENUBAR_BACKGROUND)
219         self.menu_rect = self.menu_image.get_rect()
220         self.menu_rect.x = 0
221         self.menu_rect.y = 0
222 223         self.panel_image = self.loadFrame(c.PANEL_BACKGROUND)
224         self.panel_rect = self.panel_image.get_rect()
225         self.panel_rect.x = 0
226         self.panel_rect.y = PANEL_Y_START
227 228         
229         self.value_image = getSunValueImage(sun_value)
230         self.value_rect = self.value_image.get_rect()
231         self.value_rect.x = 21
232         self.value_rect.y = self.menu_rect.bottom - 21
233 234         self.button_image =  self.loadFrame(c.START_BUTTON)
235         self.button_rect = self.button_image.get_rect()
236         self.button_rect.x = 155
237         self.button_rect.y = 547
238 239     def setupCards(self, card_list):
240         self.card_list = []
241         x = PANEL_X_START - PANEL_X_INTERNAL
242         y = PANEL_Y_START + 43 - PANEL_Y_INTERNAL
243         for i, index in enumerate(card_list):
244             if i % 8 == 0:
245                 x = PANEL_X_START - PANEL_X_INTERNAL
246                 y += PANEL_Y_INTERNAL
247             x += PANEL_X_INTERNAL
248             self.card_list.append(Card(x, y, index, 0.75))
249 250     def checkCardClick(self, mouse_pos):
251         delete_card = None
252         for card in self.selected_cards:
253             if delete_card: # when delete a card, move right cards to left
254                 card.rect.x -= 55
255             elif card.checkMouseClick(mouse_pos):
256                 self.deleteCard(card.name_index)
257                 delete_card = card
258 259         if delete_card:
260             self.selected_cards.remove(delete_card)
261             self.selected_num -= 1
262 263         if self.selected_num == CARD_LIST_NUM:
264             return
265 266         for card in self.card_list:
267             if card.checkMouseClick(mouse_pos):
268                 if card.canSelect():
269                     self.addCard(card)
270                 break
271 272     def addCard(self, card):
273         card.setSelect(False)
274         y = 8
275         x = 78 + self.selected_num * 55
276         self.selected_cards.append(Card(x, y, card.name_index))
277         self.selected_num += 1
278 279     def deleteCard(self, index):
280         self.card_list[index].setSelect(True)
281 282     def checkStartButtonClick(self, mouse_pos):
283         if self.selected_num < CARD_LIST_NUM:
284             return False
285 286         x, y = mouse_pos
287         if (x >= self.button_rect.x and x <= self.button_rect.right and
288             y >= self.button_rect.y and y <= self.button_rect.bottom):
289            return True
290         return False
291 292     def getSelectedCards(self):
293         card_index_list = []
294         for card in self.selected_cards:
295             card_index_list.append(card.name_index)
296         return card_index_list
297 298     def draw(self, surface):
299         self.menu_image.blit(self.value_image, self.value_rect)
300         surface.blit(self.menu_image, self.menu_rect)
301         surface.blit(self.panel_image, self.panel_rect)
302         for card in self.card_list:
303             card.draw(surface)
304         for card in self.selected_cards:
305             card.draw(surface)
306 307         if self.selected_num == CARD_LIST_NUM:
308             surface.blit(self.button_image, self.button_rect)

 

Mouse Picture Switching

The setupMouseImage function switches the mouse picture to the selected plant:

  • self.mouse_image: Get a picture of the selected plant according to the plant_name;

  • self.mouse_rect: Select the position of the plant picture, in the drawMouseShow function, you need to set the position of the plant picture to the current mouse position;

  • pg.mouse.set_visible(False): Hides the default mouse display so that the mouse picture switches to the selected plant.

 1    def setupMouseImage(self, plant_name, plant_cost):
 2         frame_list = tool.GFX[plant_name]
 3         if plant_name in tool.PLANT_RECT:
 4             data = tool.PLANT_RECT[plant_name]
 5             x, y, width, height = data['x'], data['y'], data['width'], data['height']
 6         else:
 7             x, y = 0, 0
 8             rect = frame_list[0].get_rect()
 9             width, height = rect.w, rect.h
10 11 12         if plant_name == c.POTATOMINE or plant_name == c.SQUASH:
13             color = c.WHITE
14         else:
15             color = c.BLACK
16         self.mouse_image = tool.get_image(frame_list[0], x, y, width, height, color, 1)
17         self.mouse_rect = self.mouse_image.get_rect()
18         pg.mouse.set_visible(False)
19         self.drag_plant = True
20         self.plant_name = plant_name
21         self.plant_cost = plant_cost
22 23 24     def drawMouseShow(self, surface):
25         if self.hint_plant:
26             surface.blit(self.hint_image, self.hint_rect)
27         x, y = pg.mouse.get_pos()
28         self.mouse_rect.centerx = x
29         self.mouse_rect.centery = y
30         surface.blit(self.mouse_image, self.mouse_rect)

 

In which square is the hint

First look at the map class, code in source\component\map.py:

  • self.map: A two-dimensional list that holds the state of each square.Each entry is initialized to zero, indicating that it can be planted, and a value of 1 indicates that the square has already planted plants.

  • getMapIndex function: The incoming parameter is the coordinate position in the game (such as the current mouse position) and returns which square of the map the position is in.

  • getMapGridPos function: Pass in the index of a square and return the coordinate location of the plant in that square.

  • showPlant function: Determines if the square in which the location is located can be planted based on the coordinate location passed in, and returns to the coordinate location of the plant in the square if it can be planted.

 1 MAP_EMPTY = 0
 2 MAP_EXIST = 1
 3  4  5 class Map():
 6     def __init__(self, width, height):
 7         self.width = width
 8         self.height = height
 9         self.map = [[0 for x in range(self.width)] for y in range(self.height)]
10 11 12     def isValid(self, map_x, map_y):
13         if (map_x < 0 or map_x >= self.width or
14             map_y < 0 or map_y >= self.height):
15             return False
16         return True
17 18     def isMovable(self, map_x, map_y):
19         return (self.map[map_y][map_x] == c.MAP_EMPTY)
20 21     def getMapIndex(self, x, y):
22         x -= c.MAP_OFFSET_X
23         y -= c.MAP_OFFSET_Y
24         return (x // c.GRID_X_SIZE, y // c.GRID_Y_SIZE)
25 26     def getMapGridPos(self, map_x, map_y):
27         return (map_x * c.GRID_X_SIZE + c.GRID_X_SIZE//2 + c.MAP_OFFSET_X,
28                 map_y * c.GRID_Y_SIZE + c.GRID_Y_SIZE//5 * 3 + c.MAP_OFFSET_Y)
29 30     def setMapGridType(self, map_x, map_y, type):
31         self.map[map_y][map_x] = type
32 33 34     def getRandomMapIndex(self):
35         map_x = random.randint(0, self.width-1)
36         map_y = random.randint(0, self.height-1)
37         return (map_x, map_y)
38 39 40     def showPlant(self, x, y):
41         pos = None
42         map_x, map_y = self.getMapIndex(x, y)
43         if self.isValid(map_x, map_y) and self.isMovable(map_x, map_y):
44             pos = self.getMapGridPos(map_x, map_y)
45         return pos

 

Code in source\state\level.py:

  • canSeedPlant function: Determines whether the current mouse position can plant plants;

  • setupHintImage function: If the current mouse position can plant and a plant card is selected, set self.hint_image to show in which square the current plant will be planted, and self.hint_rect is the coordinate location of the plant species.

 1     def canSeedPlant(self):
 2         x, y = pg.mouse.get_pos()
 3         return self.map.showPlant(x, y)
 4  5     def setupHintImage(self):
 6         pos = self.canSeedPlant()
 7         if pos and self.mouse_image:
 8             if (self.hint_image and pos[0] == self.hint_rect.x and
 9                 pos[1] == self.hint_rect.y):
10                 return
11             width, height = self.mouse_rect.w, self.mouse_rect.h
12             image = pg.Surface([width, height])
13             image.blit(self.mouse_image, (0, 0), (0, 0, width, height))
14             image.set_colorkey(c.BLACK)
15             image.set_alpha(128)
16             self.hint_image = image
17             self.hint_rect = image.get_rect()
18             self.hint_rect.centerx = pos[0]
19             self.hint_rect.bottom = pos[1]
20             self.hint_plant = True
21         else:
22             self.hint_plant = False

Posted by ali_2kool2002 on Sun, 08 Dec 2019 21:26:11 -0800