坦克大戰是一個比較經典的小遊戲,而 90 坦克大戰是一個比較經典的版本,咱們來看一下如何利用 Python 實現坦克大戰,先睹爲快。python
➢ 基本組成ios
➢ 操做規則app
玩家一dom
玩家二ide
➢ 場景實現代碼動畫
# 場景類 import pygame import random # 石頭牆 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)
➢ 坦克實現代碼ui
# 坦克類 import pygame import random from BattleCity.bullet import Bullet # 我方坦克類 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))
➢ 子彈實現代碼spa
# 子彈類 import pygame # 子彈類 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
➢ 食物實現代碼code
# 食物類 import pygame import random # 食物類, 用於提高坦克能力 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
➢ 大本營實現代碼遊戲
# 大本營類 import pygame # 大本營類 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
➢ 啓動類實現代碼
import sys import pygame from BattleCity import scene, tank, home, food def show_start_interface(screen, width, height): tfont = pygame.font.Font('font/simkai.ttf', width//5) cfont = pygame.font.Font('font/simkai.ttf', width//20) title = tfont.render(u'TANK', True, (255, 0, 0)) content1 = cfont.render(u'1 PLAYER(按1)', True, (0, 0, 255)) content2 = cfont.render(u'2 PLAYER(按2)', True, (0, 0, 255)) trect = title.get_rect() trect.midtop = (width/2, height/5) crect1 = content1.get_rect() crect1.midtop = (width/2, height/1.8) crect2 = content2.get_rect() crect2.midtop = (width/2, height/1.6) screen.blit(title, trect) screen.blit(content1, crect1) screen.blit(content2, crect2) pygame.display.update() while True: for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit() elif event.type == pygame.KEYDOWN: if event.key == pygame.K_1: return 1 if event.key == pygame.K_2: return 2 # 結束界面顯示 def show_end_interface(screen, width, height, is_win): bg_img = pygame.image.load("images/others/background.png") screen.blit(bg_img, (0, 0)) if is_win: font = pygame.font.Font('font/simkai.ttf', width//10) content = font.render(u'恭喜通關!', True, (255, 0, 0)) rect = content.get_rect() rect.midtop = (width/2, height/2) screen.blit(content, rect) else: fail_img = pygame.image.load("images/others/gameover.png") rect = fail_img.get_rect() rect.midtop = (width/2, height/2) screen.blit(fail_img, rect) pygame.display.update() while True: for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit() # 關卡切換 def show_switch_stage(screen, width, height, stage): bg_img = pygame.image.load("images/others/background.png") screen.blit(bg_img, (0, 0)) font = pygame.font.Font('font/simkai.ttf', width//10) content = font.render(u'第%d關' % stage, True, (0, 255, 0)) rect = content.get_rect() rect.midtop = (width/2, height/2) screen.blit(content, rect) pygame.display.update() delay_event = pygame.constants.USEREVENT pygame.time.set_timer(delay_event, 1000) while True: for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit() if event.type == delay_event: return def main(): # 初始化 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() # 主循環 while not is_gameover: # 關卡 stage += 1 if stage > num_stage: break show_switch_stage(screen, 630, 630, stage) # 該關卡坦克總數量 enemytanks_total = min(stage * 12, 60) # 場上存在的敵方坦克總數量 enemytanks_now = 0 # 場上能夠存在的敵方坦克總數量 enemytanks_now_max = min(max(stage * 2, 4), 8) # 精靈組 tanksGroup = pygame.sprite.Group() mytanksGroup = pygame.sprite.Group() enemytanksGroup = pygame.sprite.Group() bulletsGroup = pygame.sprite.Group() mybulletsGroup = pygame.sprite.Group() enemybulletsGroup = pygame.sprite.Group() myfoodsGroup = pygame.sprite.Group() # 自定義事件 # -生成敵方坦克事件 genEnemyEvent = pygame.constants.USEREVENT + 0 pygame.time.set_timer(genEnemyEvent, 100) # -敵方坦克靜止恢復事件 recoverEnemyEvent = pygame.constants.USEREVENT + 1 pygame.time.set_timer(recoverEnemyEvent, 8000) # -我方坦克無敵恢復事件 noprotectMytankEvent = pygame.constants.USEREVENT + 2 pygame.time.set_timer(noprotectMytankEvent, 8000) # 關卡地圖 map_stage = scene.Map(stage) # 我方坦克 tank_player1 = tank.myTank(1) tanksGroup.add(tank_player1) mytanksGroup.add(tank_player1) if num_player > 1: tank_player2 = tank.myTank(2) tanksGroup.add(tank_player2) mytanksGroup.add(tank_player2) is_switch_tank = True player1_moving = False player2_moving = False # 爲了輪胎的動畫效果 time = 0 # 敵方坦克 for i in range(0, 3): if enemytanks_total > 0: enemytank = tank.enemyTank(i) tanksGroup.add(enemytank) enemytanksGroup.add(enemytank) enemytanks_now += 1 enemytanks_total -= 1 # 大本營 myhome = home.Home() # 出場特效 appearance_img = pygame.image.load("images/others/appear.png").convert_alpha() appearances = [] appearances.append(appearance_img.subsurface((0, 0), (48, 48))) appearances.append(appearance_img.subsurface((48, 0), (48, 48))) appearances.append(appearance_img.subsurface((96, 0), (48, 48))) # 關卡主循環 while True: if is_gameover is True: break if enemytanks_total < 1 and enemytanks_now < 1: is_gameover = False break for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() if event.type == genEnemyEvent: if enemytanks_total > 0: if enemytanks_now < enemytanks_now_max: enemytank = tank.enemyTank() if not pygame.sprite.spritecollide(enemytank, tanksGroup, False, None): tanksGroup.add(enemytank) enemytanksGroup.add(enemytank) enemytanks_now += 1 enemytanks_total -= 1 if event.type == recoverEnemyEvent: for each in enemytanksGroup: each.can_move = True if event.type == noprotectMytankEvent: for each in mytanksGroup: mytanksGroup.protected = False # 檢查用戶鍵盤操做 key_pressed = pygame.key.get_pressed() # 玩家一 if key_pressed[pygame.K_w]: tanksGroup.remove(tank_player1) tank_player1.move_up(tanksGroup, map_stage.brickGroup, map_stage.ironGroup, myhome) tanksGroup.add(tank_player1) player1_moving = True elif key_pressed[pygame.K_s]: tanksGroup.remove(tank_player1) tank_player1.move_down(tanksGroup, map_stage.brickGroup, map_stage.ironGroup, myhome) tanksGroup.add(tank_player1) player1_moving = True elif key_pressed[pygame.K_a]: tanksGroup.remove(tank_player1) tank_player1.move_left(tanksGroup, map_stage.brickGroup, map_stage.ironGroup, myhome) tanksGroup.add(tank_player1) player1_moving = True elif key_pressed[pygame.K_d]: tanksGroup.remove(tank_player1) tank_player1.move_right(tanksGroup, map_stage.brickGroup, map_stage.ironGroup, myhome) tanksGroup.add(tank_player1) player1_moving = True elif key_pressed[pygame.K_j]: if not tank_player1.bullet.being: fire_sound.play() tank_player1.shoot() # 玩家二 if num_player > 1: if key_pressed[pygame.K_UP]: tanksGroup.remove(tank_player2) tank_player2.move_up(tanksGroup, map_stage.brickGroup, map_stage.ironGroup, myhome) tanksGroup.add(tank_player2) player2_moving = True elif key_pressed[pygame.K_DOWN]: tanksGroup.remove(tank_player2) tank_player2.move_down(tanksGroup, map_stage.brickGroup, map_stage.ironGroup, myhome) tanksGroup.add(tank_player2) player2_moving = True elif key_pressed[pygame.K_LEFT]: tanksGroup.remove(tank_player2) tank_player2.move_left(tanksGroup, map_stage.brickGroup, map_stage.ironGroup, myhome) tanksGroup.add(tank_player2) player2_moving = True elif key_pressed[pygame.K_RIGHT]: tanksGroup.remove(tank_player2) tank_player2.move_right(tanksGroup, map_stage.brickGroup, map_stage.ironGroup, myhome) tanksGroup.add(tank_player2) player2_moving = True elif key_pressed[pygame.K_0]: if not tank_player2.bullet.being: fire_sound.play() tank_player2.shoot() # 背景 screen.blit(bg_img, (0, 0)) # 石頭牆 for each in map_stage.brickGroup: screen.blit(each.brick, each.rect) # 鋼牆 for each in map_stage.ironGroup: screen.blit(each.iron, each.rect) # 冰 for each in map_stage.iceGroup: screen.blit(each.ice, each.rect) # 河流 for each in map_stage.riverGroup: screen.blit(each.river, each.rect) # 樹 for each in map_stage.treeGroup: screen.blit(each.tree, each.rect) time += 1 if time == 5: time = 0 is_switch_tank = not is_switch_tank # 我方坦克 if tank_player1 in mytanksGroup: if is_switch_tank and player1_moving: screen.blit(tank_player1.tank_0, (tank_player1.rect.left, tank_player1.rect.top)) player1_moving = False else: screen.blit(tank_player1.tank_1, (tank_player1.rect.left, tank_player1.rect.top)) if tank_player1.protected: screen.blit(tank_player1.protected_mask1, (tank_player1.rect.left, tank_player1.rect.top)) if num_player > 1: if tank_player2 in mytanksGroup: if is_switch_tank and player2_moving: screen.blit(tank_player2.tank_0, (tank_player2.rect.left, tank_player2.rect.top)) player1_moving = False else: screen.blit(tank_player2.tank_1, (tank_player2.rect.left, tank_player2.rect.top)) if tank_player2.protected: screen.blit(tank_player1.protected_mask1, (tank_player2.rect.left, tank_player2.rect.top)) # 敵方坦克 for each in enemytanksGroup: # 出生特效 if each.born: if each.times > 0: each.times -= 1 if each.times <= 10: screen.blit(appearances[2], (3+each.x*12*24, 3)) elif each.times <= 20: screen.blit(appearances[1], (3+each.x*12*24, 3)) elif each.times <= 30: screen.blit(appearances[0], (3+each.x*12*24, 3)) elif each.times <= 40: screen.blit(appearances[2], (3+each.x*12*24, 3)) elif each.times <= 50: screen.blit(appearances[1], (3+each.x*12*24, 3)) elif each.times <= 60: screen.blit(appearances[0], (3+each.x*12*24, 3)) elif each.times <= 70: screen.blit(appearances[2], (3+each.x*12*24, 3)) elif each.times <= 80: screen.blit(appearances[1], (3+each.x*12*24, 3)) elif each.times <= 90: screen.blit(appearances[0], (3+each.x*12*24, 3)) else: each.born = False else: if is_switch_tank: screen.blit(each.tank_0, (each.rect.left, each.rect.top)) else: screen.blit(each.tank_1, (each.rect.left, each.rect.top)) if each.can_move: tanksGroup.remove(each) each.move(tanksGroup, map_stage.brickGroup, map_stage.ironGroup, myhome) tanksGroup.add(each) # 我方子彈 for tank_player in mytanksGroup: if tank_player.bullet.being: tank_player.bullet.move() screen.blit(tank_player.bullet.bullet, tank_player.bullet.rect) # 子彈碰撞敵方子彈 for each in enemybulletsGroup: if each.being: if pygame.sprite.collide_rect(tank_player.bullet, each): tank_player.bullet.being = False each.being = False enemybulletsGroup.remove(each) break else: enemybulletsGroup.remove(each) # 子彈碰撞敵方坦克 for each in enemytanksGroup: if each.being: if pygame.sprite.collide_rect(tank_player.bullet, each): if each.is_red == True: myfood = food.Food() myfood.generate() myfoodsGroup.add(myfood) each.is_red = False each.blood -= 1 each.color -= 1 if each.blood < 0: bang_sound.play() each.being = False enemytanksGroup.remove(each) enemytanks_now -= 1 tanksGroup.remove(each) else: each.reload() tank_player.bullet.being = False break else: enemytanksGroup.remove(each) tanksGroup.remove(each) # 子彈碰撞石頭牆 if pygame.sprite.spritecollide(tank_player.bullet, map_stage.brickGroup, True, None): tank_player.bullet.being = False ''' # 等價方案(更科學點) for each in map_stage.brickGroup: if pygame.sprite.collide_rect(tank_player.bullet, each): tank_player.bullet.being = False each.being = False map_stage.brickGroup.remove(each) break ''' # 子彈碰鋼牆 if tank_player.bullet.stronger: if pygame.sprite.spritecollide(tank_player.bullet, map_stage.ironGroup, True, None): tank_player.bullet.being = False else: if pygame.sprite.spritecollide(tank_player.bullet, map_stage.ironGroup, False, None): tank_player.bullet.being = False ''' # 等價方案(更科學點) for each in map_stage.ironGroup: if pygame.sprite.collide_rect(tank_player.bullet, each): tank_player.bullet.being = False if tank_player.bullet.stronger: each.being = False map_stage.ironGroup.remove(each) break ''' # 子彈碰大本營 if pygame.sprite.collide_rect(tank_player.bullet, myhome): tank_player.bullet.being = False myhome.set_dead() is_gameover = True # 敵方子彈 for each in enemytanksGroup: if each.being: if each.can_move and not each.bullet.being: enemybulletsGroup.remove(each.bullet) each.shoot() enemybulletsGroup.add(each.bullet) if not each.born: if each.bullet.being: each.bullet.move() screen.blit(each.bullet.bullet, each.bullet.rect) # 子彈碰撞我方坦克 for tank_player in mytanksGroup: if pygame.sprite.collide_rect(each.bullet, tank_player): if not tank_player.protected: bang_sound.play() tank_player.life -= 1 if tank_player.life < 0: mytanksGroup.remove(tank_player) tanksGroup.remove(tank_player) if len(mytanksGroup) < 1: is_gameover = True else: tank_player.reset() each.bullet.being = False enemybulletsGroup.remove(each.bullet) break # 子彈碰撞石頭牆 if pygame.sprite.spritecollide(each.bullet, map_stage.brickGroup, True, None): each.bullet.being = False enemybulletsGroup.remove(each.bullet) ''' # 等價方案(更科學點) for one in map_stage.brickGroup: if pygame.sprite.collide_rect(each.bullet, one): each.bullet.being = False one.being = False enemybulletsGroup.remove(one) break ''' # 子彈碰鋼牆 if each.bullet.stronger: if pygame.sprite.spritecollide(each.bullet, map_stage.ironGroup, True, None): each.bullet.being = False else: if pygame.sprite.spritecollide(each.bullet, map_stage.ironGroup, False, None): each.bullet.being = False ''' # 等價方案(更科學點) for one in map_stage.ironGroup: if pygame.sprite.collide_rect(each.bullet, one): each.bullet.being = False if each.bullet.stronger: one.being = False map_stage.ironGroup.remove(one) break ''' # 子彈碰大本營 if pygame.sprite.collide_rect(each.bullet, myhome): each.bullet.being = False myhome.set_dead() is_gameover = True else: enemytanksGroup.remove(each) tanksGroup.remove(each) # 家 screen.blit(myhome.home, myhome.rect) # 食物 for myfood in myfoodsGroup: if myfood.being and myfood.time > 0: screen.blit(myfood.food, myfood.rect) myfood.time -= 1 for tank_player in mytanksGroup: if pygame.sprite.collide_rect(tank_player, myfood): # 消滅當前全部敵人 if myfood.kind == 0: for _ in enemytanksGroup: bang_sound.play() enemytanksGroup = pygame.sprite.Group() enemytanks_total -= enemytanks_now enemytanks_now = 0 # 敵人靜止 if myfood.kind == 1: for each in enemytanksGroup: each.can_move = False # 子彈加強 if myfood.kind == 2: add_sound.play() tank_player.bullet.stronger = True # 使得大本營的牆變爲鋼板 if myfood.kind == 3: map_stage.protect_home() # 坦克得到一段時間的保護罩 if myfood.kind == 4: add_sound.play() for tank_player in mytanksGroup: tank_player.protected = True # 坦克升級 if myfood.kind == 5: add_sound.play() tank_player.up_level() # 坦克生命+1 if myfood.kind == 6: add_sound.play() tank_player.life += 1 myfood.being = False myfoodsGroup.remove(myfood) break else: myfood.being = False myfoodsGroup.remove(myfood) pygame.display.flip() clock.tick(60) if not is_gameover: show_end_interface(screen, 630, 630, True) else: show_end_interface(screen, 630, 630, False) if __name__ == '__main__': main()
源碼及素材在公衆號 Python小二 後臺回覆 tank 獲取。