• 用 Python 写个坦克大战


    坦克大战是一款策略类的平面射击游戏,于 1985 年由 Namco 游戏公司发布,尽管时至今日已经有了很多衍生类的游戏,但这款游戏仍然受到了相当一部分人的欢迎,本文我们看一下如何使用 Python 来实现这款游戏,游戏实现主要用到的 Python 库为 pygame。

    简介

    很多人学习python,不知道从何学起。
    很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手。
    很多已经做案例的人,却不知道如何去学习更加高深的知识。
    那么针对这三类人,我给大家提供一个好的学习平台,免费领取视频教程,电子书籍,以及课程的源代码!
    QQ群:1097524789

    坦克大战的组成主要包括:场景、坦克、子弹、食物、大本营,其本质就是一个塔防类的游戏,游戏目标为:守住大本营并且消灭敌方坦克,通常支持单双人模式,下面我们来看一下具体实现。

    实现

    首先,我们来实现游戏场景,场景的组成主要包括:石头墙、钢墙、冰、河流、树、地图,我们暂时做两个关卡,代码实现如下:

    # 石头墙
    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 实现了坦克大战的基本功能,还有待完善,有兴趣的话,可以对游戏做进一步的完善和扩展。

  • 相关阅读:
    WPF/Sliverlight ScrollViewer与Panel(2)
    OpenGL学习笔记(7)多边形绘制
    OpenGL学习笔记(10)抗锯齿
    OpenGL学习笔记(9)颜色混合
    GLUT函数说明(转)
    OpenGL学习笔记(8)显示列表
    C#操作IIS的代码
    完整解决Flash载入中文FLASH乱码问题
    用C#的IIS上配置用户账号
    ASP.NET定时调用WebService 运行后台代码
  • 原文地址:https://www.cnblogs.com/shann001/p/13202436.html
Copyright © 2020-2023  润新知