标题 python制作坦克大战完整版、素材后期更新
"""
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Time : 2021/3/15 2:27
# @Author : allen
"""
import pygame, time, random
_display = pygame.display
class MianGame:
# 创建游戏主窗口
window = None
display_width = 900
display_height = 600
color_back = pygame.Color(0, 0, 0)
color_red = pygame.Color(255, 0, 0)
tank_num = 5
Vision = "坦克大战v1.04"
Tank_p1 = None
eTank_list = []
eTank_count = 4
# 创建一个子弹列表
bullet_list = []
# 创建敌方子弹列表
enemy_bullet_list = []
# 创建爆炸效果列表
Explode_list = []
# 创建墙壁列表
wall_list = []
def __init__(self):
pass
def startGame(self):
# 创建窗口加载窗口(借鉴官方文档) https://www.pygame.org/docs/ref/display.html#pygame.display.init
_display.init()
# 设置游戏窗口的宽和高
MianGame.window = _display.set_mode([self.display_width, self.display_height])
# MianGame.CreationMyTank()
# 调用创建我方对象坦克的方法
self.CreationMyTank()
# 调用创建敌方对象坦克的方法
self.creation_etank()
# 调用创建墙壁对象的方法
self.creatwalls()
# 展示当前版本型号
_display.set_caption(self.Vision)
# 让窗口实现持续刷新操作
while True:
MianGame.window.fill(self.color_back)
self.get_Event()
MianGame.window.blit(self.getTextSurface("剩余敌方坦克数量 %d 辆" % len(self.eTank_list)), (4, 4))
self.blitWalls()
# 循环展示我方坦克
if MianGame.Tank_p1 and MianGame.Tank_p1.Live:
MianGame.Tank_p1.dispalayTank()
else:
del MianGame.Tank_p1
MianGame.Tank_p1 = None
# 循环展示敌方坦克
self.displayetank()
if MianGame.Tank_p1 and not MianGame.Tank_p1.stop:
# 调用我方坦克的移动方法
MianGame.Tank_p1.move()
# 调用我方坦克与敌方坦克的碰撞方法
MianGame.Tank_p1.hitetank()
# 调用我方坦克与墙壁的碰撞方法
MianGame.Tank_p1.hitWalls()
self.blitBullet()
self.enemy_blit_Bullet()
self.disExplode_list()
time.sleep(0.02)
_display.update()
# 创建我方坦克,新建对象
def CreationMyTank(self):
MianGame.Tank_p1 = MyTank(450, 300, speed=5)
music = Music("picture/start.wav")
music.playMusic()
def getTextSurface(self, text):
pygame.font.init()
font = pygame.font.SysFont("kaiti", 18)
textSurface = font.render(text, True, self.color_red)
return textSurface
def endGame(self):
print("感谢体验! - _ - ")
exit()
def get_Event(self):
# 获取队列事件列表
Event_list = pygame.event.get()
for Event in Event_list:
if Event.type == pygame.QUIT:
self.endGame()
if Event.type == pygame.KEYDOWN:
# 判断我方坦克的状态,如果我方坦克不存在,则通过ESC按键获取重生
if Event.key == pygame.K_ESCAPE and not MianGame.Tank_p1:
self.CreationMyTank()
# 判断我方坦克的状态,当我方的坦克存在,状态live,则通过上下左右键控制方向
# 通过空格键发射子弹
if MianGame.Tank_p1 and MianGame.Tank_p1.Live:
# 判断按下的是哪一个按件
if Event.key == pygame.K_LEFT:
print("坦克向左掉头, 移动")
MianGame.Tank_p1.direction = "L"
MianGame.Tank_p1.stop = False
# MianGame.Tank_p1.move()
if Event.key == pygame.K_RIGHT:
print("坦克向右掉头, 移动")
MianGame.Tank_p1.direction = "R"
MianGame.Tank_p1.stop = False
# MianGame.Tank_p1.move()
if Event.key == pygame.K_DOWN:
print("坦克向下掉头, 移动")
MianGame.Tank_p1.direction = "D"
MianGame.Tank_p1.stop = False
# MianGame.Tank_p1.move()
if Event.key == pygame.K_UP:
print("坦克向上掉头, 移动")
MianGame.Tank_p1.direction = "U"
MianGame.Tank_p1.stop = False
# MianGame.Tank_p1.move()
if Event.key == pygame.K_SPACE:
if len(MianGame.bullet_list) < 3:
m = Bullet(MianGame.Tank_p1)
MianGame.bullet_list.append(m)
music = Music("picture/fire.wav")
music.playMusic()
print("当前子弹的数量为%d" % len(MianGame.bullet_list))
else:
print("子弹数量不足")
# 判断如果松开按键
if Event.type == pygame.KEYUP:
# MianGame.Tank_p1.stop = True
if Event.key == pygame.K_UP or pygame.K_LEFT or pygame.K_RIGHT or pygame.K_DOWN:
if MianGame.Tank_p1 and MianGame.Tank_p1.Live:
MianGame.Tank_p1.stop = True
def creation_etank(self):
"""
创建敌方坦克,并将敌方 坦克加到列表中
"""
left = [100, 800, 100, 800]
top = [100, 100, 500, 500]
speed = 1
for i in range(self.eTank_count):
etank = EnemyTank(left[i], top[i], speed)
self.eTank_list.append(etank)
def displayetank(self):
"""
展示敌方坦克
"""
# 遍历敌方坦克列表
for etank in MianGame.eTank_list:
if etank.Live:
etank.dispalayTank()
etank.randMove()
etank.hitMyTank()
etank.hitWalls()
ebullet = etank.shot()
if ebullet:
MianGame.enemy_bullet_list.append(ebullet)
else:
MianGame.eTank_list.remove(etank)
def blitBullet(self):
"""
在窗口中展示子弹,以及实现子弹的移动
"""
for bullet in self.bullet_list:
# 判断子弹的状态,如果活着,展示子弹,实现子弹的移动,碰撞,否则在列表中删除该子弹
if bullet.Live == True:
# 实现窗口展示子弹
bullet.displayBullet()
# 实现子弹的移动
bullet.moveBullet()
# 调用子弹打中墙壁的方法
bullet.hitWalls()
# 调用我方子弹与敌方坦克碰撞的方法
bullet.hitEnemyTank()
else:
MianGame.bullet_list.remove(bullet)
# 新增方法展示爆炸效果列表
def disExplode_list(self):
for explode in MianGame.Explode_list:
if explode.live:
explode.disExplode()
else:
music = Music("picture/blast.wav")
music.playMusic()
MianGame.Explode_list.remove(explode)
def enemy_blit_Bullet(self):
"""
在窗口中展示敌方坦克发射的子弹
:return:
"""
for ebullet in self.enemy_bullet_list:
if ebullet.Live == True:
ebullet.displayBullet()
ebullet.moveBullet()
# 调用敌方子弹与墙壁碰撞的方法
ebullet.hitWalls()
# 调用敌方子弹与我方坦克的碰撞方法
if MianGame.Tank_p1 and MianGame.Tank_p1.Live:
ebullet.hitMyTank()
else:
MianGame.enemy_bullet_list.remove(ebullet)
def creatwalls(self):
for i in range(8):
wall = Wall(120*i, 200)
MianGame.wall_list.append(wall)
def blitWalls(self):
for wall in MianGame.wall_list:
wall.displayWall()
class BaseItem(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
class Tank(BaseItem):
def __init__(self, left, top, speed):
self.images = {"U": pygame.image.load("picture/p1tankU.gif"),
"D": pygame.image.load("picture/p1tankD.gif"),
"L": pygame.image.load("picture/p1tankL.gif"),
"R": pygame.image.load("picture/p1tankR.gif")}
self.direction = "U"
self.image = self.images[self.direction]
self.rect = self.image.get_rect()
self.rect.left = left
self.rect.top = top
self.speed = speed
self.stop = True
# 新增属性坦克的状态
self.Live = True
# 用来记录坦克移动之前的坐标
self.oldleft = self.rect.left
self.oldtop = self.rect.top
def move(self):
if self.direction == "L":
if self.rect.left > 0:
self.rect.left -= self.speed
elif self.direction == "R":
if self.rect.left + self.rect.height < MianGame.display_width:
self.rect.left += self.speed
elif self.direction == "U":
if self.rect.top > 0:
self.rect.top -= self.speed
elif self.direction == "D":
if self.rect.top + self.rect.height < MianGame.display_height:
self.rect.top += self.speed
def shot(self):
return Bullet(self)
def stay(self):
self.rect.left = self.oldleft
self.rect.top = self.oldtop
def hitWalls(self):
for wall in MianGame.wall_list:
if pygame.sprite.collide_rect(wall, self):
self.stay()
def dispalayTank(self):
self.image = self.images[self.direction]
MianGame.window.blit(self.image, self.rect)
class MyTank(Tank):
def __init__(self, left, top, speed):
super(MyTank, self).__init__(left, top, speed)
def hitetank(self):
for etank in MianGame.eTank_list:
if pygame.sprite.collide_rect(etank, self):
self.stay()
class EnemyTank(Tank):
def __init__(self, left, top, speed):
super(EnemyTank, self).__init__(left, top, speed)
self.images = {"U": pygame.image.load("picture/enemy1U.gif"),
"D": pygame.image.load("picture/enemy1D.gif"),
"L": pygame.image.load("picture/enemy1L.gif"),
"R": pygame.image.load("picture/enemy1R.gif")}
self.direction = self.rmdirection()
self.image = self.images[self.direction]
self.rect = self.image.get_rect()
self.rect.left = left
self.rect.top = top
self.stop = True
self.speed = speed
self.step = 200
def rmdirection(self):
rmnum = random.randint(0, 3)
if rmnum == 0:
return "U"
if rmnum == 1:
return "D"
if rmnum == 2:
return "R"
if rmnum == 3:
return "L"
def randMove(self):
if self.step <= 0:
self.direction = self.rmdirection()
self.step = 200
else:
self.move()
self.step -= 1
def shot(self):
"""
重载tank类中shot方法
实现敌方坦克 shot类的不一样
:return:
"""
num = random.randint(1, 1000)
if num <= 5:
return Bullet(self)
def hitMyTank(self):
# MianGame.CreationMyTank(self)
# if pygame.sprite.collide_circle(self, MianGame.Tank_p1):
# self.stay()
pass
class Bullet(BaseItem):
def __init__(self, tank):
self.images = pygame.image.load("picture/bullent.png")
self.direction = tank.direction
self.rect = self.images.get_rect()
self.speed = 4
self.Live = True
# 通过坦克的方向来实现子弹所在的方向,继承tank类
if self.direction == "U":
self.rect.left = tank.rect.left + (tank.rect.width / 2) - (self.rect.width / 2)
self.rect.top = tank.rect.top - self.rect.height
if self.direction == "D":
self.rect.left = tank.rect.left + (tank.rect.width / 2) - (self.rect.width / 2)
self.rect.top = tank.rect.top + tank.rect.height
if self.direction == "R":
self.rect.left = tank.rect.left + tank.rect.height
self.rect.top = tank.rect.top + (tank.rect.width / 2) - (self.rect.width / 2)
if self.direction == "L":
self.rect.left = tank.rect.left - self.rect.height
self.rect.top = tank.rect.top + (tank.rect.width / 2) - (self.rect.width / 2)
def moveBullet(self):
"""
实现子弹的移动通过方向按键实现坦克的移动
:return:
"""
if self.direction == "U":
# 判断按键的方向
if self.rect.top > 0:
# 根据所在的位置进行移动,限定在窗口内
self.rect.top -= self.speed
else:
self.Live = False
if self.direction == "D":
if self.rect.top < MianGame.display_height - self.rect.height:
self.rect.top += self.speed
else:
self.Live = False
if self.direction == "L":
if self.rect.left > 0:
self.rect.left -= self.speed
else:
self.Live = False
if self.direction == "R":
if self.rect.left < MianGame.display_width - self.rect.width:
self.rect.left += self.speed
else:
self.Live = False
def displayBullet(self):
"""
展示子弹,将子弹添加到窗口中blit方法实现
:return:
"""
MianGame.window.blit(self.images, self.rect)
# 敌方坦克与我方子弹的碰撞
def hitEnemyTank(self):
"""
新增敌方坦克与我方子弹的碰撞方法
:return:
"""
# 遍历所有的敌方坦克,如果碰撞则将坦克和子弹的状态改为false
for eTank in MianGame.eTank_list:
if pygame.sprite.collide_rect(eTank, self):
# 产生一个爆炸效果
explode = Explode(eTank)
# 将爆炸效果加入到爆炸效果列表
MianGame.Explode_list.append(explode)
self.Live = False
eTank.Live = False
# 敌方子弹与我方坦克的碰撞
def hitMyTank(self):
if pygame.sprite.collide_rect(self, MianGame.Tank_p1):
# 产生爆炸效果
explode = Explode(MianGame.Tank_p1)
# 将爆炸效果添加到爆炸列表
# 將爆炸效果添加到爆炸效果列表的時候大寫,導致爆炸效果列表中沒有值,debug了好久,大傢自己寫的時候要注意細節
MianGame.Explode_list.append(explode)
# 修改子弹的状态
self.Live = False
# 修改我方坦克的状态
MianGame.Tank_p1.Live = False
def hitWalls(self):
for wall in MianGame.wall_list:
if pygame.sprite.collide_rect(wall, self):
self.Live = False
class Explode:
def __init__(self, tank):
self.rect = tank.rect
self.step = 0
self.images = [pygame.image.load("picture/blast1.png"),
pygame.image.load("picture/blast2.png"),
pygame.image.load("picture/blast3.png"),
pygame.image.load("picture/blast4.png"),
pygame.image.load("picture/blast5.png")]
self.image = self.images[self.step]
self.live = True
# 展示爆炸效果
def disExplode(self):
"""
将爆炸效果图片(image和位置rect加入到window中),通过step达到一个切换图片的效果
:return:
"""
if self.step < len(self.images):
MianGame.window.blit(self.image, self.rect)
self.image = self.images[self.step]
self.step += 1
else:
self.live = False
self.step = 0
class Wall:
def __init__(self, left, top):
self.image = pygame.image.load("picture/wall.gif")
self.rect = self.image.get_rect()
self.rect.left = left
self.rect.top = top
# 来判断墙壁是否在窗口中展示
self.live = True
# 来判断墙壁的生命值,没击中一次生命值减一
self.hp = 3
def displayWall(self):
MianGame.window.blit(self.image, self.rect)
class Music:
def __init__(self, filename):
self.filename = filename
pygame.mixer.init()
pygame.mixer.music.load(self.filename)
def playMusic(self):
pygame.mixer.music.play()
if __name__ == "__main__":
tank = MianGame()
tank.startGame()
完整版的坦克大战,,终于写完了,不过我留了一个了bug, 大家多玩几下应该能发现问题所在,至于碰撞的问题,那个是pygame的方法问题和我无关啊,-------哈哈哈哈
我后面会上传完整版的坦克大战素材和代码,不过希望大家还是要动手自己下,因为这样东西才会变成你的下载记得点个赞