<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          用Python實現(xiàn)坦克大戰(zhàn)游戲 | 干貨貼

          共 9783字,需瀏覽 20分鐘

           ·

          2020-10-12 20:35

          點擊上方小白學(xué)視覺”,選擇加"星標(biāo)"或“置頂

          重磅干貨,第一時間送達


          作者 |?李秋鍵
          轉(zhuǎn)載 | AI科技大本營(rgznai100)


          《坦克大戰(zhàn)》是1985年日本南夢宮Namco游戲公司在任天堂FC平臺上,推出的一款多方位平面射擊游戲。游戲以坦克戰(zhàn)斗及保衛(wèi)基地為主題,屬于策略型聯(lián)機類。同時也是FC平臺上少有的內(nèi)建關(guān)卡編輯器的幾個游戲之一,玩家可自己創(chuàng)建獨特的關(guān)卡,并通過獲取一些道具使坦克和基地得到強化。而今天我們就將利用python還原以下坦克大戰(zhàn)的制作。


          ?

          實驗前的準(zhǔn)備


          首先我們使用的Python版本是3.6.5所用到的模塊如下:

          • Pygame模塊用來創(chuàng)建游戲整體框架、精靈等基本架構(gòu);

          • OS模塊用來加載本地文件(包括音樂,背景、圖片等素材)。



          精靈類程序


          其中精靈類設(shè)置作為基本程序框架用來主函數(shù)的調(diào)用,其中包括子彈類程序、食物類、家類、磚墻樹木等障礙物類、坦克類。具體程序布局如下:

          ?

          其中子彈類程序,首先需要建立bullet.py程序,建立類包括子彈位置、方向、圖片加載、子彈速度等基本信息。具體代碼如下:


          '''子彈'''class Bullet(pygame.sprite.Sprite):  def __init__(self, bullet_image_paths, screensize, direction, position, border_len, is_stronger=False, speed=8, **kwargs):    pygame.sprite.Sprite.__init__(self)    self.bullet_image_paths = bullet_image_paths    self.width, self.height = screensize    self.direction = direction    self.position = position    self.image = pygame.image.load(self.bullet_image_paths.get(direction))    self.rect = self.image.get_rect()    self.rect.center = position    # 地圖邊緣寬度    self.border_len = border_len    # 是否為加強版子彈(加強版可碎鐵墻)    self.is_stronger = is_stronger    # 子彈速度    self.speed = speed  '''移動子彈, 若子彈越界, 則返回True, 否則為False'''  def move(self):    if self.direction == 'up':      self.rect = self.rect.move(0, -self.speed)    elif self.direction == 'down':      self.rect = self.rect.move(0, self.speed)    elif self.direction == 'left':      self.rect = self.rect.move(-self.speed, 0)    elif self.direction == 'right':      self.rect = self.rect.move(self.speed, 0)    if (self.rect.top < self.border_len) or (self.rect.bottom > self.height) or (self.rect.left < self.border_len) or (self.rect.right > self.width):      return True????return?False


          食物獎勵類,建立food.py作為坦克吃到食物時增加生命等基本獎勵:


          '''食物類. 用于獲得獎勵'''class Foods(pygame.sprite.Sprite):  def __init__(self, food_image_paths, screensize, **kwargs):    pygame.sprite.Sprite.__init__(self)    self.name = random.choice(list(food_image_paths.keys()))    self.image = pygame.image.load(food_image_paths.get(self.name))    self.rect = self.image.get_rect()    self.rect.left, self.rect.top = random.randint(100, screensize[0]-100), random.randint(100, screensize[1]-100)    self.exist_time = 1000  def update(self):    self.exist_time -= 1????return?True?if?self.exist_time?


          坦克家類,建立home.py存儲家基本信息(包括是否存活、圖片加載、位置尺寸等)。


          '''大本營類'''class Home(pygame.sprite.Sprite):  def __init__(self, position, imagepaths, **kwargs):    pygame.sprite.Sprite.__init__(self)    self.imagepaths = imagepaths    self.image = pygame.image.load(self.imagepaths[0])    self.rect = self.image.get_rect()    self.rect.left, self.rect.top = position    self.alive = True  '''被摧毀'''  def setDead(self):    self.image = pygame.image.load(self.imagepaths[1])    self.alive = False  '''畫到屏幕上'''  def draw(self, screen):????screen.blit(self.image,?self.rect)


          磚墻等障礙物類,建立scenes.py其中也是主要位置尺寸的布局:


          '''磚墻'''class Brick(pygame.sprite.Sprite):  def __init__(self, position, imagepath, **kwargs):    pygame.sprite.Sprite.__init__(self)    self.image = pygame.image.load(imagepath)    self.rect = self.image.get_rect()    self.rect.left, self.rect.top = position'''鐵墻'''class Iron(pygame.sprite.Sprite):  def __init__(self, position, imagepath, **kwargs):    pygame.sprite.Sprite.__init__(self)    self.image = pygame.image.load(imagepath)    self.rect = self.image.get_rect()    self.rect.left, self.rect.top = position'''冰'''class Ice(pygame.sprite.Sprite):  def __init__(self, position, imagepath, **kwargs):    pygame.sprite.Sprite.__init__(self)    self.image = pygame.Surface((24, 24))    for i in range(2):      for j in range(2):        self.image.blit(pygame.image.load(imagepath), (12*i, 12*j))    self.rect = self.image.get_rect()    self.rect.left, self.rect.top = position'''河流'''class River(pygame.sprite.Sprite):  def __init__(self, position, imagepath, **kwargs):    pygame.sprite.Sprite.__init__(self)    self.image = pygame.Surface((24, 24))    for i in range(2):      for j in range(2):        self.image.blit(pygame.image.load(imagepath), (12*i, 12*j))    self.rect = self.image.get_rect()    self.rect.left, self.rect.top = position'''樹'''class Tree(pygame.sprite.Sprite):  def __init__(self, position, imagepath, **kwargs):    pygame.sprite.Sprite.__init__(self)    self.image = pygame.Surface((24, 24))    for i in range(2):      for j in range(2):        self.image.blit(pygame.image.load(imagepath), (12*i, 12*j))    self.rect = self.image.get_rect()????self.rect.left,?self.rect.top?=?position


          坦克類,建立tanks.py包括坦克數(shù)量名稱、初始位置等信息:


          '''玩家坦克類'''class PlayerTank(pygame.sprite.Sprite):  def __init__(self, name, player_tank_image_paths, position, border_len, screensize, direction='up', bullet_image_paths=None, protected_mask_path=None, boom_image_path=None, **kwargs):    pygame.sprite.Sprite.__init__(self)    # 玩家1/玩家2    self.name = name    # 坦克圖片路徑    self.player_tank_image_paths = player_tank_image_paths.get(name)    # 地圖邊緣寬度    self.border_len = border_len    # 屏幕大小    self.screensize = screensize    # 初始坦克方向    self.init_direction = direction    # 初始位置    self.init_position = position    # 子彈圖片    self.bullet_image_paths = bullet_image_paths    # 保護罩圖片路徑    self.protected_mask = pygame.image.load(protected_mask_path)    self.protected_mask_flash_time = 25    self.protected_mask_flash_count = 0    self.protected_mask_pointer = False    # 坦克爆炸圖    self.boom_image = pygame.image.load(boom_image_path)    self.boom_last_time = 5    self.booming_flag = False    self.boom_count = 0    # 坦克生命數(shù)量    self.num_lifes = 3    # 重置    self.reset()  '''移動'''  def move(self, direction, scene_elems, player_tanks_group, enemy_tanks_group, home):    # 爆炸時無法移動    if self.booming_flag:      return    # 方向不一致先改變方向    if self.direction != direction:      self.setDirection(direction)      self.switch_count = self.switch_time      self.move_cache_count = self.move_cache_time    # 移動(使用緩沖)    self.move_cache_count += 1    if self.move_cache_count < self.move_cache_time:      return    self.move_cache_count = 0    if self.direction == 'up':      speed = (0, -self.speed)    elif self.direction == 'down':      speed = (0, self.speed)    elif self.direction == 'left':      speed = (-self.speed, 0)    elif self.direction == 'right':      speed = (self.speed, 0)    rect_ori = self.rect    self.rect = self.rect.move(speed)    # --碰到場景元素    for key, value in scene_elems.items():      if key in ['brick_group', 'iron_group', 'river_group']:        if pygame.sprite.spritecollide(self, value, False, None):          self.rect = rect_ori      elif key in ['ice_group']:        if pygame.sprite.spritecollide(self, value, False, None):          self.rect = self.rect.move(speed)    # --碰到其他玩家坦克    if pygame.sprite.spritecollide(self, player_tanks_group, False, None):      self.rect = rect_ori    # --碰到敵方坦克    if pygame.sprite.spritecollide(self, enemy_tanks_group, False, None):      self.rect = rect_ori    # --碰到玩家大本營    if pygame.sprite.collide_rect(self, home):      self.rect = rect_ori    # --碰到邊界    if self.rect.left < self.border_len:      self.rect.left = self.border_len    elif self.rect.right > self.screensize[0]-self.border_len:      self.rect.right = self.screensize[0] - self.border_len    elif self.rect.top < self.border_len:      self.rect.top = self.border_len    elif self.rect.bottom > self.screensize[1]-self.border_len:      self.rect.bottom = self.screensize[1] - self.border_len    # 為了坦克輪動特效切換圖片    self.switch_count += 1    if self.switch_count > self.switch_time:      self.switch_count = 0      self.switch_pointer = not self.switch_pointer??????self.image?=?self.tank_direction_image.subsurface((48*int(self.switch_pointer),?0),?(48,?48))



          游戲界面設(shè)置


          游戲界面設(shè)置包括:開始界面設(shè)置、結(jié)束界面設(shè)置和關(guān)卡切換界面設(shè)置:


          ?


          其中游戲開始界面包括玩家數(shù)的選擇和圖片音樂的加載:


          '''游戲開始界面'''def gameStartInterface(screen, cfg):  background_img = pygame.image.load(cfg.OTHER_IMAGE_PATHS.get('background'))  color_white = (255, 255, 255)  color_red = (255, 0, 0)  font = pygame.font.Font(cfg.FONTPATH, cfg.WIDTH//12)  logo_img = pygame.image.load(cfg.OTHER_IMAGE_PATHS.get('logo'))  logo_img = pygame.transform.scale(logo_img, (446, 70))  logo_rect = logo_img.get_rect()  logo_rect.centerx, logo_rect.centery = cfg.WIDTH/2, cfg.HEIGHT//4  tank_cursor = pygame.image.load(cfg.PLAYER_TANK_IMAGE_PATHS.get('player1')[0]).convert_alpha().subsurface((0, 144), (48, 48))  tank_rect = tank_cursor.get_rect()  # 玩家數(shù)量選擇  player_render_white = font.render('1 PLAYER', True, color_white)  player_render_red = font.render('1 PLAYER', True, color_red)  player_rect = player_render_white.get_rect()  player_rect.left, player_rect.top = cfg.WIDTH/2.8, cfg.HEIGHT/2.5  players_render_white = font.render('2 PLAYERS', True, color_white)  players_render_red = font.render('2 PLAYERS', True, color_red)  players_rect = players_render_white.get_rect()  players_rect.left, players_rect.top = cfg.WIDTH/2.8, cfg.HEIGHT/2  # 游戲提示  game_tip = font.render('press  to start', True, color_white)  game_tip_rect = game_tip.get_rect()  game_tip_rect.centerx, game_tip_rect.top = cfg.WIDTH/2, cfg.HEIGHT/1.4  game_tip_flash_time = 25  game_tip_flash_count = 0  game_tip_show_flag = True  # 主循環(huán)  clock = pygame.time.Clock()  is_dual_mode = False  while True:    for event in pygame.event.get():      if event.type == pygame.QUIT:        pygame.quit()        sys.exit()      elif event.type == pygame.KEYDOWN:        if event.key == pygame.K_RETURN:          return is_dual_mode        elif event.key == pygame.K_UP or event.key == pygame.K_DOWN or event.key == pygame.K_w or event.key == pygame.K_s:          is_dual_mode = not is_dual_mode    screen.blit(background_img, (0, 0))    screen.blit(logo_img, logo_rect)    game_tip_flash_count += 1    if game_tip_flash_count > game_tip_flash_time:      game_tip_show_flag = not game_tip_show_flag      game_tip_flash_count = 0    if game_tip_show_flag:      screen.blit(game_tip, game_tip_rect)    if not is_dual_mode:      tank_rect.right, tank_rect.top = player_rect.left-10, player_rect.top      screen.blit(tank_cursor, tank_rect)      screen.blit(player_render_red, player_rect)      screen.blit(players_render_white, players_rect)    else:      tank_rect.right, tank_rect.top = players_rect.left-10, players_rect.top      screen.blit(tank_cursor, tank_rect)      screen.blit(player_render_white, player_rect)      screen.blit(players_render_red, players_rect)    pygame.display.update()????clock.tick(60)


          游戲結(jié)束界面包括游戲勝利與失敗情況判斷和是否退出游戲或重新開始的設(shè)置:


          '''游戲結(jié)束界面'''def gameEndIterface(screen, cfg, is_win=True):  background_img = pygame.image.load(cfg.OTHER_IMAGE_PATHS.get('background'))  color_white = (255, 255, 255)  color_red = (255, 0, 0)  font = pygame.font.Font(cfg.FONTPATH, cfg.WIDTH//12)  # 游戲失敗圖  gameover_img = pygame.image.load(cfg.OTHER_IMAGE_PATHS.get('gameover'))  gameover_img = pygame.transform.scale(gameover_img, (150, 75))  gameover_img_rect = gameover_img.get_rect()  gameover_img_rect.midtop = cfg.WIDTH/2, cfg.HEIGHT/8  gameover_flash_time = 25  gameover_flash_count = 0  gameover_show_flag = True  # 游戲勝利與否的提示  if is_win:    font_render = font.render('Congratulations, You win!', True, color_white)  else:    font_render = font.render('Sorry, You fail!', True, color_white)  font_rect = font_render.get_rect()  font_rect.centerx, font_rect.centery = cfg.WIDTH/2, cfg.HEIGHT/3  # 用于選擇退出或重新開始  tank_cursor = pygame.image.load(cfg.PLAYER_TANK_IMAGE_PATHS.get('player1')[0]).convert_alpha().subsurface((0, 144), (48, 48))  tank_rect = tank_cursor.get_rect()  restart_render_white = font.render('RESTART', True, color_white)  restart_render_red = font.render('RESTART', True, color_red)  restart_rect = restart_render_white.get_rect()  restart_rect.left, restart_rect.top = cfg.WIDTH/2.4, cfg.HEIGHT/2  quit_render_white = font.render('QUIT', True, color_white)  quit_render_red = font.render('QUIT', True, color_red)  quit_rect = quit_render_white.get_rect()  quit_rect.left, quit_rect.top = cfg.WIDTH/2.4, cfg.HEIGHT/1.6  is_quit_game = False  # 主循環(huán)  clock = pygame.time.Clock()  while True:    for event in pygame.event.get():      if event.type == pygame.QUIT:        pygame.quit()        sys.exit()      elif event.type == pygame.KEYDOWN:        if event.key == pygame.K_RETURN:          return is_quit_game        elif event.key == pygame.K_UP or event.key == pygame.K_DOWN or event.key == pygame.K_w or event.key == pygame.K_s:          is_quit_game = not is_quit_game    screen.blit(background_img, (0, 0))    gameover_flash_count += 1    if gameover_flash_count > gameover_flash_time:      gameover_show_flag = not gameover_show_flag      gameover_flash_count = 0    if gameover_show_flag:      screen.blit(gameover_img, gameover_img_rect)    screen.blit(font_render, font_rect)    if not is_quit_game:      tank_rect.right, tank_rect.top = restart_rect.left-10, restart_rect.top      screen.blit(tank_cursor, tank_rect)      screen.blit(restart_render_red, restart_rect)      screen.blit(quit_render_white, quit_rect)    else:      tank_rect.right, tank_rect.top = quit_rect.left-10, quit_rect.top      screen.blit(tank_cursor, tank_rect)      screen.blit(restart_render_white, restart_rect)      screen.blit(quit_render_red, quit_rect)    pygame.display.update()????clock.tick(60)



          游戲界面切換主要是利用進度條加載:


          '''關(guān)卡切換界面'''def switchLevelIterface(screen, cfg, level_next=1):  background_img = pygame.image.load(cfg.OTHER_IMAGE_PATHS.get('background'))  color_white = (255, 255, 255)  color_gray = (192, 192, 192)  font = pygame.font.Font(cfg.FONTPATH, cfg.WIDTH//20)  logo_img = pygame.image.load(cfg.OTHER_IMAGE_PATHS.get('logo'))  logo_img = pygame.transform.scale(logo_img, (446, 70))  logo_rect = logo_img.get_rect()  logo_rect.centerx, logo_rect.centery = cfg.WIDTH/2, cfg.HEIGHT//4  # 游戲加載提示  font_render = font.render('Loading game data, You will enter Level-%s' % level_next, True, color_white)  font_rect = font_render.get_rect()  font_rect.centerx, font_rect.centery = cfg.WIDTH/2, cfg.HEIGHT/2  # 游戲加載進度條  gamebar = pygame.image.load(cfg.OTHER_IMAGE_PATHS.get('gamebar')).convert_alpha()  gamebar_rect = gamebar.get_rect()  gamebar_rect.centerx, gamebar_rect.centery = cfg.WIDTH/2, cfg.HEIGHT/1.4  tank_cursor = pygame.image.load(cfg.PLAYER_TANK_IMAGE_PATHS.get('player1')[0]).convert_alpha().subsurface((0, 144), (48, 48))  tank_rect = tank_cursor.get_rect()  tank_rect.left = gamebar_rect.left  tank_rect.centery = gamebar_rect.centery  # 加載所需時間  load_time_left = gamebar_rect.right - tank_rect.right + 8  # 主循環(huán)  clock = pygame.time.Clock()  while True:    for event in pygame.event.get():      if event.type == pygame.QUIT:        pygame.quit()        sys.exit()    if load_time_left <= 0:      return    screen.blit(background_img, (0, 0))    screen.blit(logo_img, logo_rect)    screen.blit(font_render, font_rect)    screen.blit(gamebar, gamebar_rect)    screen.blit(tank_cursor, tank_rect)    pygame.draw.rect(screen, color_gray, (gamebar_rect.left+8, gamebar_rect.top+8, tank_rect.left-gamebar_rect.left-8, tank_rect.bottom-gamebar_rect.top-16))    tank_rect.left += 1    load_time_left -= 1    pygame.display.update()????clock.tick(60)



          完整代碼:

          https://pan.baidu.com/s/1BUh9M73AAGkZeDN0IEKdKA

          提取碼:09bl


          作者:李秋鍵

          CSDN博客專家,CSDN達人課作者。碩士在讀于中國礦業(yè)大學(xué),開發(fā)有taptap競賽獲獎等。




          瀏覽 50
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  成人自拍网站在线 | 大香蕉大香蕉视频网 | 亚洲欧美国产精品久久久久久久 | 精品国产人妻一区二区三区 | 国产精品美女久久 |