2020年9月12日星期六

93B《零基礎入門學習Python》筆記 第093講:Pygame:飛機大戰4 下

這節課實現的完整代碼如下:
  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. GREEN = (0, 255, 0)
  18. RED = (255, 0, 0)
  19. # 载入游戏音乐
  20. pygame.mixer.music.load("sound/game_music.ogg")
  21. pygame.mixer.music.set_volume(0.2)
  22. bullet_sound = pygame.mixer.Sound("sound/bullet.wav")
  23. bullet_sound.set_volume(0.2)
  24. bomb_sound = pygame.mixer.Sound("sound/use_bomb.wav")
  25. bomb_sound.set_volume(0.2)
  26. supply_sound = pygame.mixer.Sound("sound/supply.wav")
  27. supply_sound.set_volume(0.2)
  28. get_bomb_sound = pygame.mixer.Sound("sound/get_bomb.wav")
  29. get_bomb_sound.set_volume(0.2)
  30. get_bullet_sound = pygame.mixer.Sound("sound/get_bullet.wav")
  31. get_bullet_sound.set_volume(0.2)
  32. upgrade_sound = pygame.mixer.Sound("sound/upgrade.wav")
  33. upgrade_sound.set_volume(0.2)
  34. enemy3_fly_sound = pygame.mixer.Sound("sound/enemy3_flying.wav")
  35. enemy3_fly_sound.set_volume(0.5)
  36. enemy1_down_sound = pygame.mixer.Sound("sound/enemy1_down.wav")
  37. enemy1_down_sound.set_volume(0.2)
  38. enemy2_down_sound = pygame.mixer.Sound("sound/enemy2_down.wav")
  39. enemy2_down_sound.set_volume(0.2)
  40. enemy3_down_sound = pygame.mixer.Sound("sound/enemy3_down.wav")
  41. enemy3_down_sound.set_volume(0.5)
  42. me_down_sound = pygame.mixer.Sound("sound/me_down.wav")
  43. me_down_sound.set_volume(0.2)
  44. def add_small_enemies(group1, group2, num):
  45. for i in range(num):
  46. e1 = enemy.SmallEnemy(bg_size)
  47. group1.add(e1)
  48. group2.add(e1)
  49. def add_mid_enemies(group1, group2, num):
  50. for i in range(num):
  51. e2 = enemy.MidEnemy(bg_size)
  52. group1.add(e2)
  53. group2.add(e2)
  54. def add_big_enemies(group1, group2, num):
  55. for i in range(num):
  56. e3 = enemy.BigEnemy(bg_size)
  57. group1.add(e3)
  58. group2.add(e3)
  59. def main():
  60. pygame.mixer.music.play(-1)
  61. # 生成我方飞机
  62. me = myplane.Myplane(bg_size)
  63. #生成敌方飞机
  64. enemies = pygame.sprite.Group()
  65. # 生成敌方小型飞机
  66. small_enemies = pygame.sprite.Group()
  67. add_small_enemies(small_enemies, enemies, 15)
  68. # 生成敌方中型飞机
  69. mid_enemies = pygame.sprite.Group()
  70. add_mid_enemies(mid_enemies, enemies, 4)
  71. # 生成敌方大型飞机
  72. big_enemies = pygame.sprite.Group()
  73. add_big_enemies(big_enemies, enemies, 2)
  74. # 生成普通子弹
  75. bullet1 = []
  76. bullet1_index = 0
  77. BULLET1_NUM = 4
  78. for i in range(BULLET1_NUM):
  79. bullet1.append(bullet.Bullet1(me.rect.midtop)) #me.rect.midtop:机头位置
  80. clock = pygame.time.Clock()
  81. #中弹图片索引
  82. e1_destroy_index = 0
  83. e2_destroy_index = 0
  84. e3_destroy_index = 0
  85. me_destroy_index = 0
  86. #用于切换图片
  87. switch_image = True
  88. #用于延迟
  89. delay = 100
  90. running = True
  91. while running:
  92. for event in pygame.event.get():
  93. if event.type == QUIT:
  94. pygame.quit()
  95. sys.exit()
  96. #检测用户的键盘操作
  97. key_pressed = pygame.key.get_pressed()
  98. if key_pressed[K_w] or key_pressed[K_UP]:
  99. me.moveUp()
  100. if key_pressed[K_s] or key_pressed[K_DOWN]:
  101. me.moveDown()
  102. if key_pressed[K_a] or key_pressed[K_LEFT]:
  103. me.moveLeft()
  104. if key_pressed[K_d] or key_pressed[K_RIGHT]:
  105. me.moveRight()
  106. screen.blit(background, (0, 0))
  107. # 发射子弹
  108. if not(delay % 10):
  109. bullet1[bullet1_index].reset(me.rect.midtop)
  110. bullet1_index = (bullet1_index + 1) % BULLET1_NUM
  111. # 检测子弹是否击中敌机
  112. for b in bullet1:
  113. if b.active:
  114. b.move()
  115. screen.blit(b.image, b.rect)
  116. enemy_hit = pygame.sprite.spritecollide(b, enemies, False, pygame.sprite.collide_mask)
  117. if enemy_hit:
  118. b.active = False
  119. for e in enemy_hit:
  120. if e in mid_enemies or e in big_enemies:
  121. e.hit = True
  122. e.energy -= 1
  123. if e.energy == 0:
  124. e.active = False
  125. else:#是小型敌机
  126. e.active = False
  127. #绘制大型敌机
  128. for each in big_enemies:
  129. if each.active: #检测是否还活着
  130. each.move()
  131. if each.hit:
  132. #绘制被击中的特效
  133. screen.blit(each.image_hit, each.rect)
  134. each.hit = False
  135. else:
  136. if switch_image:
  137. screen.blit(each.image1, each.rect)
  138. else:
  139. screen.blit(each.image2, each.rect)
  140. # 绘制血槽
  141. pygame.draw.line(screen, BLACK, \
  142. (each.rect.left, each.rect.top - 5), \
  143. (each.rect.right, each.rect.top - 5), \
  144. 2)
  145. # 当生命大于20%显示绿色,否则显示红色
  146. energy_remain = each.energy / enemy.BigEnemy.energy
  147. if energy_remain > 0.2:
  148. energy_color = GREEN
  149. else:
  150. energy_color = RED
  151. pygame.draw.line(screen, energy_color, \
  152. (each.rect.left, each.rect.top - 5), \
  153. (each.rect.left + each.rect.width * energy_remain, \
  154. each.rect.top - 5),
  155. 2)
  156. #即将出现在界面中,播放音效
  157. if each.rect.bottom == -50:
  158. enemy3_fly_sound.play(-1) #循环播放
  159. else:
  160. #坠机
  161. if not(delay % 3):
  162. if e3_destroy_index == 0:
  163. enemy3_down_sound.play()
  164. screen.blit(each.destroy_images[e3_destroy_index], each.rect)
  165. e3_destroy_index = (e3_destroy_index + 1) % 6
  166. if e3_destroy_index == 0:
  167. enemy3_fly_sound.stop() #循环音效停止播放
  168. each.reset()
  169. #绘制中型敌机
  170. for each in mid_enemies:
  171. if each.active: #检测是否还活着
  172. each.move()
  173. if each.hit:
  174. #绘制被击中的特效
  175. screen.blit(each.image_hit, each.rect)
  176. each.hit = False
  177. else:
  178. screen.blit(each.image, each.rect)
  179. # 绘制血槽
  180. pygame.draw.line(screen, BLACK, \
  181. (each.rect.left, each.rect.top - 5), \
  182. (each.rect.right, each.rect.top - 5), \
  183. 2)
  184. # 当生命大于20%显示绿色,否则显示红色
  185. energy_remain = each.energy / enemy.MidEnemy.energy
  186. if energy_remain > 0.2:
  187. energy_color = GREEN
  188. else:
  189. energy_color = RED
  190. pygame.draw.line(screen, energy_color, \
  191. (each.rect.left, each.rect.top - 5), \
  192. (each.rect.left + each.rect.width * energy_remain, \
  193. each.rect.top - 5), 2)
  194. else:
  195. #坠机
  196. if not(delay % 3):
  197. if e2_destroy_index == 0:
  198. enemy2_down_sound.play() #音效
  199. screen.blit(each.destroy_images[e2_destroy_index], each.rect)
  200. e2_destroy_index = (e2_destroy_index + 1) % 4
  201. if e2_destroy_index == 0:
  202. each.reset()
  203. #绘制小型敌机
  204. for each in small_enemies:
  205. if each.active: #检测是否还活着
  206. each.move()
  207. screen.blit(each.image, each.rect)
  208. else:
  209. #坠机
  210. if not(delay % 3):
  211. if e1_destroy_index == 0:
  212. enemy1_down_sound.play() #音效
  213. screen.blit(each.destroy_images[e1_destroy_index], each.rect)
  214. e1_destroy_index = (e1_destroy_index + 1) % 4
  215. if e1_destroy_index == 0:
  216. each.reset()
  217. #检测我方飞机是否被撞
  218. enemies_down = pygame.sprite.spritecollide(me, enemies, False, pygame.sprite.collide_mask)
  219. if enemies_down:
  220. #me.active = False
  221. for e in enemies_down:
  222. e.active = False
  223. #绘制我方飞机
  224. if me.active: #检测是否还活着
  225. if switch_image:
  226. screen.blit(me.image1, me.rect)
  227. else:
  228. screen.blit(me.image2, me.rect)
  229. else:
  230. #坠机
  231. if not(delay % 3):
  232. if me_destroy_index == 0:
  233. me_down_sound.play()
  234. screen.blit(me.destroy_images[me_destroy_index], me.rect)
  235. me_destroy_index = (me_destroy_index + 1) % 4
  236. if me_destroy_index == 0:
  237. print("game over")
  238. running = False
  239. #切换图片
  240. if not(delay % 5): #5帧切换一次,一秒就只切换12次
  241. switch_image = not switch_image
  242. delay -= 1
  243. if not delay:
  244. delay = 100
  245. pygame.display.flip()
  246. clock.tick(60)
  247. if __name__ == "__main__":
  248. try:
  249. main()
  250. except SystemExit:
  251. pass
  252. except:
  253. traceback.print_exc()
  254. pygame.quit()
  255. input()
  1. #myplane.py
  2. import pygame
  3. class Myplane(pygame.sprite.Sprite):
  4. def __init__(self, bg_size):
  5. pygame.sprite.Sprite.__init__(self)
  6. self.image1 = pygame.image.load("images/me1.png").convert_alpha()
  7. self.image2 = pygame.image.load("images/me2.png").convert_alpha()
  8. #添加坠机图片
  9. self.destroy_images = []
  10. self.destroy_images.extend([\
  11. pygame.image.load("images/me_destroy_1.png").convert_alpha(), \
  12. pygame.image.load("images/me_destroy_2.png").convert_alpha(), \
  13. pygame.image.load("images/me_destroy_3.png").convert_alpha(), \
  14. pygame.image.load("images/me_destroy_4.png").convert_alpha() \
  15. ])
  16. self.rect = self.image1.get_rect()
  17. self.width, self.height = bg_size[0], bg_size[1]
  18. self.rect.left, self.rect.top = \
  19. (self.width - self.rect.width) // 2, \
  20. self.height - self.rect.height - 60 #减60,留给状态栏
  21. self.speed = 10
  22. self.active = True
  23. self.mask = pygame.mask.from_surface(self.image1) #将非透明部分标记为mask
  24. def moveUp(self):
  25. if self.rect.top > 0:
  26. self.rect.top -= self.speed
  27. else:
  28. self.rect.top = 0
  29. def moveDown(self):
  30. if self.rect.bottom < self.height - 60:
  31. self.rect.top += self.speed
  32. else:
  33. self.rect.bottom = self.height - 60
  34. def moveLeft(self):
  35. if self.rect.left > 0:
  36. self.rect.left -= self.speed
  37. else:
  38. self.rect.left = 0
  39. def moveRight(self):
  40. if self.rect.right < self.width:
  41. self.rect.left += self.speed
  42. else:
  43. self.rect.right = self.width
  1. #enemy.py
  2. import pygame
  3. from random import *
  4. class SmallEnemy(pygame.sprite.Sprite):
  5. def __init__(self, bg_size):
  6. pygame.sprite.Sprite.__init__(self)
  7. self.image = pygame.image.load("images/enemy1.png").convert_alpha()
  8. #添加坠机图片
  9. self.destroy_images = []
  10. self.destroy_images.extend([\
  11. pygame.image.load("images/enemy1_down1.png").convert_alpha(), \
  12. pygame.image.load("images/enemy1_down2.png").convert_alpha(), \
  13. pygame.image.load("images/enemy1_down3.png").convert_alpha(), \
  14. pygame.image.load("images/enemy1_down4.png").convert_alpha() \
  15. ])
  16. self.rect = self.image.get_rect()
  17. self.width, self.height = bg_size[0], bg_size[1]
  18. self.speed = 2
  19. self.active = True
  20. self.rect.left, self.rect.top = \
  21. randint(0, self.width - self.rect.width), \
  22. randint(-5 * self.height, 0) #在页面外部上方5个屏幕高度范围内随机生成一个敌机
  23. self.mask = pygame.mask.from_surface(self.image) #将非透明部分标记为mask
  24. def move(self):
  25. if self.rect.top < self.height:
  26. self.rect.top += self.speed
  27. else:
  28. self.reset()
  29. def reset(self):
  30. self.active = True
  31. self.rect.left, self.rect.top = \
  32. randint(0, self.width - self.rect.width), \
  33. randint(-5 * self.height, 0)
  34. class MidEnemy(pygame.sprite.Sprite):
  35. energy = 8
  36. def __init__(self, bg_size):
  37. pygame.sprite.Sprite.__init__(self)
  38. self.image = pygame.image.load("images/enemy2.png").convert_alpha()
  39. self.image_hit = pygame.image.load("images/enemy2_hit.png").convert_alpha()#中弹图片
  40. #添加坠机图片
  41. self.destroy_images = []
  42. self.destroy_images.extend([\
  43. pygame.image.load("images/enemy2_down1.png").convert_alpha(), \
  44. pygame.image.load("images/enemy2_down2.png").convert_alpha(), \
  45. pygame.image.load("images/enemy2_down3.png").convert_alpha(), \
  46. pygame.image.load("images/enemy2_down4.png").convert_alpha() \
  47. ])
  48. self.rect = self.image.get_rect()
  49. self.width, self.height = bg_size[0], bg_size[1]
  50. self.speed = 1
  51. self.active = True
  52. self.rect.left, self.rect.top = \
  53. randint(0, self.width - self.rect.width), \
  54. randint(-10 * self.height, -self.height) #在页面外部上方1个到10个屏幕高度范围内随机生成一个敌机(1-10个,就保证了不会一开始出大一个大的)
  55. self.mask = pygame.mask.from_surface(self.image) #将非透明部分标记为mask
  56. self.energy = MidEnemy.energy
  57. self.hit = False #检测是否被击中的属性
  58. def move(self):
  59. if self.rect.top < self.height:
  60. self.rect.top += self.speed
  61. else:
  62. self.reset()
  63. def reset(self):
  64. self.active = True
  65. self.enery = MidEnemy.energy
  66. self.rect.left, self.rect.top = \
  67. randint(0, self.width - self.rect.width), \
  68. randint(-10 * self.height, -self.height)
  69. class BigEnemy(pygame.sprite.Sprite):
  70. energy = 20
  71. def __init__(self, bg_size):
  72. pygame.sprite.Sprite.__init__(self)
  73. #大型敌机有飞行特效,两张图片切换
  74. self.image1 = pygame.image.load("images/enemy3_n1.png").convert_alpha()
  75. self.image2 = pygame.image.load("images/enemy3_n2.png").convert_alpha()
  76. self.image_hit = pygame.image.load("images/enemy3_hit.png").convert_alpha()#中弹图片
  77. #添加坠机图片
  78. self.destroy_images = []
  79. self.destroy_images.extend([\
  80. pygame.image.load("images/enemy3_down1.png").convert_alpha(), \
  81. pygame.image.load("images/enemy3_down2.png").convert_alpha(), \
  82. pygame.image.load("images/enemy3_down3.png").convert_alpha(), \
  83. pygame.image.load("images/enemy3_down4.png").convert_alpha(), \
  84. pygame.image.load("images/enemy3_down5.png").convert_alpha(), \
  85. pygame.image.load("images/enemy3_down6.png").convert_alpha() \
  86. ])
  87. self.rect = self.image1.get_rect()
  88. self.width, self.height = bg_size[0], bg_size[1]
  89. self.speed = 1
  90. self.active = True
  91. self.rect.left, self.rect.top = \
  92. randint(0, self.width - self.rect.width), \
  93. randint(-15 * self.height, -5 * self.height) #在页面外部上方5-15个屏幕高度范围内随机生成一个敌机
  94. self.mask = pygame.mask.from_surface(self.image1) #将非透明部分标记为mask
  95. self.energy = BigEnemy.energy
  96. self.hit = False #检测是否被击中的属性
  97. def move(self):
  98. if self.rect.top < self.height:
  99. self.rect.top += self.speed
  100. else:
  101. self.reset()
  102. def reset(self):
  103. self.active = True
  104. self.enery = BigEnemy.energy
  105. self.rect.left, self.rect.top = \
  106. randint(0, self.width - self.rect.width), \
  107. randint(-15 * self.height, -5 * self.height)
  1. #bullet.py
  2. import pygame
  3. class Bullet1(pygame.sprite.Sprite):#普通子弹,一次一发
  4. def __init__(self, position):
  5. pygame.sprite.Sprite.__init__(self)
  6. self.image = pygame.image.load("images/bullet1.png").convert_alpha()
  7. self.rect = self.image.get_rect()
  8. self.rect.left, self.rect.top = position #把飞机机头位置给子弹位置
  9. self.speed = 12
  10. self.active = True
  11. self.mask = pygame.mask.from_surface(self.image) #非透明部分
  12. def move(self):
  13. self.rect.top -= self.speed
  14. if self.rect.top < 0: #射出屏幕外
  15. self.active = False
  16. def reset(self, position):
  17. self.rect.left, self.rect.top = position
  18. self.active = True
(未完待續)

0 留言:

發佈留言