2020年9月12日星期六

95B 《零基礎入門學習Python》筆記 第095講:Pygame:飛機大戰6 中

這節課實現的完整代碼如下:
  1. #main.py
  2. import pygame
  3. import sys
  4. import traceback #为了更好地退出
  5. import myplane
  6. import enemy
  7. import bullet
  8. import supply
  9. from pygame.locals import *
  10. from random import *
  11. pygame.init()
  12. pygame.mixer.init() #混音器初始化
  13. bg_size = width, height = 480, 700
  14. screen = pygame.display.set_mode(bg_size)
  15. pygame.display.set_caption("飞机大战 -- Python Demo")
  16. background = pygame.image.load("images/background.png").convert()
  17. #生成一些颜色
  18. BLACK = (0, 0, 0)
  19. WHITE = (255, 255, 255)
  20. GREEN = (0, 255, 0)
  21. RED = (255, 0, 0)
  22. # 载入游戏音乐
  23. pygame.mixer.music.load("sound/game_music.ogg")
  24. pygame.mixer.music.set_volume(0.2)
  25. bullet_sound = pygame.mixer.Sound("sound/bullet.wav")
  26. bullet_sound.set_volume(0.2)
  27. bomb_sound = pygame.mixer.Sound("sound/use_bomb.wav")
  28. bomb_sound.set_volume(0.2)
  29. supply_sound = pygame.mixer.Sound("sound/supply.wav")
  30. supply_sound.set_volume(0.2)
  31. get_bomb_sound = pygame.mixer.Sound("sound/get_bomb.wav")
  32. get_bomb_sound.set_volume(0.2)
  33. get_bullet_sound = pygame.mixer.Sound("sound/get_bullet.wav")
  34. get_bullet_sound.set_volume(0.2)
  35. upgrade_sound = pygame.mixer.Sound("sound/upgrade.wav")
  36. upgrade_sound.set_volume(0.2)
  37. enemy3_fly_sound = pygame.mixer.Sound("sound/enemy3_flying.wav")
  38. enemy3_fly_sound.set_volume(0.5)
  39. enemy1_down_sound = pygame.mixer.Sound("sound/enemy1_down.wav")
  40. enemy1_down_sound.set_volume(0.2)
  41. enemy2_down_sound = pygame.mixer.Sound("sound/enemy2_down.wav")
  42. enemy2_down_sound.set_volume(0.2)
  43. enemy3_down_sound = pygame.mixer.Sound("sound/enemy3_down.wav")
  44. enemy3_down_sound.set_volume(0.5)
  45. me_down_sound = pygame.mixer.Sound("sound/me_down.wav")
  46. me_down_sound.set_volume(0.2)
  47. def add_small_enemies(group1, group2, num):
  48. for i in range(num):
  49. e1 = enemy.SmallEnemy(bg_size)
  50. group1.add(e1)
  51. group2.add(e1)
  52. def add_mid_enemies(group1, group2, num):
  53. for i in range(num):
  54. e2 = enemy.MidEnemy(bg_size)
  55. group1.add(e2)
  56. group2.add(e2)
  57. def add_big_enemies(group1, group2, num):
  58. for i in range(num):
  59. e3 = enemy.BigEnemy(bg_size)
  60. group1.add(e3)
  61. group2.add(e3)
  62. def inc_speed(target, inc): #加速函数
  63. for each in target:
  64. each.speed += inc
  65. def main():
  66. pygame.mixer.music.play(-1)
  67. # 生成我方飞机
  68. me = myplane.Myplane(bg_size)
  69. #生成敌方飞机
  70. enemies = pygame.sprite.Group()
  71. # 生成敌方小型飞机
  72. small_enemies = pygame.sprite.Group()
  73. add_small_enemies(small_enemies, enemies, 15)
  74. # 生成敌方中型飞机
  75. mid_enemies = pygame.sprite.Group()
  76. add_mid_enemies(mid_enemies, enemies, 4)
  77. # 生成敌方大型飞机
  78. big_enemies = pygame.sprite.Group()
  79. add_big_enemies(big_enemies, enemies, 2)
  80. # 生成普通子弹
  81. bullet1 = []
  82. bullet1_index = 0
  83. BULLET1_NUM = 4
  84. for i in range(BULLET1_NUM):
  85. bullet1.append(bullet.Bullet1(me.rect.midtop)) #me.rect.midtop:机头位置
  86. # 生成超级子弹
  87. bullet2 = []
  88. bullet2_index = 0
  89. BULLET2_NUM = 8
  90. for i in range(BULLET2_NUM//2):
  91. bullet2.append(bullet.Bullet2((me.rect.centerx-33, me.rect.centery)))
  92. bullet2.append(bullet.Bullet2((me.rect.centerx+30, me.rect.centery)))
  93. clock = pygame.time.Clock()
  94. #中弹图片索引
  95. e1_destroy_index = 0
  96. e2_destroy_index = 0
  97. e3_destroy_index = 0
  98. me_destroy_index = 0
  99. # 统计得分
  100. score = 0
  101. score_font = pygame.font.Font("font/font.ttf", 36) #得分字体
  102. # 标志是否暂停游戏
  103. paused = False
  104. pause_nor_image = pygame.image.load("images/pause_nor.png").convert_alpha()
  105. pause_pressed_image = pygame.image.load("images/pause_pressed.png").convert_alpha()
  106. resume_nor_image = pygame.image.load("images/resume_nor.png").convert_alpha()
  107. resume_pressed_image = pygame.image.load("images/resume_pressed.png").convert_alpha()
  108. paused_rect = pause_nor_image.get_rect()
  109. paused_rect.left, paused_rect.top = width - paused_rect.width - 10, 10
  110. paused_image = pause_nor_image
  111. # 设置难度级别
  112. level = 1
  113. # 全屏炸弹
  114. bomb_image = pygame.image.load("images/bomb.png").convert_alpha()
  115. bomb_rect = bomb_image.get_rect()
  116. bomb_font = pygame.font.Font("font/font.ttf", 48)
  117. bomb_num = 3
  118. # 每30秒发放一个补给包
  119. bullet_supply = supply.Bullet_Supply(bg_size)
  120. bomb_supply = supply.Bomb_Supply(bg_size)
  121. SUPPLY_TIME = USEREVENT
  122. pygame.time.set_timer(SUPPLY_TIME, 30 * 1000)
  123. # 超级子弹定时器
  124. DOUBLE_BULLET_TIME = USEREVENT + 1
  125. # 标志是否使用超级子弹
  126. is_double_bullet = False
  127. #用于切换图片
  128. switch_image = True
  129. #用于延迟
  130. delay = 100
  131. running = True
  132. while running:
  133. for event in pygame.event.get():
  134. if event.type == QUIT:
  135. pygame.quit()
  136. sys.exit()
  137. elif event.type == MOUSEBUTTONDOWN:
  138. if event.button == 1 and paused_rect.collidepoint(event.pos):
  139. paused = not paused
  140. if paused:
  141. pygame.time.set_timer(SUPPLY_TIME, 0)
  142. pygame.mixer.music.pause()
  143. pygame.mixer.pause()
  144. else:
  145. pygame.time.set_timer(SUPPLY_TIME, 30 * 1000)
  146. pygame.mixer.music.unpause()
  147. pygame.mixer.unpause()
  148. elif event.type == MOUSEMOTION:
  149. if paused_rect.collidepoint(event.pos):
  150. if paused:
  151. paused_image = resume_pressed_image
  152. else:
  153. paused_image = pause_pressed_image
  154. else:
  155. if paused:
  156. paused_image = resume_nor_image
  157. else:
  158. paused_image = pause_nor_image
  159. #空格触发全屏炸弹
  160. elif event.type == KEYDOWN:
  161. if event.key == K_SPACE:
  162. if bomb_num:
  163. bomb_num -= 1
  164. bomb_sound.play()
  165. for each in enemies:
  166. if each.rect.bottom > 0:
  167. each.active = False
  168. #响应补给包事件
  169. elif event.type == SUPPLY_TIME:
  170. supply_sound.play()
  171. if choice([True, False]):
  172. bomb_supply.reset()
  173. else:
  174. bullet_supply.reset()
  175. #响应超级子弹事件
  176. elif event.type == DOUBLE_BULLET_TIME:
  177. is_double_bullet = False
  178. pygame.time.set_timer(DOUBLE_BULLET_TIME, 0)
  179. # 根据用户的得分增加难度
  180. if level == 1 and score > 50000:
  181. level = 2
  182. upgrade_sound.play()
  183. # 增加3架小型敌机、2架中型敌机和1架大型敌机
  184. add_small_enemies(small_enemies, enemies, 3)
  185. add_mid_enemies(mid_enemies, enemies, 2)
  186. add_big_enemies(big_enemies, enemies, 1)
  187. # 提升小型敌机的速度
  188. inc_speed(small_enemies, 1)
  189. elif level == 2 and score > 300000:
  190. level = 3
  191. upgrade_sound.play()
  192. # 增加5架小型敌机、3架中型敌机和2架大型敌机
  193. add_small_enemies(small_enemies, enemies, 5)
  194. add_mid_enemies(mid_enemies, enemies, 3)
  195. add_big_enemies(big_enemies, enemies, 2)
  196. # 提升小型敌机的速度
  197. inc_speed(small_enemies, 1)
  198. inc_speed(mid_enemies, 1)
  199. elif level == 3 and score > 600000:
  200. level = 4
  201. upgrade_sound.play()
  202. # 增加5架小型敌机、3架中型敌机和2架大型敌机
  203. add_small_enemies(small_enemies, enemies, 5)
  204. add_mid_enemies(mid_enemies, enemies, 3)
  205. add_big_enemies(big_enemies, enemies, 2)
  206. # 提升小型敌机的速度
  207. inc_speed(small_enemies, 1)
  208. inc_speed(mid_enemies, 1)
  209. elif level == 4 and score > 1000000:
  210. level = 5
  211. upgrade_sound.play()
  212. # 增加5架小型敌机、3架中型敌机和2架大型敌机
  213. add_small_enemies(small_enemies, enemies, 5)
  214. add_mid_enemies(mid_enemies, enemies, 3)
  215. add_big_enemies(big_enemies, enemies, 2)
  216. # 提升小型敌机的速度
  217. inc_speed(small_enemies, 1)
  218. inc_speed(mid_enemies, 1)
  219. screen.blit(background, (0, 0))
  220. if not paused:
  221. #检测用户的键盘操作
  222. key_pressed = pygame.key.get_pressed()
  223. if key_pressed[K_w] or key_pressed[K_UP]:
  224. me.moveUp()
  225. if key_pressed[K_s] or key_pressed[K_DOWN]:
  226. me.moveDown()
  227. if key_pressed[K_a] or key_pressed[K_LEFT]:
  228. me.moveLeft()
  229. if key_pressed[K_d] or key_pressed[K_RIGHT]:
  230. me.moveRight()
  231. # 绘制全屏炸弹补给并检测是否获得
  232. if bomb_supply.active:
  233. bomb_supply.move()
  234. screen.blit(bomb_supply.image, bomb_supply.rect)
  235. if pygame.sprite.collide_mask(bomb_supply, me):
  236. get_bomb_sound.play()
  237. if bomb_num < 3:
  238. bomb_num += 1
  239. bomb_supply.active = False
  240. # 绘制超级子弹补给并检测是否获得
  241. if bullet_supply.active:
  242. bullet_supply.move()
  243. screen.blit(bullet_supply.image, bullet_supply.rect)
  244. if pygame.sprite.collide_mask(bullet_supply, me):
  245. get_bullet_sound.play()
  246. #发射超级子弹18秒
  247. is_double_bullet = True
  248. pygame.time.set_timer(DOUBLE_BULLET_TIME, 18 * 1000)
  249. bullet_supply.active = False
  250. # 发射子弹
  251. if not(delay % 10):
  252. bullet_sound.play()
  253. if is_double_bullet:
  254. bullets = bullet2
  255. bullets[bullet2_index].reset((me.rect.centerx-33, me.rect.centery))
  256. bullets[bullet2_index+1].reset((me.rect.centerx+30, me.rect.centery))
  257. bullet2_index = (bullet2_index + 2) % BULLET2_NUM
  258. else:
  259. bullets = bullet1
  260. bullets[bullet1_index].reset(me.rect.midtop)
  261. bullet1_index = (bullet1_index + 1) % BULLET1_NUM
  262. # 检测子弹是否击中敌机
  263. for b in bullets:
  264. if b.active:
  265. b.move()
  266. screen.blit(b.image, b.rect)
  267. enemy_hit = pygame.sprite.spritecollide(b, enemies, False, pygame.sprite.collide_mask)
  268. if enemy_hit:
  269. b.active = False
  270. for e in enemy_hit:
  271. if e in mid_enemies or e in big_enemies:
  272. e.hit = True
  273. e.energy -= 1
  274. if e.energy == 0:
  275. e.active = False
  276. else:#是小型敌机
  277. e.active = False
  278. #绘制大型敌机
  279. for each in big_enemies:
  280. if each.active: #检测是否还活着
  281. each.move()
  282. if each.hit:
  283. #绘制被击中的特效
  284. screen.blit(each.image_hit, each.rect)
  285. each.hit = False
  286. else:
  287. if switch_image:
  288. screen.blit(each.image1, each.rect)
  289. else:
  290. screen.blit(each.image2, each.rect)
  291. # 绘制血槽
  292. pygame.draw.line(screen, BLACK, \
  293. (each.rect.left, each.rect.top - 5), \
  294. (each.rect.right, each.rect.top - 5), \
  295. 2)
  296. # 当生命大于20%显示绿色,否则显示红色
  297. energy_remain = each.energy / enemy.BigEnemy.energy
  298. if energy_remain > 0.2:
  299. energy_color = GREEN
  300. else:
  301. energy_color = RED
  302. pygame.draw.line(screen, energy_color, \
  303. (each.rect.left, each.rect.top - 5), \
  304. (each.rect.left + each.rect.width * energy_remain, \
  305. each.rect.top - 5),
  306. 2)
  307. #即将出现在界面中,播放音效
  308. if each.rect.bottom == -50:
  309. enemy3_fly_sound.play(-1) #循环播放
  310. else:
  311. #坠机
  312. if not(delay % 3):
  313. if e3_destroy_index == 0:
  314. enemy3_down_sound.play()
  315. screen.blit(each.destroy_images[e3_destroy_index], each.rect)
  316. e3_destroy_index = (e3_destroy_index + 1) % 6
  317. if e3_destroy_index == 0:
  318. enemy3_fly_sound.stop() #循环音效停止播放
  319. score += 10000
  320. each.reset()
  321. #绘制中型敌机
  322. for each in mid_enemies:
  323. if each.active: #检测是否还活着
  324. each.move()
  325. if each.hit:
  326. #绘制被击中的特效
  327. screen.blit(each.image_hit, each.rect)
  328. each.hit = False
  329. else:
  330. screen.blit(each.image, each.rect)
  331. # 绘制血槽
  332. pygame.draw.line(screen, BLACK, \
  333. (each.rect.left, each.rect.top - 5), \
  334. (each.rect.right, each.rect.top - 5), \
  335. 2)
  336. # 当生命大于20%显示绿色,否则显示红色
  337. energy_remain = each.energy / enemy.MidEnemy.energy
  338. if energy_remain > 0.2:
  339. energy_color = GREEN
  340. else:
  341. energy_color = RED
  342. pygame.draw.line(screen, energy_color, \
  343. (each.rect.left, each.rect.top - 5), \
  344. (each.rect.left + each.rect.width * energy_remain, \
  345. each.rect.top - 5), 2)
  346. else:
  347. #坠机
  348. if not(delay % 3):
  349. if e2_destroy_index == 0:
  350. enemy2_down_sound.play() #音效
  351. screen.blit(each.destroy_images[e2_destroy_index], each.rect)
  352. e2_destroy_index = (e2_destroy_index + 1) % 4
  353. if e2_destroy_index == 0:
  354. score += 6000
  355. each.reset()
  356. #绘制小型敌机
  357. for each in small_enemies:
  358. if each.active: #检测是否还活着
  359. each.move()
  360. screen.blit(each.image, each.rect)
  361. else:
  362. #坠机
  363. if not(delay % 3):
  364. if e1_destroy_index == 0:
  365. enemy1_down_sound.play() #音效
  366. screen.blit(each.destroy_images[e1_destroy_index], each.rect)
  367. e1_destroy_index = (e1_destroy_index + 1) % 4
  368. if e1_destroy_index == 0:
  369. score += 1000
  370. each.reset()
  371. #检测我方飞机是否被撞
  372. enemies_down = pygame.sprite.spritecollide(me, enemies, False, pygame.sprite.collide_mask)
  373. if enemies_down:
  374. #me.active = False
  375. for e in enemies_down:
  376. e.active = False
  377. #绘制我方飞机
  378. if me.active: #检测是否还活着
  379. if switch_image:
  380. screen.blit(me.image1, me.rect)
  381. else:
  382. screen.blit(me.image2, me.rect)
  383. else:
  384. #坠机
  385. if not(delay % 3):
  386. if me_destroy_index == 0:
  387. me_down_sound.play()
  388. screen.blit(me.destroy_images[me_destroy_index], me.rect)
  389. me_destroy_index = (me_destroy_index + 1) % 4
  390. if me_destroy_index == 0:
  391. print("game over")
  392. running = False
  393. # 绘制全屏炸弹数量
  394. bomb_text = bomb_font.render("× %d" % bomb_num, True, WHITE)
  395. text_rect = bomb_text.get_rect()
  396. screen.blit(bomb_image, (10, height - 10 - bomb_rect.height))
  397. screen.blit(bomb_text, (20 + bomb_rect.width, height - 5 - text_rect.height))
  398. # 绘制得分
  399. score_text = score_font.render("Score : %s" % str(score), True, WHITE)
  400. screen.blit(score_text, (10, 5))
  401. # 绘制暂停按钮
  402. screen.blit(paused_image, paused_rect)
  403. #切换图片
  404. if not(delay % 5): #5帧切换一次,一秒就只切换12次
  405. switch_image = not switch_image
  406. delay -= 1
  407. if not delay:
  408. delay = 100
  409. pygame.display.flip()
  410. clock.tick(60)
  411. if __name__ == "__main__":
  412. try:
  413. main()
  414. except SystemExit:
  415. pass
  416. except:
  417. traceback.print_exc()
  418. pygame.quit()
  419. input()
  420. #myplane.py
  421. import pygame
  422. class Myplane(pygame.sprite.Sprite):
  423. def __init__(self, bg_size):
  424. pygame.sprite.Sprite.__init__(self)
  425. self.image1 = pygame.image.load("images/me1.png").convert_alpha()
  426. self.image2 = pygame.image.load("images/me2.png").convert_alpha()
  427. #添加坠机图片
  428. self.destroy_images = []
  429. self.destroy_images.extend([\
  430. pygame.image.load("images/me_destroy_1.png").convert_alpha(), \
  431. pygame.image.load("images/me_destroy_2.png").convert_alpha(), \
  432. pygame.image.load("images/me_destroy_3.png").convert_alpha(), \
  433. pygame.image.load("images/me_destroy_4.png").convert_alpha() \
  434. ])
  435. self.rect = self.image1.get_rect()
  436. self.width, self.height = bg_size[0], bg_size[1]
  437. self.rect.left, self.rect.top = \
  438. (self.width - self.rect.width) // 2, \
  439. self.height - self.rect.height - 60 #减60,留给状态栏
  440. self.speed = 10
  441. self.active = True
  442. self.mask = pygame.mask.from_surface(self.image1) #将非透明部分标记为mask
  443. def moveUp(self):
  444. if self.rect.top > 0:
  445. self.rect.top -= self.speed
  446. else:
  447. self.rect.top = 0
  448. def moveDown(self):
  449. if self.rect.bottom < self.height - 60:
  450. self.rect.top += self.speed
  451. else:
  452. self.rect.bottom = self.height - 60
  453. def moveLeft(self):
  454. if self.rect.left > 0:
  455. self.rect.left -= self.speed
  456. else:
  457. self.rect.left = 0
  458. def moveRight(self):
  459. if self.rect.right < self.width:
  460. self.rect.left += self.speed
  461. else:
  462. self.rect.right = self.width

0 留言:

發佈留言