基于Python3-Pygame的植物大战僵尸小游戏
依赖库:pygame
pip install pygame -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
源码(详细注释):
1 #1 引入需要的模块 2 import pygame 3 import random 4 5 #1 配置图片地址 6 IMAGE_PATH = 'imgs/' 7 8 #1 设置页面宽高 9 scrrr_width=800 10 scrrr_height =560 11 12 #1 创建控制游戏结束的状态 13 GAMEOVER = False 14 15 #4 图片加载报错处理 16 LOG = '文件:{}中的方法:{}出错'.format(__file__,__name__) 17 18 19 #3 创建地图类 20 class Map(): 21 #3 存储两张不同颜色的图片名称 22 map_names_list = [IMAGE_PATH + 'map1.png', IMAGE_PATH + 'map2.png'] 23 #3 初始化地图 24 def __init__(self, x, y, img_index): 25 self.image = pygame.image.load(Map.map_names_list[img_index]) 26 self.position = (x, y) 27 # 是否能够种植 28 self.can_grow = True 29 #3 加载地图 30 def load_map(self): 31 MainGame.window.blit(self.image,self.position) 32 33 34 35 #4 植物类 36 class Plant(pygame.sprite.Sprite): 37 def __init__(self): 38 super(Plant, self).__init__() 39 self.live=True 40 41 # 加载图片 42 def load_image(self): 43 if hasattr(self, 'image') and hasattr(self, 'rect'): 44 MainGame.window.blit(self.image, self.rect) 45 else: 46 print(LOG) 47 48 49 #5 向日葵类 50 class Sunflower(Plant): 51 def __init__(self,x,y): 52 super(Sunflower, self).__init__() 53 self.image = pygame.image.load('imgs/sunflower.png') 54 self.rect = self.image.get_rect() 55 self.rect.x = x 56 self.rect.y = y 57 self.price = 50 58 self.hp = 100 59 #5 时间计数器 60 self.time_count = 0 61 62 #5 新增功能:生成阳光 63 def produce_money(self): 64 self.time_count += 1 65 if self.time_count == 25: 66 MainGame.money += 5 67 self.time_count = 0 68 #5 向日葵加入到窗口中 69 def display_sunflower(self): 70 MainGame.window.blit(self.image,self.rect) 71 72 73 #6 豌豆射手类 74 class PeaShooter(Plant): 75 def __init__(self,x,y): 76 super(PeaShooter, self).__init__() 77 # self.image 为一个 surface 78 self.image = pygame.image.load('imgs/peashooter.png') 79 self.rect = self.image.get_rect() 80 self.rect.x = x 81 self.rect.y = y 82 self.price = 50 83 self.hp = 200 84 #6 发射计数器 85 self.shot_count = 0 86 87 #6 增加射击方法 88 def shot(self): 89 #6 记录是否应该射击 90 should_fire = False 91 for zombie in MainGame.zombie_list: 92 if zombie.rect.y == self.rect.y and zombie.rect.x < 800 and zombie.rect.x > self.rect.x: 93 should_fire = True 94 #6 如果活着 95 if self.live and should_fire: 96 self.shot_count += 1 97 #6 计数器到25发射一次 98 if self.shot_count == 25: 99 #6 基于当前豌豆射手的位置,创建子弹 100 peabullet = PeaBullet(self) 101 #6 将子弹存储到子弹列表中 102 MainGame.peabullet_list.append(peabullet) 103 self.shot_count = 0 104 105 #6 将豌豆射手加入到窗口中的方法 106 def display_peashooter(self): 107 MainGame.window.blit(self.image,self.rect) 108 109 110 #7 豌豆子弹类 111 class PeaBullet(pygame.sprite.Sprite): 112 def __init__(self,peashooter): 113 self.live = True 114 self.image = pygame.image.load('imgs/peabullet.png') 115 self.damage = 50 116 self.speed = 10 117 self.rect = self.image.get_rect() 118 self.rect.x = peashooter.rect.x + 60 119 self.rect.y = peashooter.rect.y + 15 120 121 def move_bullet(self): 122 #7 在屏幕范围内,实现往右移动 123 if self.rect.x < scrrr_width: 124 self.rect.x += self.speed 125 else: 126 self.live = False 127 128 #7 新增,子弹与僵尸的碰撞 129 def hit_zombie(self): 130 for zombie in MainGame.zombie_list: 131 if pygame.sprite.collide_rect(self,zombie): 132 #打中僵尸之后,修改子弹的状态, 133 self.live = False 134 #僵尸掉血 135 zombie.hp -= self.damage 136 if zombie.hp <= 0: 137 zombie.live = False 138 self.nextLevel() 139 #7闯关方法 140 def nextLevel(self): 141 MainGame.score += 20 142 MainGame.remnant_score -=20 143 for i in range(1,100): 144 if MainGame.score==100*i and MainGame.remnant_score==0: 145 MainGame.remnant_score=100*i 146 MainGame.shaoguan+=1 147 MainGame.produce_zombie+=50 148 149 150 151 def display_peabullet(self): 152 MainGame.window.blit(self.image,self.rect) 153 154 155 156 #9 僵尸类 157 class Zombie(pygame.sprite.Sprite): 158 def __init__(self,x,y): 159 super(Zombie, self).__init__() 160 self.image = pygame.image.load('imgs/zombie.png') 161 self.rect = self.image.get_rect() 162 self.rect.x = x 163 self.rect.y = y 164 self.hp = 1000 165 self.damage = 2 166 self.speed = 1 167 self.live = True 168 self.stop = False 169 #9 僵尸的移动 170 def move_zombie(self): 171 if self.live and not self.stop: 172 self.rect.x -= self.speed 173 if self.rect.x < -80: 174 #8 调用游戏结束方法 175 MainGame().gameOver() 176 177 #9 判断僵尸是否碰撞到植物,如果碰撞,调用攻击植物的方法 178 def hit_plant(self): 179 for plant in MainGame.plants_list: 180 if pygame.sprite.collide_rect(self,plant): 181 #8 僵尸移动状态的修改 182 self.stop = True 183 self.eat_plant(plant) 184 #9 僵尸攻击植物 185 def eat_plant(self,plant): 186 #9 植物生命值减少 187 plant.hp -= self.damage 188 #9 植物死亡后的状态修改,以及地图状态的修改 189 if plant.hp <= 0: 190 a = plant.rect.y // 80 - 1 191 b = plant.rect.x // 80 192 map = MainGame.map_list[a][b] 193 map.can_grow = True 194 plant.live = False 195 #8 修改僵尸的移动状态 196 self.stop = False 197 198 199 200 #9 将僵尸加载到地图中 201 def display_zombie(self): 202 MainGame.window.blit(self.image,self.rect) 203 204 205 #1 主程序 206 class MainGame(): 207 #2 创建关数,得分,剩余分数,钱数 208 shaoguan = 1 209 score = 0 210 remnant_score = 100 211 money = 200 212 #3 存储所有地图坐标点 213 map_points_list = [] 214 #3 存储所有的地图块 215 map_list = [] 216 #4 存储所有植物的列表 217 plants_list = [] 218 #7 存储所有豌豆子弹的列表 219 peabullet_list = [] 220 #9 新增存储所有僵尸的列表 221 zombie_list = [] 222 count_zombie = 0 223 produce_zombie = 100 224 #1 加载游戏窗口 225 def init_window(self): 226 #1 调用显示模块的初始化 227 pygame.display.init() 228 #1 创建窗口 229 MainGame.window = pygame.display.set_mode([scrrr_width,scrrr_height]) 230 231 #2 文本绘制 232 def draw_text(self, content, size, color): 233 pygame.font.init() 234 font = pygame.font.SysFont('kaiti', size) 235 text = font.render(content, True, color) 236 return text 237 238 #2 加载帮助提示 239 def load_help_text(self): 240 text1 = self.draw_text('1.按左键创建向日葵 2.按右键创建豌豆射手', 26, (255, 0, 0)) 241 MainGame.window.blit(text1, (5, 5)) 242 243 #3 初始化坐标点 244 def init_plant_points(self): 245 for y in range(1, 7): 246 points = [] 247 for x in range(10): 248 point = (x, y) 249 points.append(point) 250 MainGame.map_points_list.append(points) 251 print("MainGame.map_points_list", MainGame.map_points_list) 252 253 #3 初始化地图 254 def init_map(self): 255 for points in MainGame.map_points_list: 256 temp_map_list = list() 257 for point in points: 258 # map = None 259 if (point[0] + point[1]) % 2 == 0: 260 map = Map(point[0] * 80, point[1] * 80, 0) 261 else: 262 map = Map(point[0] * 80, point[1] * 80, 1) 263 # 将地图块加入到窗口中 264 temp_map_list.append(map) 265 print("temp_map_list", temp_map_list) 266 MainGame.map_list.append(temp_map_list) 267 print("MainGame.map_list", MainGame.map_list) 268 269 #3 将地图加载到窗口中 270 def load_map(self): 271 for temp_map_list in MainGame.map_list: 272 for map in temp_map_list: 273 map.load_map() 274 275 #6 增加豌豆射手发射处理 276 def load_plants(self): 277 for plant in MainGame.plants_list: 278 #6 优化加载植物的处理逻辑 279 if plant.live: 280 if isinstance(plant, Sunflower): 281 plant.display_sunflower() 282 plant.produce_money() 283 elif isinstance(plant, PeaShooter): 284 plant.display_peashooter() 285 plant.shot() 286 else: 287 MainGame.plants_list.remove(plant) 288 289 #7 加载所有子弹的方法 290 def load_peabullets(self): 291 for b in MainGame.peabullet_list: 292 if b.live: 293 b.display_peabullet() 294 b.move_bullet() 295 # v1.9 调用子弹是否打中僵尸的方法 296 b.hit_zombie() 297 else: 298 MainGame.peabullet_list.remove(b) 299 300 #8事件处理 301 302 def deal_events(self): 303 #8 获取所有事件 304 eventList = pygame.event.get() 305 #8 遍历事件列表,判断 306 for e in eventList: 307 if e.type == pygame.QUIT: 308 self.gameOver() 309 elif e.type == pygame.MOUSEBUTTONDOWN: 310 # print('按下鼠标按键') 311 print(e.pos) 312 # print(e.button)#左键1 按下滚轮2 上转滚轮为4 下转滚轮为5 右键 3 313 314 x = e.pos[0] // 80 315 y = e.pos[1] // 80 316 print(x, y) 317 map = MainGame.map_list[y - 1][x] 318 print(map.position) 319 #8 增加创建时候的地图装填判断以及金钱判断 320 if e.button == 1: 321 if map.can_grow and MainGame.money >= 50: 322 sunflower = Sunflower(map.position[0], map.position[1]) 323 MainGame.plants_list.append(sunflower) 324 print('当前植物列表长度:{}'.format(len(MainGame.plants_list))) 325 map.can_grow = False 326 MainGame.money -= 50 327 elif e.button == 3: 328 if map.can_grow and MainGame.money >= 50: 329 peashooter = PeaShooter(map.position[0], map.position[1]) 330 MainGame.plants_list.append(peashooter) 331 print('当前植物列表长度:{}'.format(len(MainGame.plants_list))) 332 map.can_grow = False 333 MainGame.money -= 50 334 335 #9 新增初始化僵尸的方法 336 def init_zombies(self): 337 for i in range(1, 7): 338 dis = random.randint(1, 5) * 200 339 zombie = Zombie(800 + dis, i * 80) 340 MainGame.zombie_list.append(zombie) 341 342 #9将所有僵尸加载到地图中 343 def load_zombies(self): 344 for zombie in MainGame.zombie_list: 345 if zombie.live: 346 zombie.display_zombie() 347 zombie.move_zombie() 348 # v2.0 调用是否碰撞到植物的方法 349 zombie.hit_plant() 350 else: 351 MainGame.zombie_list.remove(zombie) 352 #1 开始游戏 353 def start_game(self): 354 #1 初始化窗口 355 self.init_window() 356 #3 初始化坐标和地图 357 self.init_plant_points() 358 self.init_map() 359 #9 调用初始化僵尸的方法 360 self.init_zombies() 361 #1 只要游戏没结束,就一直循环 362 while not GAMEOVER: 363 #1 渲染白色背景 364 MainGame.window.fill((255, 255, 255)) 365 #2 渲染的文字和坐标位置 366 MainGame.window.blit(self.draw_text('当前钱数$: {}'.format(MainGame.money), 26, (255, 0, 0)), (500, 40)) 367 MainGame.window.blit(self.draw_text( 368 '当前关数{},得分{},距离下关还差{}分'.format(MainGame.shaoguan, MainGame.score, MainGame.remnant_score), 26, 369 (255, 0, 0)), (5, 40)) 370 self.load_help_text() 371 372 #3 需要反复加载地图 373 self.load_map() 374 #6 调用加载植物的方法 375 self.load_plants() 376 #7 调用加载所有子弹的方法 377 self.load_peabullets() 378 #8 调用事件处理的方法 379 self.deal_events() 380 #9 调用展示僵尸的方法 381 self.load_zombies() 382 #9 计数器增长,每数到100,调用初始化僵尸的方法 383 MainGame.count_zombie += 1 384 if MainGame.count_zombie == MainGame.produce_zombie: 385 self.init_zombies() 386 MainGame.count_zombie = 0 387 #9 pygame自己的休眠 388 pygame.time.wait(10) 389 #1 实时更新 390 pygame.display.update() 391 392 393 #10 程序结束方法 394 def gameOver(self): 395 MainGame.window.blit(self.draw_text('游戏结束', 50, (255, 0, 0)), (300, 200)) 396 print('游戏结束') 397 pygame.time.wait(400) 398 global GAMEOVER 399 GAMEOVER = True 400 401 402 #1 启动主程序 403 if __name__ == '__main__': 404 game = MainGame() 405 game.start_game()
效果图:
源码及文件下载:
链接:https://pan.baidu.com/s/1RywCxixiozq2VF0MI5syxg
提取码:26w8