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