溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

使用python制作一個飛機(jī)大戰(zhàn)游戲

發(fā)布時間:2021-03-20 15:09:59 來源:億速云 閱讀:140 作者:Leah 欄目:開發(fā)技術(shù)

使用python制作一個飛機(jī)大戰(zhàn)游戲?相信很多沒有經(jīng)驗的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。

具體內(nèi)容如下

import gc
import random

import pygame

# 玩家飛機(jī)精靈類
import Constants


class HeroPlane(pygame.sprite.Sprite):
 def __init__(self, screen):
  # 調(diào)用父類初始化方法
  # pygame.sprite.Sprite.__init__(self)
  super().__init__()
  # 窗口
  self.screen = screen
  # 一個玩家飛機(jī)圖片
  self.image = pygame.image.load('./feiji/feiji.png')
  # 飛機(jī)矩形區(qū)域?qū)ο?
  self.rect = self.image.get_rect()
  # 左上角坐標(biāo)
  self.rect.topleft = [512 / 2 - 116 / 2, 600]
  # 飛機(jī)的速度
  self.speed = 15
  # 一個精靈組 存放所有的子彈精靈
  self.bullets = pygame.sprite.Group()
  # 血量 初始100
  self.blood_value = 100

  # 標(biāo)記玩家飛機(jī)是否over
  self.is_remove = False

  # 顯示爆炸圖片的 索引 從0開始
  self.mIndex = 0

  # 存放爆炸圖片 的列表
  self.bomb_mImages = []

  for v in range(1, 15):
   # 把所有圖片 存到列表里 每個圖片 存2次
   self.bomb_mImages.append(pygame.image.load('./feiji/image ' + str(v) + '.png'))
   self.bomb_mImages.append(pygame.image.load('./feiji/image ' + str(v) + '.png'))

 def kill_blood(self, kill_value=10):
  """血量減少"""
  self.blood_value -= kill_value
  print('被打中了,血量還剩%s' % self.blood_value)
  if self.blood_value <= 0:
   # 避免血量負(fù)值
   self.blood_value = 0
   # 血量<=0 設(shè)置is_remove 為True
   self.is_remove = True

 def key_control(self):
  """按鍵監(jiān)聽 操作飛機(jī)上下左右和發(fā)子彈"""
  # 監(jiān)聽鍵盤事件
  key_pressed = pygame.key.get_pressed() # 注意這種方式是能夠檢測到一直按下不松開的鍵盤

  if key_pressed[pygame.K_w] or key_pressed[pygame.K_UP]:
   # top值如果小于0 就到了最頂部 不要再移動了
   if self.rect.top > 3:
    self.rect.top -= self.speed
  if key_pressed[pygame.K_s] or key_pressed[pygame.K_DOWN]:
   if self.rect.bottom <= 768:
    self.rect.bottom += self.speed
  if key_pressed[pygame.K_a] or key_pressed[pygame.K_LEFT]:
   if self.rect.left > 0:
    self.rect.left -= self.speed
  if key_pressed[pygame.K_d] or key_pressed[pygame.K_RIGHT]:
   if self.rect.right < 520:
    self.rect.right += self.speed
  if key_pressed[pygame.K_SPACE]:
   # print("space")
   # 創(chuàng)建3個子彈
   bullet1 = Bullet(self.screen, self.rect.left, self.rect.top, 1)
   bullet2 = Bullet(self.screen, self.rect.left, self.rect.top, 2)
   bullet3 = Bullet(self.screen, self.rect.left, self.rect.top, 3)
   # 添加到精靈組
   self.bullets.add(bullet1, bullet2, bullet3)

 def bomb(self):
  print('玩家飛機(jī)爆炸中')
  """顯示爆炸圖片"""
  self.screen.blit(self.bomb_mImages[self.mIndex], self.rect)
  self.mIndex += 1
  print('mIndex', self.mIndex)
  if self.mIndex >= len(self.bomb_mImages):
   # 播放到了最后 爆炸結(jié)束 返回True
   return True

 def update(self):
  if self.is_remove:
   print('玩家飛機(jī)掛掉')
   # 如果玩家飛機(jī)掛掉
   if self.bomb():
    # 爆炸結(jié)束
    print('爆炸結(jié)束')
    self.rect.topleft = [-200, -200]
    # 開啟倒計時
    pygame.time.set_timer(Constants.game_over_id, 1000)
    # 把玩家飛機(jī)指向None 停止update
    manager.hero = None
  else:
   self.key_control()
   self.display()

 def display(self):
  # if self.blood_value <= 0:
  #  # 如果血量小于0 移出窗口
  #  self.rect.topleft = [-200, -200]

  # 把飛機(jī)顯示到窗口上 飛機(jī) 116*100
  self.screen.blit(self.image, self.rect)
  # 更新精靈組里的子彈位置
  self.bullets.update()
  # 精靈組所有子彈顯示到窗口
  self.bullets.draw(self.screen)


class Bullet(pygame.sprite.Sprite):
 # path_num表示散彈中 子彈是哪一個
 def __init__(self, screen, planex, planey, path_num):
  # 調(diào)用父類初始化方法
  # pygame.sprite.Sprite.__init__(self)
  super().__init__()
  # 窗口
  self.screen = screen
  # 一個子彈圖片
  self.image = pygame.image.load('./feiji/bullet_12.png')
  # 子彈矩形區(qū)域?qū)ο?
  self.rect = self.image.get_rect()
  # 子彈左上角坐標(biāo)
  self.rect.topleft = [planex + 48, planey - 20]
  # 子彈的速度
  self.speed = 15
  # path_num表示散彈中 子彈是哪一個
  self.path_num = path_num

 def update(self):
  """修改子彈坐標(biāo)"""
  self.rect.top -= self.speed
  if self.rect.bottom < 0:
   # 子彈已經(jīng)移出了屏幕上方 這時把子彈從精靈組刪除
   self.kill()
  if self.path_num == 1:
   pass
  elif self.path_num == 2:
   # 如果等于2 就是左側(cè)的散彈
   self.rect.left -= 10
  elif self.path_num == 3:
   # 如果等于3 就是右側(cè)的散彈
   self.rect.right += 10


# 敵機(jī)精靈類
class EnemyPlane(pygame.sprite.Sprite):
 # 創(chuàng)建類屬性 存放所有飛機(jī)的所有的子彈
 all_bullets = pygame.sprite.Group()

 def __init__(self, screen):
  # 調(diào)用父類初始化方法
  # pygame.sprite.Sprite.__init__(self)
  super().__init__()
  # 窗口
  self.screen = screen
  # 一個玩家飛機(jī)圖片
  self.image = pygame.image.load('./feiji/img-plane_5.png')
  # 飛機(jī)矩形區(qū)域?qū)ο?
  self.rect = self.image.get_rect()
  # 左上角坐標(biāo) x坐標(biāo)隨機(jī)
  self.rect.topleft = [random.randint(0, 412), 0]
  # 飛機(jī)的速度
  self.speed = 3
  # 一個精靈組 存放所有的子彈精靈
  self.bullets = pygame.sprite.Group()
  # 敵機(jī)的左右方向 默認(rèn)一開始向右
  self.direction = 'right'
  # 子彈的精靈組
  self.bullets = pygame.sprite.Group()
  # 標(biāo)記敵機(jī)是否被擊中 是否要刪除
  self.is_remove = False

  # 顯示爆炸圖片的 索引 從0開始
  self.mIndex = 0

  # 存放爆炸圖片 的列表
  self.bomb_mImages = []

  for v in range(1, 14):
   # 把所有圖片 存到列表里 每個圖片 存2次
   self.bomb_mImages.append(pygame.image.load('./feiji/image ' + str(v) + '.png'))
   self.bomb_mImages.append(pygame.image.load('./feiji/image ' + str(v) + '.png'))

  # 記錄爆炸位置
  self.x = 0
  self.y = 0

 def auto_move(self):
  """自動移動"""
  # 向下移動
  self.rect.bottom += self.speed
  # 如果飛機(jī)向下移出邊界 刪除它
  if self.rect.top > Manager.height:
   self.kill()

  # 按不同方向左右移動
  if self.direction == 'right':
   self.rect.right += 6
  elif self.direction == 'left':
   self.rect.right -= 6

  # 超出左右邊界 更改移動方向
  if self.rect.right >= Manager.width:
   self.direction = 'left'
  if self.rect.left <= 0:
   self.direction = 'right'

 def auto_fire(self):
  # 用一個隨機(jī)數(shù)
  num = random.randint(1, 40)
  # 判斷如果等于1就發(fā)射一個子彈 ,降低了概率
  if num == 5:
   # 生成敵機(jī)子彈
   bullet = EnemyBullet(self.screen, self.rect.left, self.rect.top)
   # 添加到精靈組
   self.bullets.add(bullet)
   # 把子彈添加到類的all_bullets里 用來碰撞檢測
   EnemyPlane.all_bullets.add(bullet)

 def bomb(self):
  """顯示爆炸圖片"""
  if self.mIndex >= len(self.bomb_mImages):
   # 播放到了最后 爆炸結(jié)束 返回True
   return True
  self.screen.blit(self.bomb_mImages[self.mIndex], (self.x, self.y))
  self.mIndex += 1

 def update(self):
  if self.is_remove:
   if self.rect.left != -200:
    # 記錄爆炸時的位置
    self.x = self.rect.left
    self.y = self.rect.top
   # 如果已經(jīng)被擊中 把飛機(jī)移除窗口 防止繼續(xù)碰撞檢測
   self.rect.left = -200
   self.rect.top = -200
   # 顯示爆炸效果
   if self.bomb() and not self.bullets:
    # 如果爆炸結(jié)束 把自己從精靈組刪除
    self.kill()
  else:
   # 移動
   self.auto_move()
   # 開火
   self.auto_fire()
   # 顯示
   self.display()

  self.bullet_show()

 def display(self):
  # 把飛機(jī)顯示到窗口上 飛機(jī) 116*100
  self.screen.blit(self.image, self.rect)

 def bullet_show(self):
  if self.bullets:
   # 敵機(jī)子彈更新
   self.bullets.update()
   # 敵機(jī)子彈顯示
   self.bullets.draw(self.screen)


class EnemyBullet(pygame.sprite.Sprite):
 # path_num表示散彈中 子彈是哪一個
 def __init__(self, screen, x, y):
  # 調(diào)用父類初始化方法
  # pygame.sprite.Sprite.__init__(self)
  super().__init__()
  # 窗口
  self.screen = screen
  # 一個子彈圖片
  self.image = pygame.image.load('./feiji/bullet_6.png')
  # 子彈矩形區(qū)域?qū)ο?
  self.rect = self.image.get_rect()
  # 子彈左上角坐標(biāo)
  self.rect.topleft = [x + 40, y + 60]
  # 子彈的速度
  self.speed = 10

 def update(self):
  """修改子彈坐標(biāo)"""
  self.rect.bottom += self.speed
  # 如果子彈向下移出邊界 刪除它
  if self.rect.top > Manager.height:
   self.kill()


# 游戲音樂
class GameSound(object):
 def __init__(self):
  pygame.mixer.init() # 音樂模塊初始化
  pygame.mixer.music.load("./feiji/Jamesketed.mp3")
  pygame.mixer.music.set_volume(0.5) # 聲音大小 一半

  self.__bomb = pygame.mixer.Sound("./feiji/bomb.wav")

 def playBackgroundMusic(self):
  # 開始播放背景音樂 -1表示一直重復(fù)播放
  pygame.mixer.music.play(-1)

 def playBombSound(self):
  pygame.mixer.Sound.play(self.__bomb) # 爆炸音樂


class GameBackground(object):
 # 初始化地圖
 def __init__(self, screen):
  self.mImage1 = pygame.image.load("./feiji/img_bg_level_4.jpg")
  self.mImage2 = pygame.image.load("./feiji/img_bg_level_4.jpg")
  # 窗口
  self.screen = screen
  # 輔助移動地圖
  self.y1 = 0
  self.y2 = -Manager.height # -768

 def update(self):
  self.move()
  self.draw()

 # 移動地圖
 def move(self):
  self.y1 += 2
  self.y2 += 2
  if self.y1 >= Manager.height:
   self.y1 = 0
  if self.y2 >= 0:
   self.y2 = -Manager.height

 # 繪制地圖
 def draw(self):
  self.screen.blit(self.mImage1, (0, self.y1))
  self.screen.blit(self.mImage2, (0, self.y2))


class Manager:
 hero: HeroPlane
 # 創(chuàng)建寬高
 width = 512
 height = 768

 def __init__(self):
  # pygame初始化 否則找不到字體文件
  pygame.init()

  # 1 創(chuàng)建一個窗口 參數(shù)1是寬高,參數(shù)2 附加參數(shù) 參3是顏色深度
  self.screen = pygame.display.set_mode((self.width, self.height), 0, 32)

  # 2創(chuàng)建背景圖的對象
  # self.background = pygame.image.load('./feiji/img_bg_level_5.jpg')
  self.background = GameBackground(self.screen)

  # 創(chuàng)建飛機(jī)對象
  self.hero = HeroPlane(self.screen)

  # 創(chuàng)建時鐘對象
  self.clock = pygame.time.Clock()

  # 敵機(jī)的精靈組
  self.enemys = pygame.sprite.Group()

  # 初始化音效對象
  self.sound = GameSound()
  # 定義分?jǐn)?shù)屬性
  self.score = 0
  # 倒計時時間
  self.over_time = 3

 def exit(self):
  # 執(zhí)行退出代碼
  pygame.quit()
  # 程序的退出
  exit()

 def new_enemy(self):
  # 創(chuàng)建敵機(jī)對象
  enemy = EnemyPlane(self.screen)
  # 添加到精靈組
  self.enemys.add(enemy)

 def drawText(self, text, x, y, textHeight=30, fontColor=(255, 255, 255), backgroudColor=None):

  # 通過字體文件獲得字體對象 參數(shù)1 字體文件 參數(shù)2 字體大小
  font_obj = pygame.font.Font('./feiji/baddf.ttf', textHeight)
  # 1文字 2是否抗鋸齒 3文字顏色 4背景顏色
  text_obj = font_obj.render(text, True, fontColor, backgroudColor) # 配置要顯示的文字
  # 獲得要顯示的對象的rect
  text_rect = text_obj.get_rect()
  # 設(shè)置顯示對象的坐標(biāo)
  text_rect.topleft = (x, y)
  # 繪制字 到指定區(qū)域 參1是文字對象 參2 矩形對象
  self.screen.blit(text_obj, text_rect)

 def game_over_timer(self):
  """執(zhí)行倒計時"""
  self.over_time -= 1
  if self.over_time == 0:
   # 停止倒計時
   pygame.time.set_timer(Constants.game_over_id, 0)
   # 重新開始游戲
   self.start_game()

 def show_over_text(self):
  print('self.over_time', self.over_time)
  # 游戲結(jié)束 顯示倒計時時間
  self.drawText('gameover %d' % self.over_time, 0, Manager.height / 2, textHeight=50,
      fontColor=[0, 0, 0])

 def start_game(self):
  global manager
  # 情況敵機(jī)子彈的精靈組
  EnemyPlane.all_bullets.empty()
  manager = Manager()
  # 垃圾回收 提示python解釋器 要回收了
  gc.collect()
  manager.main()

 def main(self):
  # 播放背景音樂
  self.sound.playBackgroundMusic()

  # 參1eventid是事件id,自己定義(0 - 32之間)不要和已用的pygame的其它事件id沖突,
  # 參2是定時事件的間隔時間,單位是毫秒
  pygame.time.set_timer(Constants.new_enemy, 500)

  while True:
   # 控制每s執(zhí)行的次數(shù)
   self.clock.tick(60)
   # 獲取事件 并且處理
   for event in pygame.event.get():
    # 判斷事件的類型是否是退出
    if event.type == pygame.QUIT:
     # 退出
     self.exit()
    elif event.type == Constants.new_enemy:
     # 等于20 說明定時器生效 添加一個敵機(jī)
     # print('添加一個敵機(jī)')
     self.new_enemy()
    elif event.type == Constants.game_over_id:
     print('倒計時 33333')
     # 顯示倒計時時間
     self.game_over_timer()

   # 3把背景圖顯示到窗口上
   # self.screen.blit(self.background, (0, 0))
   self.background.update()

   self.drawText('分?jǐn)?shù):%s' % self.score, 0, 0)

   if self.hero:
    self.drawText('血量:%s' % self.hero.blood_value, 0, 30)
    # 更新飛機(jī)
    self.hero.update()
    # if self.hero.blood_value <= 0 and not self.hero.bullets.sprites():
    #  # 把玩家飛機(jī)引用指向None 盡快釋放
    #  self.hero = None
   else:
    self.drawText('血量:0', 0, 30)

   # 更新 敵機(jī)
   self.enemys.update()

   # 如果飛機(jī)已經(jīng)掛掉 就一直顯示倒計時
   if not self.hero:
    # 顯示倒計時
    self.show_over_text()

   # 判斷 玩家飛機(jī) 和敵機(jī)是否都存在 self.enemys.sprites()返回精靈組對應(yīng)的精靈列表
   if self.hero and self.enemys.sprites():
    # 碰撞檢測 返回的碰撞到的 敵機(jī)列表
    collide_enemys = pygame.sprite.spritecollide(self.hero, self.enemys, False, pygame.sprite.collide_mask)
    if collide_enemys:
     # 如果列表不為空 說明碰到了敵機(jī)
     print('碰到了敵機(jī)')
     # 爆炸聲音
     self.sound.playBombSound()
     self.hero.kill_blood(100)
     for enemy_item in collide_enemys:
      # 標(biāo)記敵機(jī)已經(jīng)被撞到
      enemy_item.is_remove = True

   # 判斷 玩家飛機(jī) 和 玩家飛機(jī)的子彈 和 敵機(jī)是否都存在
   if self.hero and self.hero.bullets and self.enemys:
    # 檢測玩家飛機(jī)的子彈 和敵機(jī)的碰撞
    # 返回是個字典 格式{<Bullet sprite(in 0 groups)>: [<EnemyPlane sprite(in 0 groups)>]}
    # {碰撞的子彈1:[打中的敵機(jī)1,打中的敵機(jī)2],碰撞的子彈2:[打中的敵機(jī)1,打中的敵機(jī)5]}
    collode_dict = pygame.sprite.groupcollide(self.hero.bullets, self.enemys, True, False,
               pygame.sprite.collide_mask)

    # 1多個子彈打中同一個飛機(jī) # 2不同子彈 打中不同飛機(jī) # 所有加分值時 要去除重復(fù)的敵機(jī)

    # print(collode_dict)
    if collode_dict:
     # 爆炸聲音
     self.sound.playBombSound()

     print(self.score)
     # 用一個集合 添加敵機(jī) 去除重復(fù)的
     enemyset = set()
     # 獲取所有打中的敵機(jī)列表,然后遍歷
     for v_enemys in collode_dict.values():
      # 遍歷敵機(jī)列表
      for enemy_item in v_enemys:
       # print(id(enemy_item))
       enemyset.add(enemy_item)
       # 標(biāo)記敵機(jī)已經(jīng)被擊中
       enemy_item.is_remove = True

     # 碰撞后 +10分*集合里敵機(jī)的數(shù)量
     self.score += 10 * len(enemyset)

   # 判斷 玩家飛機(jī) 和 和 敵機(jī)子彈
   if self.hero and EnemyPlane.all_bullets:
    # 檢測玩家 和敵機(jī)子彈的碰撞
    collide_bullets = pygame.sprite.spritecollide(self.hero, EnemyPlane.all_bullets, True,
                pygame.sprite.collide_mask)
    if collide_bullets:
     # 如果碰到了 就減少10*子彈數(shù)量的血量
     self.hero.kill_blood(10 * len(collide_bullets))

   # 2 顯示窗口
   pygame.display.update()


if __name__ == '__main__':
 manager = Manager()
 manager.main()

看完上述內(nèi)容,你們掌握使用python制作一個飛機(jī)大戰(zhàn)游戲的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI