2020年9月12日星期六

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

《零基礎入門學習Python》第091講:Pygame:飛機大戰2



上節課我們實現了遊戲的背景和背景音樂,接下來,我們應該讓主角閃亮登場了,創建一個名為myplane 的模塊,然後把我方飛機的所有屬性和方法定義在裡邊。
  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.image = pygame.image.load("images/me1.png").convert_alpha()
  7. self.rect = self.image.get_rect()
  8. self.width, self.height = bg_size[0], bg_size[1]
  9. self.rect.left, self.rect.top = \
  10. (self.width - self.rect.width) // 2, \
  11. self.height - self.rect.height - 60 #减60留给状态栏
  12. self.speed = 10
  13. def moveUp(self):
  14. if self.rect.top > 0:
  15. self.rect.top -= self.speed
  16. else:
  17. self.rect.top = 0
  18. def moveDown(self):
  19. if self.rect.bottom < self.height - 60:
  20. self.rect.top += self.speed
  21. else:
  22. self.rect.bottom = self.height - 60
  23. def moveLeft(self):
  24. if self.rect.left > 0:
  25. self.rect.left -= self.speed
  26. else:
  27. self.rect.left = 0
  28. def moveRight(self):
  29. if self.rect.right < self.width:
  30. self.rect.left += self.speed
  31. else:
  32. self.rect.right = self.width
目前就實現這麼多。
那麼接下來我們就需要在main 模塊中響應用戶的鍵盤操作,響應用戶的鍵盤操作有兩種方法:
1、通過檢測事件消息,檢測到如果有KEYDOWN 或者KEYUP 事件,我們就知道是用戶按下了鍵盤按鍵。(這是我們之前常用的一種方法)
2、調用key 模塊裡的 get_pressed() 方法,會返回一個序列,該序列包含鍵盤上所有按鍵的布爾類型的值,如果這個值是True 的話,表示該按鍵被按下。
我們這裡有一個建議:對於檢測偶然觸發的鍵盤事件,我們推薦使用方法1,例如該遊戲中會設置一個全屏炸彈,按下空格鍵時爆炸,這是偶然觸發的,沒有經常觸發,這時使用第1種方法較好;對於頻繁觸發的鍵盤事件,我們則建議使用第二種方法,例如控制飛機移動的4個方向鍵,我們就使用方法2。
我們就來改一下我們的main 函數:
  1. #main.py
  2. import pygame
  3. import sys
  4. import traceback #为了更好地退出
  5. import myplane
  6. from pygame.locals import *
  7. pygame.init()
  8. pygame.mixer.init() #混音器初始化
  9. bg_size = width, height = 480, 700
  10. screen = pygame.display.set_mode(bg_size)
  11. pygame.display.set_caption("飞机大战 -- Python Demo")
  12. background = pygame.image.load("images/background.png").convert()
  13. # 载入游戏音乐
  14. pygame.mixer.music.load("sound/game_music.ogg")
  15. pygame.mixer.music.set_volume(0.2)
  16. bullet_sound = pygame.mixer.Sound("sound/bullet.wav")
  17. bullet_sound.set_volume(0.2)
  18. bomb_sound = pygame.mixer.Sound("sound/use_bomb.wav")
  19. bomb_sound.set_volume(0.2)
  20. supply_sound = pygame.mixer.Sound("sound/supply.wav")
  21. supply_sound.set_volume(0.2)
  22. get_bomb_sound = pygame.mixer.Sound("sound/get_bomb.wav")
  23. get_bomb_sound.set_volume(0.2)
  24. get_bullet_sound = pygame.mixer.Sound("sound/get_bullet.wav")
  25. get_bullet_sound.set_volume(0.2)
  26. upgrade_sound = pygame.mixer.Sound("sound/upgrade.wav")
  27. upgrade_sound.set_volume(0.2)
  28. enemy3_fly_sound = pygame.mixer.Sound("sound/enemy3_flying.wav")
  29. enemy3_fly_sound.set_volume(0.2)
  30. enemy1_down_sound = pygame.mixer.Sound("sound/enemy1_down.wav")
  31. enemy1_down_sound.set_volume(0.2)
  32. enemy2_down_sound = pygame.mixer.Sound("sound/enemy2_down.wav")
  33. enemy2_down_sound.set_volume(0.2)
  34. enemy3_down_sound = pygame.mixer.Sound("sound/enemy3_down.wav")
  35. enemy3_down_sound.set_volume(0.5)
  36. me_down_sound = pygame.mixer.Sound("sound/me_down.wav")
  37. me_down_sound.set_volume(0.2)
  38. def main():
  39. pygame.mixer.music.play(-1)
  40. # 生成我方飞机
  41. me = myplane.Myplane(bg_size)
  42. clock = pygame.time.Clock()
  43. running = True
  44. while running:
  45. for event in pygame.event.get():
  46. if event.type == QUIT:
  47. pygame.quit()
  48. sys.exit()
  49. #检测用户的键盘操作
  50. key_pressed = pygame.key.get_pressed()
  51. if key_pressed[K_w] or key_pressed[K_UP]:
  52. me.moveUp()
  53. if key_pressed[K_s] or key_pressed[K_DOWN]:
  54. me.moveDown()
  55. if key_pressed[K_a] or key_pressed[K_LEFT]:
  56. me.moveLeft()
  57. if key_pressed[K_d] or key_pressed[K_RIGHT]:
  58. me.moveRight()
  59. screen.blit(background, (0, 0))
  60. #绘制我方飞机
  61. screen.blit(me.image, me.rect)
  62. pygame.display.flip()
  63. clock.tick(60)
  64. if __name__ == "__main__":
  65. try:
  66. main()
  67. except SystemExit:
  68. pass
  69. except:
  70. traceback.print_exc()
  71. pygame.quit()
  72. input()
我們的飛機就生成了,也可以根據鍵盤上的AWSD 或者方向鍵進行移動控制。
我們剛才說過,為了增加我方飛機的動態效果,我們可以通過兩張圖片(me1,png 和me2.png)的切換來實現飛機冒煙的效果。
我們就只需要:
1、在myplane.py 中加多一種圖片
  1. #myplane.py
  2. class Myplane(pygame.sprite.Sprite):
  3. def __init__(self, bg_size):
  4. pygame.sprite.Sprite.__init__(self)
  5. self.image1 = pygame.image.load("images/me1.png").convert_alpha()
  6. self.image2 = pygame.image.load("images/me2.png").convert_alpha()
  7. self.rect = self.image1.get_rect()
  8. self.width, self.height = bg_size[0], bg_size[1]
  9. self.rect.left, self.rect.top = \
  10. (self.width - self.rect.width) // 2, \
  11. self.height - self.rect.height - 60 #减60,留给状态栏
  12. self.speed = 10
2、在main.py 中 
首先計算一個布爾類型的變量用於控制切換圖片;然後在繪製我方飛機這裡交叉顯示兩張圖片。
  1. #main.py
  2. def main():
  3. pygame.mixer.music.play(-1)
  4. # 生成我方飞机
  5. me = myplane.Myplane(bg_size)
  6. clock = pygame.time.Clock()
  7. #用于切换图片
  8. switch_image = True
  9. running = True
  10. while running:
  11. for event in pygame.event.get():
  12. if event.type == QUIT:
  13. pygame.quit()
  14. sys.exit()
  15. #检测用户的键盘操作
  16. key_pressed = pygame.key.get_pressed()
  17. if key_pressed[K_w] or key_pressed[K_UP]:
  18. me.moveUp()
  19. if key_pressed[K_s] or key_pressed[K_DOWN]:
  20. me.moveDown()
  21. if key_pressed[K_a] or key_pressed[K_LEFT]:
  22. me.moveLeft()
  23. if key_pressed[K_d] or key_pressed[K_RIGHT]:
  24. me.moveRight()
  25. screen.blit(background, (0, 0))
  26. #绘制我方飞机
  27. switch_image = not switch_image
  28. if switch_image:
  29. screen.blit(me.image1, me.rect)
  30. else:
  31. screen.blit(me.image,2 me.rect)
  32. pygame.display.flip()
  33. clock.tick(60)
但是我們這樣改,飛機還是沒有理想中"突突突" 的感覺,畢竟我們的幀率為60(每秒切換60次),我們最好在不影響遊戲性能的情況來延遲圖片的切換,這裡我們就使用單片機開發中常常用到的一招,增加一個延時變量:
  1. #main.py
  2. def main():
  3. pygame.mixer.music.play(-1)
  4. # 生成我方飞机
  5. me = myplane.Myplane(bg_size)
  6. clock = pygame.time.Clock()
  7. #用于切换图片
  8. switch_image = True
  9. #用于延迟
  10. delay = 100
  11. running = True
  12. while running:
  13. for event in pygame.event.get():
  14. if event.type == QUIT:
  15. pygame.quit()
  16. sys.exit()
  17. #检测用户的键盘操作
  18. key_pressed = pygame.key.get_pressed()
  19. if key_pressed[K_w] or key_pressed[K_UP]:
  20. me.moveUp()
  21. if key_pressed[K_s] or key_pressed[K_DOWN]:
  22. me.moveDown()
  23. if key_pressed[K_a] or key_pressed[K_LEFT]:
  24. me.moveLeft()
  25. if key_pressed[K_d] or key_pressed[K_RIGHT]:
  26. me.moveRight()
  27. screen.blit(background, (0, 0))
  28. #绘制我方飞机
  29. if switch_image:
  30. screen.blit(me.image1, me.rect)
  31. else:
  32. screen.blit(me.image2, me.rect)
  33. #切换图片
  34. if not(delay % 5): #5帧切换一次,一秒就只切换12次
  35. switch_image = not switch_image
  36. delay -= 1
  37. if not delay:
  38. delay = 100
  39. pygame.display.flip()
  40. clock.tick(60)
接下來就來創造敵機啦:
敵機分為小中大三個尺寸,它們的速度一次就是快中慢(越小越快),在頁面上方,我們就需要隨機創建一些敵機,可以通過在頁面外部上方5個屏幕高度範圍內隨機生成一個敵機以保證不讓敵機在一排出現。
  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. self.rect = self.image.get_rect()
  9. self.width, self.height = bg_size[0], bg_size[1]
  10. self.speed = 2
  11. self.rect.left, self.rect.top = \
  12. randint(0, self.width - self.rect.width), \
  13. randint(-5 * self.height, 0) #在页面外部上方5个屏幕高度范围内随机生成一个敌机
  14. def move(self):
  15. if self.rect.top < self.height:
  16. self.rect.top += self.speed
  17. else:
  18. self.reset()
  19. def reset(self):
  20. self.rect.left, self.rect.top = \
  21. randint(0, self.width - self.rect.width), \
  22. randint(-5 * self.height, 0)
  23. class MidEnemy(pygame.sprite.Sprite):
  24. def __init__(self, bg_size):
  25. pygame.sprite.Sprite.__init__(self)
  26. self.image = pygame.image.load("images/enemy2.png").convert_alpha()
  27. self.rect = self.image.get_rect()
  28. self.width, self.height = bg_size[0], bg_size[1]
  29. self.speed = 1
  30. self.rect.left, self.rect.top = \
  31. randint(0, self.width - self.rect.width), \
  32. randint(-10 * self.height, -self.height) #在页面外部上方1个到10个屏幕高度范围内随机生成一个敌机(1-10个,就保证了不会一开始出大一个大的)
  33. def move(self):
  34. if self.rect.top < self.height:
  35. self.rect.top += self.speed
  36. else:
  37. self.reset()
  38. def reset(self):
  39. self.rect.left, self.rect.top = \
  40. randint(0, self.width - self.rect.width), \
  41. randint(-10 * self.height, -self.height)
  42. class BigEnemy(pygame.sprite.Sprite):
  43. def __init__(self, bg_size):
  44. pygame.sprite.Sprite.__init__(self)
  45. #大型敌机有飞行特效,两张图片切换
  46. self.image1 = pygame.image.load("images/enemy3_n1.png").convert_alpha()
  47. self.image2 = pygame.image.load("images/enemy3_n2.png").convert_alpha()
  48. self.rect = self.image1.get_rect()
  49. self.width, self.height = bg_size[0], bg_size[1]
  50. self.speed = 1
  51. self.rect.left, self.rect.top = \
  52. randint(0, self.width - self.rect.width), \
  53. randint(-15 * self.height, -5 * self.height) #在页面外部上方5-15个屏幕高度范围内随机生成一个敌机
  54. def move(self):
  55. if self.rect.top < self.height:
  56. self.rect.top += self.speed
  57. else:
  58. self.reset()
  59. def reset(self):
  60. self.rect.left, self.rect.top = \
  61. randint(0, self.width - self.rect.width), \
  62. randint(-15 * self.height, -5 * self.height)
敵機的定義有了,我們接下來就在main 模塊中將它們實例化:
  1. #main.py
  2. import pygame
  3. import sys
  4. import traceback #为了更好地退出
  5. import myplane
  6. import enemy
  7. from pygame.locals import *
  8. pygame.init()
  9. pygame.mixer.init() #混音器初始化
  10. bg_size = width, height = 480, 700
  11. screen = pygame.display.set_mode(bg_size)
  12. pygame.display.set_caption("飞机大战 -- Python Demo")
  13. background = pygame.image.load("images/background.png").convert()
  14. # 载入游戏音乐
  15. pygame.mixer.music.load("sound/game_music.ogg")
  16. pygame.mixer.music.set_volume(0.2)
  17. bullet_sound = pygame.mixer.Sound("sound/bullet.wav")
  18. bullet_sound.set_volume(0.2)
  19. bomb_sound = pygame.mixer.Sound("sound/use_bomb.wav")
  20. bomb_sound.set_volume(0.2)
  21. supply_sound = pygame.mixer.Sound("sound/supply.wav")
  22. supply_sound.set_volume(0.2)
  23. get_bomb_sound = pygame.mixer.Sound("sound/get_bomb.wav")
  24. get_bomb_sound.set_volume(0.2)
  25. get_bullet_sound = pygame.mixer.Sound("sound/get_bullet.wav")
  26. get_bullet_sound.set_volume(0.2)
  27. upgrade_sound = pygame.mixer.Sound("sound/upgrade.wav")
  28. upgrade_sound.set_volume(0.2)
  29. enemy3_fly_sound = pygame.mixer.Sound("sound/enemy3_flying.wav")
  30. enemy3_fly_sound.set_volume(0.2)
  31. enemy1_down_sound = pygame.mixer.Sound("sound/enemy1_down.wav")
  32. enemy1_down_sound.set_volume(0.2)
  33. enemy2_down_sound = pygame.mixer.Sound("sound/enemy2_down.wav")
  34. enemy2_down_sound.set_volume(0.2)
  35. enemy3_down_sound = pygame.mixer.Sound("sound/enemy3_down.wav")
  36. enemy3_down_sound.set_volume(0.5)
  37. me_down_sound = pygame.mixer.Sound("sound/me_down.wav")
  38. me_down_sound.set_volume(0.2)
  39. def add_small_enemies(group1, group2, num):
  40. for i in range(num):
  41. e1 = enemy.SmallEnemy(bg_size)
  42. group1.add(e1)
  43. group2.add(e1)
  44. def add_mid_enemies(group1, group2, num):
  45. for i in range(num):
  46. e2 = enemy.MidEnemy(bg_size)
  47. group1.add(e2)
  48. group2.add(e2)
  49. def add_big_enemies(group1, group2, num):
  50. for i in range(num):
  51. e3 = enemy.BigEnemy(bg_size)
  52. group1.add(e3)
  53. group2.add(e3)
  54. def main():
  55. pygame.mixer.music.play(-1)
  56. # 生成我方飞机
  57. me = myplane.Myplane(bg_size)
  58. #生成敌方飞机
  59. enemies = pygame.sprite.Group()
  60. # 生成敌方小型飞机
  61. small_enemies = pygame.sprite.Group()
  62. add_small_enemies(small_enemies, enemies, 15)
  63. # 生成敌方中型飞机
  64. mid_enemies = pygame.sprite.Group()
  65. add_mid_enemies(mid_enemies, enemies, 4)
  66. # 生成敌方大型飞机
  67. big_enemies = pygame.sprite.Group()
  68. add_big_enemies(big_enemies, enemies, 2)
  69. clock = pygame.time.Clock()
  70. #用于切换图片
  71. switch_image = True
  72. #用于延迟
  73. delay = 100
  74. running = True
  75. while running:
  76. for event in pygame.event.get():
  77. if event.type == QUIT:
  78. pygame.quit()
  79. sys.exit()
  80. #检测用户的键盘操作
  81. key_pressed = pygame.key.get_pressed()
  82. if key_pressed[K_w] or key_pressed[K_UP]:
  83. me.moveUp()
  84. if key_pressed[K_s] or key_pressed[K_DOWN]:
  85. me.moveDown()
  86. if key_pressed[K_a] or key_pressed[K_LEFT]:
  87. me.moveLeft()
  88. if key_pressed[K_d] or key_pressed[K_RIGHT]:
  89. me.moveRight()
  90. screen.blit(background, (0, 0))
  91. #绘制大型敌机
  92. for each in big_enemies:
  93. each.move()
  94. if switch_image:
  95. screen.blit(each.image1, each.rect)
  96. else:
  97. screen.blit(each.image2, each.rect)
  98. #即将出现在界面中,播放音效
  99. if each.rect.bottom > -50:
  100. enemy3_fly_sound.play()
  101. #绘制中型敌机
  102. for each in mid_enemies:
  103. each.move()
  104. screen.blit(each.image, each.rect)
  105. #绘制小型敌机
  106. for each in small_enemies:
  107. each.move()
  108. screen.blit(each.image, each.rect)
  109. #绘制我方飞机
  110. if switch_image:
  111. screen.blit(me.image1, me.rect)
  112. else:
  113. screen.blit(me.image2, me.rect)
  114. #切换图片
  115. if not(delay % 5): #5帧切换一次,一秒就只切换12次
  116. switch_image = not switch_image
  117. delay -= 1
  118. if not delay:
  119. delay = 100
  120. pygame.display.flip()
  121. clock.tick(60)
  122. if __name__ == "__main__":
  123. try:
  124. main()
  125. except SystemExit:
  126. pass
  127. except:
  128. traceback.print_exc()
  129. pygame.quit()
  130. input()
我們可以看到敵機依次出來,由於我們現在還沒有做碰撞檢測,所以它們可以友好的交叉飛過,我們在下節課中會教大家如何做完美的碰撞檢測,因為飛機是不規則的圖形,所有我們沒辦法像之前講小球一樣弄一個半徑。但是別擔心,這種不規則的圖形也可以做完美的碰撞檢測,大家拭目以待吧。

0 留言:

發佈留言