2020年9月12日星期六

94 A 《零基礎入門學習Python》筆記 第094講:Pygame:飛機大戰5 上

《零基礎入門學習Python》筆記    第094講:Pygame:飛機大戰5

我們接下來在遊戲界面的左上角設置一個得分顯示區域,實時顯示玩家得分,我們的規則如下:
擊落小中大敵機分別可以獲得1000,6000,10000分。
我們現在main 函數中添加一個score 變量統計用戶的得分,並設置顯示分數的字體,我們已經放在素材庫的font 文件夾中了。
  1. # 统计得分
  2. score = 0
  3. score_font = pygame.font.Font("font/font.ttf", 36) #字体
然後在大型敵機墜機要重建之前加10000分,中小型敵機同理。
然後在繪製我方飛機時把分數繪製到界面上。
  1. # 绘制得分
  2. score_text = score_font.render("Score : %s" % str(score), True, WHITE)
  3. screen.blit(score_text, (10, 5))
接下來,我們在界面右上角添加一個暫停符。
這裡總共有4張圖片,左邊兩張表示要暫停,右邊兩個表示要恢復遊戲。兩組各有一張深色的和淺色的,當鼠標移到圖像上方時(並沒有點擊鼠標),圖片會加深,起到一個提示的效果。
我們通過響應MOUSEBUTTONDOWN 的事件可以知道用戶是否點下鼠標,在點下鼠標那一剎那,我們去獲得鼠標的位置,就可以知道玩家是否點下了暫停按鈕。通過響應MOUSEMOTION 事件,我們可以改變按鈕的樣式。
在main函數里加一個pause 變量作為判斷暫停的標誌。
  1. # 标志是否暂停游戏
  2. paused = False
  3. pause_nor_image = pygame.image.load("images/pause_nor.png").convert_alpha()
  4. pause_pressed_image = pygame.image.load("images/pause_pressed.png").convert_alpha()
  5. resume_nor_image = pygame.image.load("images/resume_nor.png").convert_alpha()
  6. resume_pressed_image = pygame.image.load("images/resume_pressed.png").convert_alpha()
  7. paused_rect = pause_nor_image.get_rect()
  8. paused_rect.left, paused_rect.top = width - paused_rect.width - 10, 10
  9. paused_image = pause_nor_image
接下來我們響應MOUSEBUTTONDOWN 事件和MOUSEMOTION 事件:
  1. elif event.type == MOUSEBUTTONDOWN:
  2. if event.button == 1 and paused_rect.collidepoint(event.pos):
  3. paused = not paused
  4. elif event.type == MOUSEMOTION:
  5. if paused_rect.collidepoint(event.pos):
  6. if paused:
  7. paused_image = resume_pressed_image
  8. else:
  9. paused_image = pause_pressed_image
  10. else:
  11. if paused:
  12. paused_image = resume_nor_image
  13. else:
  14. paused_image = pause_nor_image
接下來我們來談一下難度的控制:
因為敵人一成不變的慢慢的出現,對於玩家來說是無法忍受的,玩家希望的遊戲體驗是刺激。我們要讓遊戲的難度隨著玩家的得分增加而增加,這裡將游戲難度劃分為5 個級別,每提升一個級別,就會增加一些敵機或者說增加敵機的移動速度。
  1. # 设置难度级别
  2. level = 1
  1. # 根据用户的得分增加难度
  2. if level == 1 and score > 50000:
  3. level = 2
  4. upgrade_sound.play()
  5. # 增加3架小型敌机、2架中型敌机和1架大型敌机
  6. add_small_enemies(small_enemies, enemies, 3)
  7. add_mid_enemies(mid_enemies, enemies, 2)
  8. add_big_enemies(big_enemies, enemies, 1)
  9. # 提升小型敌机的速度
  10. inc_speed(small_enemies, 1)
  11. elif level == 2 and score > 300000:
  12. level = 3
  13. upgrade_sound.play()
  14. # 增加5架小型敌机、3架中型敌机和2架大型敌机
  15. add_small_enemies(small_enemies, enemies, 5)
  16. add_mid_enemies(mid_enemies, enemies, 3)
  17. add_big_enemies(big_enemies, enemies, 2)
  18. # 提升小型敌机的速度
  19. inc_speed(small_enemies, 1)
  20. inc_speed(mid_enemies, 1)
  21. elif level == 3 and score > 600000:
  22. level = 4
  23. upgrade_sound.play()
  24. # 增加5架小型敌机、3架中型敌机和2架大型敌机
  25. add_small_enemies(small_enemies, enemies, 5)
  26. add_mid_enemies(mid_enemies, enemies, 3)
  27. add_big_enemies(big_enemies, enemies, 2)
  28. # 提升小型敌机的速度
  29. inc_speed(small_enemies, 1)
  30. inc_speed(mid_enemies, 1)
  31. elif level == 4 and score > 1000000:
  32. level = 5
  33. upgrade_sound.play()
  34. # 增加5架小型敌机、3架中型敌机和2架大型敌机
  35. add_small_enemies(small_enemies, enemies, 5)
  36. add_mid_enemies(mid_enemies, enemies, 3)
  37. add_big_enemies(big_enemies, enemies, 2)
  38. # 提升小型敌机的速度
  39. inc_speed(small_enemies, 1)
  40. inc_speed(mid_enemies, 1)
但是考慮到,如果level 到5 的時候,敵機的密集度就會很大,玩家就很容易陷入不利的局面,這就需要給玩家提供大殺招:全屏爆炸。
這個大殺招的觸發是通過空格鍵來觸發的,初始化情況下,我們帶著3顆全屏炸彈,我們可以通過每30秒一次的補給獲得,但是最多你的飛機只能裝載3顆。
由於觸發全屏炸彈是屬於偶然事件,因此我們通過響應KEYDOWN事件,再檢測event.key 是否為 K_SPACE 就可以了。
我們首先定義全屏炸彈:
  1. # 全屏炸弹
  2. bomb_image = pygame.image.load("images/bomb.png").convert_alpha()
  3. bomb_rect = bomb_image.get_rect()
  4. bomb_font = pygame.font.Font("font/font.ttf", 48)
  5. bomb_num = 3
然後實現 空格觸發全屏炸彈
  1. #空格触发全屏炸弹
  2. elif event.type == KEYDOWN:
  3. if event.key == K_SPACE:
  4. if bomb_num:
  5. bomb_num -= 1
  6. bomb_sound.play()
  7. for each in enemies:
  8. if each.rect.bottom > 0:
  9. each.active = False
在界面左下角繪製全屏炸彈數量
  1. # 绘制全屏炸弹数量
  2. bomb_text = bomb_font.render("× %d" % bomb_num, True, WHITE)
  3. text_rect = bomb_text.get_rect()
  4. screen.blit(bomb_image, (10, height - 10 - bomb_rect.height))
  5. screen.blit(bomb_text, (20 + bomb_rect.width, height - 5 - text_rect.height))
今天的任務就到這里為止了,在全屏炸彈用完之後,我們可以通過每30秒一次的補給來獲得,這個在下節課講解。
下面給出今天實現的全部代碼:
  1. #main.py
  2. import pygame
  3. import sys
  4. import traceback #为了更好地退出
  5. import myplane
  6. import enemy
  7. import bullet
  8. from pygame.locals import *
  9. pygame.init()
  10. pygame.mixer.init() #混音器初始化
  11. bg_size = width, height = 480, 700
  12. screen = pygame.display.set_mode(bg_size)
  13. pygame.display.set_caption("飞机大战 -- Python Demo")
  14. background = pygame.image.load("images/background.png").convert()
  15. #生成一些颜色
  16. BLACK = (0, 0, 0)
  17. WHITE = (255, 255, 255)
  18. GREEN = (0, 255, 0)
  19. RED = (255, 0, 0)
  20. # 载入游戏音乐
  21. pygame.mixer.music.load("sound/game_music.ogg")
  22. pygame.mixer.music.set_volume(0.2)
  23. bullet_sound = pygame.mixer.Sound("sound/bullet.wav")
  24. bullet_sound.set_volume(0.2)
  25. bomb_sound = pygame.mixer.Sound("sound/use_bomb.wav")
  26. bomb_sound.set_volume(0.2)
  27. supply_sound = pygame.mixer.Sound("sound/supply.wav")
  28. supply_sound.set_volume(0.2)
  29. get_bomb_sound = pygame.mixer.Sound("sound/get_bomb.wav")
  30. get_bomb_sound.set_volume(0.2)
  31. get_bullet_sound = pygame.mixer.Sound("sound/get_bullet.wav")
  32. get_bullet_sound.set_volume(0.2)
  33. upgrade_sound = pygame.mixer.Sound("sound/upgrade.wav")
  34. upgrade_sound.set_volume(0.2)
  35. enemy3_fly_sound = pygame.mixer.Sound("sound/enemy3_flying.wav")
  36. enemy3_fly_sound.set_volume(0.5)
  37. enemy1_down_sound = pygame.mixer.Sound("sound/enemy1_down.wav")
  38. enemy1_down_sound.set_volume(0.2)
  39. enemy2_down_sound = pygame.mixer.Sound("sound/enemy2_down.wav")
  40. enemy2_down_sound.set_volume(0.2)
  41. enemy3_down_sound = pygame.mixer.Sound("sound/enemy3_down.wav")
  42. enemy3_down_sound.set_volume(0.5)
  43. me_down_sound = pygame.mixer.Sound("sound/me_down.wav")
  44. me_down_sound.set_volume(0.2)
  45. def add_small_enemies(group1, group2, num):
  46. for i in range(num):
  47. e1 = enemy.SmallEnemy(bg_size)
  48. group1.add(e1)
  49. group2.add(e1)
  50. def add_mid_enemies(group1, group2, num):
  51. for i in range(num):
  52. e2 = enemy.MidEnemy(bg_size)
  53. group1.add(e2)
  54. group2.add(e2)
  55. def add_big_enemies(group1, group2, num):
  56. for i in range(num):
  57. e3 = enemy.BigEnemy(bg_size)
  58. group1.add(e3)
  59. group2.add(e3)
  60. def inc_speed(target, inc): #加速函数
  61. for each in target:
  62. each.speed += inc
  63. def main():
  64. pygame.mixer.music.play(-1)
  65. # 生成我方飞机
  66. me = myplane.Myplane(bg_size)
  67. #生成敌方飞机
  68. enemies = pygame.sprite.Group()
  69. # 生成敌方小型飞机
  70. small_enemies = pygame.sprite.Group()
  71. add_small_enemies(small_enemies, enemies, 15)
  72. # 生成敌方中型飞机
  73. mid_enemies = pygame.sprite.Group()
  74. add_mid_enemies(mid_enemies, enemies, 4)
  75. # 生成敌方大型飞机
  76. big_enemies = pygame.sprite.Group()
  77. add_big_enemies(big_enemies, enemies, 2)
  78. # 生成普通子弹
  79. bullet1 = []
  80. bullet1_index = 0
  81. BULLET1_NUM = 4
  82. for i in range(BULLET1_NUM):
  83. bullet1.append(bullet.Bullet1(me.rect.midtop)) #me.rect.midtop:机头位置
  84. clock = pygame.time.Clock()
  85. #中弹图片索引
  86. e1_destroy_index = 0
  87. e2_destroy_index = 0
  88. e3_destroy_index = 0
  89. me_destroy_index = 0
  90. # 统计得分
  91. score = 0
  92. score_font = pygame.font.Font("font/font.ttf", 36) #得分字体
  93. # 标志是否暂停游戏
  94. paused = False
  95. pause_nor_image = pygame.image.load("images/pause_nor.png").convert_alpha()
  96. pause_pressed_image = pygame.image.load("images/pause_pressed.png").convert_alpha()
  97. resume_nor_image = pygame.image.load("images/resume_nor.png").convert_alpha()
  98. resume_pressed_image = pygame.image.load("images/resume_pressed.png").convert_alpha()
  99. paused_rect = pause_nor_image.get_rect()
  100. paused_rect.left, paused_rect.top = width - paused_rect.width - 10, 10
  101. paused_image = pause_nor_image
  102. # 设置难度级别
  103. level = 1
  104. # 全屏炸弹
  105. bomb_image = pygame.image.load("images/bomb.png").convert_alpha()
  106. bomb_rect = bomb_image.get_rect()
  107. bomb_font = pygame.font.Font("font/font.ttf", 48)
  108. bomb_num = 3
  109. #用于切换图片
  110. switch_image = True
  111. #用于延迟
  112. delay = 100
  113. running = True
  114. while running:
  115. for event in pygame.event.get():
  116. if event.type == QUIT:
  117. pygame.quit()
  118. sys.exit()
  119. elif event.type == MOUSEBUTTONDOWN:
  120. if event.button == 1 and paused_rect.collidepoint(event.pos):
  121. paused = not paused
  122. elif event.type == MOUSEMOTION:
  123. if paused_rect.collidepoint(event.pos):
  124. if paused:
  125. paused_image = resume_pressed_image
  126. else:
  127. paused_image = pause_pressed_image
  128. else:
  129. if paused:
  130. paused_image = resume_nor_image
  131. else:
  132. paused_image = pause_nor_image
  133. #空格触发全屏炸弹
  134. elif event.type == KEYDOWN:
  135. if event.key == K_SPACE:
  136. if bomb_num:
  137. bomb_num -= 1
  138. bomb_sound.play()
  139. for each in enemies:
  140. if each.rect.bottom > 0:
  141. each.active = False
  142. # 根据用户的得分增加难度
  143. if level == 1 and score > 50000:
  144. level = 2
  145. upgrade_sound.play()
  146. # 增加3架小型敌机、2架中型敌机和1架大型敌机
  147. add_small_enemies(small_enemies, enemies, 3)
  148. add_mid_enemies(mid_enemies, enemies, 2)
  149. add_big_enemies(big_enemies, enemies, 1)
  150. # 提升小型敌机的速度
  151. inc_speed(small_enemies, 1)
  152. elif level == 2 and score > 300000:
  153. level = 3
  154. upgrade_sound.play()
  155. # 增加5架小型敌机、3架中型敌机和2架大型敌机
  156. add_small_enemies(small_enemies, enemies, 5)
  157. add_mid_enemies(mid_enemies, enemies, 3)
  158. add_big_enemies(big_enemies, enemies, 2)
  159. # 提升小型敌机的速度
  160. inc_speed(small_enemies, 1)
  161. inc_speed(mid_enemies, 1)
  162. elif level == 3 and score > 600000:
  163. level = 4
  164. upgrade_sound.play()
  165. # 增加5架小型敌机、3架中型敌机和2架大型敌机
  166. add_small_enemies(small_enemies, enemies, 5)
  167. add_mid_enemies(mid_enemies, enemies, 3)
  168. add_big_enemies(big_enemies, enemies, 2)
  169. # 提升小型敌机的速度
  170. inc_speed(small_enemies, 1)
  171. inc_speed(mid_enemies, 1)
  172. elif level == 4 and score > 1000000:
  173. level = 5
  174. upgrade_sound.play()
  175. # 增加5架小型敌机、3架中型敌机和2架大型敌机
  176. add_small_enemies(small_enemies, enemies, 5)
  177. add_mid_enemies(mid_enemies, enemies, 3)
  178. add_big_enemies(big_enemies, enemies, 2)
  179. # 提升小型敌机的速度
  180. inc_speed(small_enemies, 1)
  181. inc_speed(mid_enemies, 1)
  182. screen.blit(background, (0, 0))
  183. if not paused:
  184. #检测用户的键盘操作
  185. key_pressed = pygame.key.get_pressed()
  186. if key_pressed[K_w] or key_pressed[K_UP]:
  187. me.moveUp()
  188. if key_pressed[K_s] or key_pressed[K_DOWN]:
  189. me.moveDown()
  190. if key_pressed[K_a] or key_pressed[K_LEFT]:
  191. me.moveLeft()
  192. if key_pressed[K_d] or key_pressed[K_RIGHT]:
  193. me.moveRight()
  194. # 发射子弹
  195. if not(delay % 10):
  196. bullet1[bullet1_index].reset(me.rect.midtop)
  197. bullet1_index = (bullet1_index + 1) % BULLET1_NUM
  198. # 检测子弹是否击中敌机
  199. for b in bullet1:
  200. if b.active:
  201. b.move()
  202. screen.blit(b.image, b.rect)
  203. enemy_hit = pygame.sprite.spritecollide(b, enemies, False, pygame.sprite.collide_mask)
  204. if enemy_hit:
  205. b.active = False
  206. for e in enemy_hit:
  207. if e in mid_enemies or e in big_enemies:
  208. e.hit = True
  209. e.energy -= 1
  210. if e.energy == 0:
  211. e.active = False
  212. else:#是小型敌机
  213. e.active = False
  214. #绘制大型敌机
  215. for each in big_enemies:
  216. if each.active: #检测是否还活着
  217. each.move()
  218. if each.hit:
  219. #绘制被击中的特效
  220. screen.blit(each.image_hit, each.rect)
  221. each.hit = False
  222. else:
  223. if switch_image:
  224. screen.blit(each.image1, each.rect)
  225. else:
  226. screen.blit(each.image2, each.rect)
  227. # 绘制血槽
  228. pygame.draw.line(screen, BLACK, \
  229. (each.rect.left, each.rect.top - 5), \
  230. (each.rect.right, each.rect.top - 5), \
  231. 2)
  232. # 当生命大于20%显示绿色,否则显示红色
  233. energy_remain = each.energy / enemy.BigEnemy.energy
  234. if energy_remain > 0.2:
  235. energy_color = GREEN
  236. else:
  237. energy_color = RED
  238. pygame.draw.line(screen, energy_color, \
  239. (each.rect.left, each.rect.top - 5), \
  240. (each.rect.left + each.rect.width * energy_remain, \
  241. each.rect.top - 5),
  242. 2)
  243. #即将出现在界面中,播放音效
  244. if each.rect.bottom == -50:
  245. enemy3_fly_sound.play(-1) #循环播放
  246. else:
  247. #坠机
  248. if not(delay % 3):
  249. if e3_destroy_index == 0:
  250. enemy3_down_sound.play()
  251. screen.blit(each.destroy_images[e3_destroy_index], each.rect)
  252. e3_destroy_index = (e3_destroy_index + 1) % 6
  253. if e3_destroy_index == 0:
  254. enemy3_fly_sound.stop() #循环音效停止播放
  255. score += 10000
  256. each.reset()
  257. #绘制中型敌机
  258. for each in mid_enemies:
  259. if each.active: #检测是否还活着
  260. each.move()
  261. if each.hit:
  262. #绘制被击中的特效
  263. screen.blit(each.image_hit, each.rect)
  264. each.hit = False
  265. else:
  266. screen.blit(each.image, each.rect)
  267. # 绘制血槽
  268. pygame.draw.line(screen, BLACK, \
  269. (each.rect.left, each.rect.top - 5), \
  270. (each.rect.right, each.rect.top - 5), \
  271. 2)
  272. # 当生命大于20%显示绿色,否则显示红色
  273. energy_remain = each.energy / enemy.MidEnemy.energy
  274. if energy_remain > 0.2:
  275. energy_color = GREEN
  276. else:
  277. energy_color = RED
  278. pygame.draw.line(screen, energy_color, \
  279. (each.rect.left, each.rect.top - 5), \
  280. (each.rect.left + each.rect.width * energy_remain, \
  281. each.rect.top - 5), 2)
  282. else:
  283. #坠机
  284. if not(delay % 3):
  285. if e2_destroy_index == 0:
  286. enemy2_down_sound.play() #音效
  287. screen.blit(each.destroy_images[e2_destroy_index], each.rect)
  288. e2_destroy_index = (e2_destroy_index + 1) % 4
  289. if e2_destroy_index == 0:
  290. score += 6000
  291. each.reset()
  292. #绘制小型敌机
  293. for each in small_enemies:
  294. if each.active: #检测是否还活着
  295. each.move()
  296. screen.blit(each.image, each.rect)
  297. else:
  298. #坠机
  299. if not(delay % 3):
  300. if e1_destroy_index == 0:
  301. enemy1_down_sound.play() #音效
  302. screen.blit(each.destroy_images[e1_destroy_index], each.rect)
  303. e1_destroy_index = (e1_destroy_index + 1) % 4
  304. if e1_destroy_index == 0:
  305. score += 1000
  306. each.reset()
  307. #检测我方飞机是否被撞
  308. enemies_down = pygame.sprite.spritecollide(me, enemies, False, pygame.sprite.collide_mask)
  309. if enemies_down:
  310. #me.active = False
  311. for e in enemies_down:
  312. e.active = False
  313. #绘制我方飞机
  314. if me.active: #检测是否还活着
  315. if switch_image:
  316. screen.blit(me.image1, me.rect)
  317. else:
  318. screen.blit(me.image2, me.rect)
  319. else:
  320. #坠机
  321. if not(delay % 3):
  322. if me_destroy_index == 0:
  323. me_down_sound.play()
  324. screen.blit(me.destroy_images[me_destroy_index], me.rect)
  325. me_destroy_index = (me_destroy_index + 1) % 4
  326. if me_destroy_index == 0:
  327. print("game over")
  328. running = False
  329. # 绘制全屏炸弹数量
  330. bomb_text = bomb_font.render("× %d" % bomb_num, True, WHITE)
  331. text_rect = bomb_text.get_rect()
  332. screen.blit(bomb_image, (10, height - 10 - bomb_rect.height))
  333. screen.blit(bomb_text, (20 + bomb_rect.width, height - 5 - text_rect.height))
  334. # 绘制得分
  335. score_text = score_font.render("Score : %s" % str(score), True, WHITE)
  336. screen.blit(score_text, (10, 5))
  337. # 绘制暂停按钮
  338. screen.blit(paused_image, paused_rect)
  339. #切换图片
  340. if not(delay % 5): #5帧切换一次,一秒就只切换12次
  341. switch_image = not switch_image
  342. delay -= 1
  343. if not delay:
  344. delay = 100
  345. pygame.display.flip()
  346. clock.tick(60)
  347. if __name__ == "__main__":
  348. try:
  349. main()
  350. except SystemExit:
  351. pass
  352. except:
  353. traceback.print_exc()
  354. pygame.quit()
  355. input()

0 留言:

發佈留言