用 Python 寫個坦克大戰

文 | 野客

來源:Python 技術「ID: pythonall」

坦克大戰是一款策略類的平面射擊遊戲,於 1985 年由 Namco 遊戲公司發佈,儘管時至今日已經有了很多衍生類的遊戲,但這款遊戲仍然受到了相當一部分人的歡迎,本文我們看一下如何使用 Python 來實現這款遊戲,遊戲實現主要用到的 Python 庫爲 pygame。

簡介

坦克大戰的組成主要包括:場景、坦克、子彈、食物、大本營,其本質就是一個塔防類的遊戲,遊戲目標爲:守住大本營並且消滅敵方坦克,通常支持單雙人模式,下面我們來看一下具體實現。

實現

首先,我們來實現遊戲場景,場景的組成主要包括:石頭牆、鋼牆、冰、河流、樹、地圖,我們暫時做兩個關卡,代碼實現如下:

# 石頭牆
class Brick(pygame.sprite.Sprite):
 def __init__(self):
  pygame.sprite.Sprite.__init__(self)
  self.brick = pygame.image.load('images/scene/brick.png')
  self.rect = self.brick.get_rect()
  self.being = False

# 鋼牆
class Iron(pygame.sprite.Sprite):
 def __init__(self):
  pygame.sprite.Sprite.__init__(self)
  self.iron = pygame.image.load('images/scene/iron.png')
  self.rect = self.iron.get_rect()
  self.being = False

# 冰
class Ice(pygame.sprite.Sprite):
 def __init__(self):
  pygame.sprite.Sprite.__init__(self)
  self.ice = pygame.image.load('images/scene/ice.png')
  self.rect = self.ice.get_rect()
  self.being = False

# 河流
class River(pygame.sprite.Sprite):
 def __init__(self, kind=None):
  pygame.sprite.Sprite.__init__(self)
  if kind is None:
   self.kind = random.randint(0, 1)
  self.rivers = ['images/scene/river1.png', 'images/scene/river2.png']
  self.river = pygame.image.load(self.rivers[self.kind])
  self.rect = self.river.get_rect()
  self.being = False

# 樹
class Tree(pygame.sprite.Sprite):
 def __init__(self):
  pygame.sprite.Sprite.__init__(self)
  self.tree = pygame.image.load('images/scene/tree.png')
  self.rect = self.tree.get_rect()
  self.being = False

# 地圖
class Map():
 def __init__(self, stage):
  self.brickGroup = pygame.sprite.Group()
  self.ironGroup  = pygame.sprite.Group()
  self.iceGroup = pygame.sprite.Group()
  self.riverGroup = pygame.sprite.Group()
  self.treeGroup = pygame.sprite.Group()
  if stage == 1:
   self.stage1()
  elif stage == 2:
   self.stage2()
 # 關卡一
 def stage1(self):
  for x in [2, 3, 6, 7, 18, 19, 22, 23]:
   for y in [2, 3, 4, 5, 6, 7, 8, 9, 10, 17, 18, 19, 20, 21, 22, 23]:
    self.brick = Brick()
    self.brick.rect.left, self.brick.rect.top = 3 + x * 24, 3 + y * 24
    self.brick.being = True
    self.brickGroup.add(self.brick)
  for x in [10, 11, 14, 15]:
   for y in [2, 3, 4, 5, 6, 7, 8, 11, 12, 15, 16, 17, 18, 19, 20]:
    self.brick = Brick()
    self.brick.rect.left, self.brick.rect.top = 3 + x * 24, 3 + y * 24
    self.brick.being = True
    self.brickGroup.add(self.brick)
  for x in [4, 5, 6, 7, 18, 19, 20, 21]:
   for y in [13, 14]:
    self.brick = Brick()
    self.brick.rect.left, self.brick.rect.top = 3 + x * 24, 3 + y * 24
    self.brick.being = True
    self.brickGroup.add(self.brick)
  for x in [12, 13]:
   for y in [16, 17]:
    self.brick = Brick()
    self.brick.rect.left, self.brick.rect.top = 3 + x * 24, 3 + y * 24
    self.brick.being = True
    self.brickGroup.add(self.brick)
  for x, y in [(11, 23), (12, 23), (13, 23), (14, 23), (11, 24), (14, 24), (11, 25), (14, 25)]:
   self.brick = Brick()
   self.brick.rect.left, self.brick.rect.top = 3 + x * 24, 3 + y * 24
   self.brick.being = True
   self.brickGroup.add(self.brick)
  for x, y in [(0, 14), (1, 14), (12, 6), (13, 6), (12, 7), (13, 7), (24, 14), (25, 14)]:
   self.iron = Iron()
   self.iron.rect.left, self.iron.rect.top = 3 + x * 24, 3 + y * 24
   self.iron.being = True
   self.ironGroup.add(self.iron)
 # 關卡二
 def stage2(self):
  for x in [2, 3, 6, 7, 18, 19, 22, 23]:
   for y in [2, 3, 4, 5, 6, 7, 8, 9, 10, 17, 18, 19, 20, 21, 22, 23]:
    self.brick = Brick()
    self.brick.rect.left, self.brick.rect.top = 3 + x * 24, 3 + y * 24
    self.brick.being = True
    self.brickGroup.add(self.brick)
  for x in [10, 11, 14, 15]:
   for y in [2, 3, 4, 5, 6, 7, 8, 11, 12, 15, 16, 17, 18, 19, 20]:
    self.brick = Brick()
    self.brick.rect.left, self.brick.rect.top = 3 + x * 24, 3 + y * 24
    self.brick.being = True
    self.brickGroup.add(self.brick)
  for x in [4, 5, 6, 7, 18, 19, 20, 21]:
   for y in [13, 14]:
    self.brick = Brick()
    self.brick.rect.left, self.brick.rect.top = 3 + x * 24, 3 + y * 24
    self.brick.being = True
    self.brickGroup.add(self.brick)
  for x in [12, 13]:
   for y in [16, 17]:
    self.brick = Brick()
    self.brick.rect.left, self.brick.rect.top = 3 + x * 24, 3 + y * 24
    self.brick.being = True
    self.brickGroup.add(self.brick)
  for x, y in [(11, 23), (12, 23), (13, 23), (14, 23), (11, 24), (14, 24), (11, 25), (14, 25)]:
   self.brick = Brick()
   self.brick.rect.left, self.brick.rect.top = 3 + x * 24, 3 + y * 24
   self.brick.being = True
   self.brickGroup.add(self.brick)
  for x, y in [(0, 14), (1, 14), (12, 6), (13, 6), (12, 7), (13, 7), (24, 14), (25, 14)]:
   self.iron = Iron()
   self.iron.rect.left, self.iron.rect.top = 3 + x * 24, 3 + y * 24
   self.iron.being = True
   self.ironGroup.add(self.iron)
 def protect_home(self):
  for x, y in [(11, 23), (12, 23), (13, 23), (14, 23), (11, 24), (14, 24), (11, 25), (14, 25)]:
   self.iron = Iron()
   self.iron.rect.left, self.iron.rect.top = 3 + x * 24, 3 + y * 24
   self.iron.being = True
   self.ironGroup.add(self.iron)

我們接着看大本營的實現,大本營的實現相對比較簡單,其本質就是一個標識物,代碼實現如下:

class Home(pygame.sprite.Sprite):
 def __init__(self):
  pygame.sprite.Sprite.__init__(self)
  self.homes = ['images/home/home1.png', 'images/home/home2.png', 'images/home/home_destroyed.png']
  self.home = pygame.image.load(self.homes[0])
  self.rect = self.home.get_rect()
  self.rect.left, self.rect.top = (3 + 12 * 24, 3 + 24 * 24)
  self.alive = True
 # 大本營置爲摧毀狀態
 def set_dead(self):
  self.home = pygame.image.load(self.homes[-1])
  self.alive = False

再接着看食物的實現,食物主要用來提升坦克能力,如:坦克升級、增加生命等,代碼實現如下:

# 食物類
class Food(pygame.sprite.Sprite):
 def __init__(self):
  pygame.sprite.Sprite.__init__(self)
  # 消滅當前所有敵人
  self.food_boom = 'images/food/food_boom.png'
  # 當前所有敵人靜止一段時間
  self.food_clock = 'images/food/food_clock.png'
  # 使得坦克子彈可碎鋼板
  self.food_gun = 'images/food/food_gun.png'
  # 使得大本營的牆變爲鋼板
  self.food_iron = 'images/food/food_gun.png'
  # 坦克獲得一段時間的保護罩
  self.food_protect = 'images/food/food_protect.png'
  # 坦克升級
  self.food_star = 'images/food/food_star.png'
  # 坦克生命 + 1
  self.food_tank = 'images/food/food_tank.png'
  # 所有食物
  self.foods = [self.food_boom, self.food_clock, self.food_gun, self.food_iron, self.food_protect, self.food_star, self.food_tank]
  self.kind = None
  self.food = None
  self.rect = None
  # 是否存在
  self.being = False
  # 存在時間
  self.time = 1000
 # 生成食物
 def generate(self):
  self.kind = random.randint(0, 6)
  self.food = pygame.image.load(self.foods[self.kind]).convert_alpha()
  self.rect = self.food.get_rect()
  self.rect.left, self.rect.top = random.randint(100, 500), random.randint(100, 500)
  self.being = True

再接着看坦克的實現,坦克包括我方坦克和敵方坦克,我方坦克由玩家自己控制移動、射擊等操作,敵方坦克實現自動移動、射擊等操作,代碼實現如下:

# 我方坦克類
class myTank(pygame.sprite.Sprite):
 def __init__(self, player):
  pygame.sprite.Sprite.__init__(self)
  # 玩家編號(1/2)
  self.player = player
  # 不同玩家用不同的坦克(不同等級對應不同的圖)
  if player == 1:
   self.tanks = ['images/myTank/tank_T1_0.png', 'images/myTank/tank_T1_1.png', 'images/myTank/tank_T1_2.png']
  elif player == 2:
   self.tanks = ['images/myTank/tank_T2_0.png', 'images/myTank/tank_T2_1.png', 'images/myTank/tank_T2_2.png']
  else:
   raise ValueError('myTank class -> player value error.')
  # 坦克等級(初始0)
  self.level = 0
  # 載入(兩個tank是爲了輪子特效)
  self.tank = pygame.image.load(self.tanks[self.level]).convert_alpha()
  self.tank_0 = self.tank.subsurface((0, 0), (48, 48))
  self.tank_1 = self.tank.subsurface((48, 0), (48, 48))
  self.rect = self.tank_0.get_rect()
  # 保護罩
  self.protected_mask = pygame.image.load('images/others/protect.png').convert_alpha()
  self.protected_mask1 = self.protected_mask.subsurface((0, 0), (48, 48))
  self.protected_mask2 = self.protected_mask.subsurface((48, 0), (48, 48))
  # 坦克方向
  self.direction_x, self.direction_y = 0, -1
  # 不同玩家的出生位置不同
  if player == 1:
   self.rect.left, self.rect.top = 3 + 24 * 8, 3 + 24 * 24
  elif player == 2:
   self.rect.left, self.rect.top = 3 + 24 * 16, 3 + 24 * 24
  else:
   raise ValueError('myTank class -> player value error.')
  # 坦克速度
  self.speed = 3
  # 是否存活
  self.being = True
  # 有幾條命
  self.life = 3
  # 是否處於保護狀態
  self.protected = False
  # 子彈
  self.bullet = Bullet()
 # 射擊
 def shoot(self):
  self.bullet.being = True
  self.bullet.turn(self.direction_x, self.direction_y)
  if self.direction_x == 0 and self.direction_y == -1:
   self.bullet.rect.left = self.rect.left + 20
   self.bullet.rect.bottom = self.rect.top - 1
  elif self.direction_x == 0 and self.direction_y == 1:
   self.bullet.rect.left = self.rect.left + 20
   self.bullet.rect.top = self.rect.bottom + 1
  elif self.direction_x == -1 and self.direction_y == 0:
   self.bullet.rect.right = self.rect.left - 1
   self.bullet.rect.top = self.rect.top + 20
  elif self.direction_x == 1 and self.direction_y == 0:
   self.bullet.rect.left = self.rect.right + 1
   self.bullet.rect.top = self.rect.top + 20
  else:
   raise ValueError('myTank class -> direction value error.')
  if self.level == 0:
   self.bullet.speed = 8
   self.bullet.stronger = False
  elif self.level == 1:
   self.bullet.speed = 12
   self.bullet.stronger = False
  elif self.level == 2:
   self.bullet.speed = 12
   self.bullet.stronger = True
  elif self.level == 3:
   self.bullet.speed = 16
   self.bullet.stronger = True
  else:
   raise ValueError('myTank class -> level value error.')
 # 等級提升
 def up_level(self):
  if self.level < 3:
   self.level += 1
  try:
   self.tank = pygame.image.load(self.tanks[self.level]).convert_alpha()
  except:
   self.tank = pygame.image.load(self.tanks[-1]).convert_alpha()
 # 等級降低
 def down_level(self):
  if self.level > 0:
   self.level -= 1
  self.tank = pygame.image.load(self.tanks[self.level]).convert_alpha()
 # 向上
 def move_up(self, tankGroup, brickGroup, ironGroup, myhome):
  self.direction_x, self.direction_y = 0, -1
  # 先移動後判斷
  self.rect = self.rect.move(self.speed*self.direction_x, self.speed*self.direction_y)
  self.tank_0 = self.tank.subsurface((0, 0), (48, 48))
  self.tank_1 = self.tank.subsurface((48, 0), (48, 48))
  # 是否可以移動
  is_move = True
  # 地圖頂端
  if self.rect.top < 3:
   self.rect = self.rect.move(self.speed*-self.direction_x, self.speed*-self.direction_y)
   is_move = False
  # 撞石頭/鋼牆
  if pygame.sprite.spritecollide(self, brickGroup, False, None) or \
   pygame.sprite.spritecollide(self, ironGroup, False, None):
   self.rect = self.rect.move(self.speed*-self.direction_x, self.speed*-self.direction_y)
   is_move = False
  # 撞其他坦克
  if pygame.sprite.spritecollide(self, tankGroup, False, None):
   self.rect = self.rect.move(self.speed*-self.direction_x, self.speed*-self.direction_y)
   is_move = False
  # 大本營
  if pygame.sprite.collide_rect(self, myhome):
   self.rect = self.rect.move(self.speed*-self.direction_x, self.speed*-self.direction_y)
   is_move = False
  return is_move
 # 向下
 def move_down(self, tankGroup, brickGroup, ironGroup, myhome):
  self.direction_x, self.direction_y = 0, 1
  # 先移動後判斷
  self.rect = self.rect.move(self.speed*self.direction_x, self.speed*self.direction_y)
  self.tank_0 = self.tank.subsurface((0, 48), (48, 48))
  self.tank_1 = self.tank.subsurface((48, 48), (48, 48))
  # 是否可以移動
  is_move = True
  # 地圖底端
  if self.rect.bottom > 630 - 3:
   self.rect = self.rect.move(self.speed*-self.direction_x, self.speed*-self.direction_y)
   is_move = False
  # 撞石頭/鋼牆
  if pygame.sprite.spritecollide(self, brickGroup, False, None) or \
   pygame.sprite.spritecollide(self, ironGroup, False, None):
   self.rect = self.rect.move(self.speed*-self.direction_x, self.speed*-self.direction_y)
   is_move = False
  # 撞其他坦克
  if pygame.sprite.spritecollide(self, tankGroup, False, None):
   self.rect = self.rect.move(self.speed*-self.direction_x, self.speed*-self.direction_y)
   is_move = False
  # 大本營
  if pygame.sprite.collide_rect(self, myhome):
   self.rect = self.rect.move(self.speed*-self.direction_x, self.speed*-self.direction_y)
   is_move = False
  return is_move
 # 向左
 def move_left(self, tankGroup, brickGroup, ironGroup, myhome):
  self.direction_x, self.direction_y = -1, 0
  # 先移動後判斷
  self.rect = self.rect.move(self.speed*self.direction_x, self.speed*self.direction_y)
  self.tank_0 = self.tank.subsurface((0, 96), (48, 48))
  self.tank_1 = self.tank.subsurface((48, 96), (48, 48))
  # 是否可以移動
  is_move = True
  # 地圖左端
  if self.rect.left < 3:
   self.rect = self.rect.move(self.speed*-self.direction_x, self.speed*-self.direction_y)
   is_move = False
  # 撞石頭/鋼牆
  if pygame.sprite.spritecollide(self, brickGroup, False, None) or \
   pygame.sprite.spritecollide(self, ironGroup, False, None):
   self.rect = self.rect.move(self.speed*-self.direction_x, self.speed*-self.direction_y)
   is_move = False
  # 撞其他坦克
  if pygame.sprite.spritecollide(self, tankGroup, False, None):
   self.rect = self.rect.move(self.speed*-self.direction_x, self.speed*-self.direction_y)
   is_move = False  
  # 大本營
  if pygame.sprite.collide_rect(self, myhome):
   self.rect = self.rect.move(self.speed*-self.direction_x, self.speed*-self.direction_y)
   is_move = False
  return is_move
 # 向右
 def move_right(self, tankGroup, brickGroup, ironGroup, myhome):
  self.direction_x, self.direction_y = 1, 0
  # 先移動後判斷
  self.rect = self.rect.move(self.speed*self.direction_x, self.speed*self.direction_y)
  self.tank_0 = self.tank.subsurface((0, 144), (48, 48))
  self.tank_1 = self.tank.subsurface((48, 144), (48, 48))
  # 是否可以移動
  is_move = True
  # 地圖右端
  if self.rect.right > 630 - 3:
   self.rect = self.rect.move(self.speed*-self.direction_x, self.speed*-self.direction_y)
   is_move = False
  # 撞石頭/鋼牆
  if pygame.sprite.spritecollide(self, brickGroup, False, None) or \
   pygame.sprite.spritecollide(self, ironGroup, False, None):
   self.rect = self.rect.move(self.speed*-self.direction_x, self.speed*-self.direction_y)
   is_move = False
  # 撞其他坦克
  if pygame.sprite.spritecollide(self, tankGroup, False, None):
   self.rect = self.rect.move(self.speed*-self.direction_x, self.speed*-self.direction_y)
   is_move = False
  # 大本營
  if pygame.sprite.collide_rect(self, myhome):
   self.rect = self.rect.move(self.speed*-self.direction_x, self.speed*-self.direction_y)
   is_move = False
  return is_move
 # 死後重置
 def reset(self):
  self.level = 0
  self.protected = False
  self.tank = pygame.image.load(self.tanks[self.level]).convert_alpha()
  self.tank_0 = self.tank.subsurface((0, 0), (48, 48))
  self.tank_1 = self.tank.subsurface((48, 0), (48, 48))
  self.rect = self.tank_0.get_rect()
  self.direction_x, self.direction_y = 0, -1
  if self.player == 1:
   self.rect.left, self.rect.top = 3 + 24 * 8, 3 + 24 * 24
  elif self.player == 2:
   self.rect.left, self.rect.top = 3 + 24 * 16, 3 + 24 * 24
  else:
   raise ValueError('myTank class -> player value error.')
  self.speed = 3

# 敵方坦克類
class enemyTank(pygame.sprite.Sprite):
 def __init__(self, x=None, kind=None, is_red=None):
  pygame.sprite.Sprite.__init__(self)
  # 用於給剛生成的坦克播放出生特效
  self.born = True
  self.times = 90
  # 坦克的種類編號
  if kind is None:
   self.kind = random.randint(0, 3)
  else:
   self.kind = kind
  # 所有坦克
  self.tanks1 = ['images/enemyTank/enemy_1_0.png', 'images/enemyTank/enemy_1_1.png', 'images/enemyTank/enemy_1_2.png', 'images/enemyTank/enemy_1_3.png']
  self.tanks2 = ['images/enemyTank/enemy_2_0.png', 'images/enemyTank/enemy_2_1.png', 'images/enemyTank/enemy_2_2.png', 'images/enemyTank/enemy_2_3.png']
  self.tanks3 = ['images/enemyTank/enemy_3_0.png', 'images/enemyTank/enemy_3_1.png', 'images/enemyTank/enemy_3_2.png', 'images/enemyTank/enemy_3_3.png']
  self.tanks4 = ['images/enemyTank/enemy_4_0.png', 'images/enemyTank/enemy_4_1.png', 'images/enemyTank/enemy_4_2.png', 'images/enemyTank/enemy_4_3.png']
  self.tanks = [self.tanks1, self.tanks2, self.tanks3, self.tanks4]
  # 是否攜帶食物(紅色的坦克攜帶食物)
  if is_red is None:
   self.is_red = random.choice((True, False, False, False, False))
  else:
   self.is_red = is_red
  # 同一種類的坦克具有不同的顏色, 紅色的坦克比同類坦克多一點血量
  if self.is_red:
   self.color = 3
  else:
   self.color = random.randint(0, 2)
  # 血量
  self.blood = self.color
  # 載入(兩個tank是爲了輪子特效)
  self.tank = pygame.image.load(self.tanks[self.kind][self.color]).convert_alpha()
  self.tank_0 = self.tank.subsurface((0, 48), (48, 48))
  self.tank_1 = self.tank.subsurface((48, 48), (48, 48))
  self.rect = self.tank_0.get_rect()
  # 坦克位置
  if x is None:
   self.x = random.randint(0, 2)
  else:
   self.x = x
  self.rect.left, self.rect.top = 3 + self.x * 12 * 24, 3
  # 坦克是否可以行動
  self.can_move = True
  # 坦克速度
  self.speed = max(3 - self.kind, 1)
  # 方向
  self.direction_x, self.direction_y = 0, 1
  # 是否存活
  self.being = True
  # 子彈
  self.bullet = Bullet()
 # 射擊
 def shoot(self):
  self.bullet.being = True
  self.bullet.turn(self.direction_x, self.direction_y)
  if self.direction_x == 0 and self.direction_y == -1:
   self.bullet.rect.left = self.rect.left + 20
   self.bullet.rect.bottom = self.rect.top - 1
  elif self.direction_x == 0 and self.direction_y == 1:
   self.bullet.rect.left = self.rect.left + 20
   self.bullet.rect.top = self.rect.bottom + 1
  elif self.direction_x == -1 and self.direction_y == 0:
   self.bullet.rect.right = self.rect.left - 1
   self.bullet.rect.top = self.rect.top + 20
  elif self.direction_x == 1 and self.direction_y == 0:
   self.bullet.rect.left = self.rect.right + 1
   self.bullet.rect.top = self.rect.top + 20
  else:
   raise ValueError('enemyTank class -> direction value error.')
 # 隨機移動
 def move(self, tankGroup, brickGroup, ironGroup, myhome):
  self.rect = self.rect.move(self.speed*self.direction_x, self.speed*self.direction_y)
  is_move = True
  if self.direction_x == 0 and self.direction_y == -1:
   self.tank_0 = self.tank.subsurface((0, 0), (48, 48))
   self.tank_1 = self.tank.subsurface((48, 0), (48, 48))
   if self.rect.top < 3:
    self.rect = self.rect.move(self.speed*-self.direction_x, self.speed*-self.direction_y)
    self.direction_x, self.direction_y = random.choice(([0, 1], [0, -1], [1, 0], [-1, 0]))
    is_move = False
  elif self.direction_x == 0 and self.direction_y == 1:
   self.tank_0 = self.tank.subsurface((0, 48), (48, 48))
   self.tank_1 = self.tank.subsurface((48, 48), (48, 48))
   if self.rect.bottom > 630 - 3:
    self.rect = self.rect.move(self.speed*-self.direction_x, self.speed*-self.direction_y)
    self.direction_x, self.direction_y = random.choice(([0, 1], [0, -1], [1, 0], [-1, 0]))
    is_move = False
  elif self.direction_x == -1 and self.direction_y == 0:
   self.tank_0 = self.tank.subsurface((0, 96), (48, 48))
   self.tank_1 = self.tank.subsurface((48, 96), (48, 48))
   if self.rect.left < 3:
    self.rect = self.rect.move(self.speed*-self.direction_x, self.speed*-self.direction_y)
    self.direction_x, self.direction_y = random.choice(([0, 1], [0, -1], [1, 0], [-1, 0]))
    is_move = False
  elif self.direction_x == 1 and self.direction_y == 0:
   self.tank_0 = self.tank.subsurface((0, 144), (48, 48))
   self.tank_1 = self.tank.subsurface((48, 144), (48, 48))
   if self.rect.right > 630 - 3:
    self.rect = self.rect.move(self.speed*-self.direction_x, self.speed*-self.direction_y)
    self.direction_x, self.direction_y = random.choice(([0, 1], [0, -1], [1, 0], [-1, 0]))
    is_move = False
  else:
   raise ValueError('enemyTank class -> direction value error.')
  if pygame.sprite.spritecollide(self, brickGroup, False, None) \
   or pygame.sprite.spritecollide(self, ironGroup, False, None) \
   or pygame.sprite.spritecollide(self, tankGroup, False, None):
   self.rect = self.rect.move(self.speed*-self.direction_x, self.speed*-self.direction_y)
   self.direction_x, self.direction_y = random.choice(([0, 1], [0, -1], [1, 0], [-1, 0]))
   is_move = False
  if pygame.sprite.collide_rect(self, myhome):
   self.rect = self.rect.move(self.speed*-self.direction_x, self.speed*-self.direction_y)
   self.direction_x, self.direction_y = random.choice(([0, 1], [0, -1], [1, 0], [-1, 0]))
   is_move = False
  return is_move
 # 重新載入坦克
 def reload(self):
  self.tank = pygame.image.load(self.tanks[self.kind][self.color]).convert_alpha()
  self.tank_0 = self.tank.subsurface((0, 48), (48, 48))
  self.tank_1 = self.tank.subsurface((48, 48), (48, 48))

再接着看子彈的實現,子彈的主要屬性包括:方向、速度、是否存活、是否爲加強版等,代碼實現如下:

# 子彈類
class Bullet(pygame.sprite.Sprite):
 def __init__(self):
  pygame.sprite.Sprite.__init__(self)
  # 子彈四個方向(上下左右)
  self.bullets = ['images/bullet/bullet_up.png', 'images/bullet/bullet_down.png', 'images/bullet/bullet_left.png', 'images/bullet/bullet_right.png']
  # 子彈方向(默認向上)
  self.direction_x, self.direction_y = 0, -1
  self.bullet = pygame.image.load(self.bullets[0])
  self.rect = self.bullet.get_rect()
  # 在坦克類中再賦實際值
  self.rect.left, self.rect.right = 0, 0
  # 速度
  self.speed = 6
  # 是否存活
  self.being = False
  # 是否爲加強版子彈(可碎鋼板)
  self.stronger = False
 # 改變子彈方向
 def turn(self, direction_x, direction_y):
  self.direction_x, self.direction_y = direction_x, direction_y
  if self.direction_x == 0 and self.direction_y == -1:
   self.bullet = pygame.image.load(self.bullets[0])
  elif self.direction_x == 0 and self.direction_y == 1:
   self.bullet = pygame.image.load(self.bullets[1])
  elif self.direction_x == -1 and self.direction_y == 0:
   self.bullet = pygame.image.load(self.bullets[2])
  elif self.direction_x == 1 and self.direction_y == 0:
   self.bullet = pygame.image.load(self.bullets[3])
  else:
   raise ValueError('Bullet class -> direction value error.')
 # 移動
 def move(self):
  self.rect = self.rect.move(self.speed*self.direction_x, self.speed*self.direction_y)
  # 到地圖邊緣後消失
  if (self.rect.top < 3) or (self.rect.bottom > 630 - 3) or (self.rect.left < 3) or (self.rect.right > 630 - 3):
   self.being = False

最後,我們看一下程序的主要初始化代碼,如下所示:

# 初始化
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((630, 630))
pygame.display.set_caption("TANK")
# 加載圖片
bg_img = pygame.image.load("images/others/background.png")
# 加載音效
add_sound = pygame.mixer.Sound("audios/add.wav")
add_sound.set_volume(1)
bang_sound = pygame.mixer.Sound("audios/bang.wav")
bang_sound.set_volume(1)
blast_sound = pygame.mixer.Sound("audios/blast.wav")
blast_sound.set_volume(1)
fire_sound = pygame.mixer.Sound("audios/fire.wav")
fire_sound.set_volume(1)
Gunfire_sound = pygame.mixer.Sound("audios/Gunfire.wav")
Gunfire_sound.set_volume(1)
hit_sound = pygame.mixer.Sound("audios/hit.wav")
hit_sound.set_volume(1)
start_sound = pygame.mixer.Sound("audios/start.wav")
start_sound.set_volume(1)
# 開始界面
num_player = show_start_interface(screen, 630, 630)
# 播放遊戲開始的音樂
start_sound.play()
# 關卡
stage = 0
num_stage = 2
# 遊戲是否結束
is_gameover = False
# 時鐘
clock = pygame.time.Clock()

看一下實現效果:

再說一下玩家一、二的操作鍵,玩家一、二移動鍵分別爲:WASD、←→↑↓,玩家一、二射擊鍵分別爲:J、0。

總結

本文我們使用 Python 實現了坦克大戰的基本功能,還有待完善,有興趣的話,可以對遊戲做進一步的完善和擴展。

PS公號內回覆「Python」即可進入Python 新手學習交流羣,一起100天計劃!

老規矩,兄弟們還記得麼,右下角的 “在看” 點一下如果感覺文章內容不錯的話,記得分享朋友圈讓更多的人知道!

代碼獲取方式

識別文末二維碼,回覆:200628

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章