You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

589 lines
20 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import pygame,time,random
from pygame.sprite import Sprite
#定义常量
SCREEN_WIDTH = 750
SCREEN_HEIGHT= 500
BG_COLOR = pygame.Color(0,0,0)
TEXT_COLOR = pygame.Color(255,0,0)
#创建精灵基类
class BaseItem(Sprite):
pass
class MainGame():
window = None
myTank = None
enemyCount = 5
enemyList = []
#定义我方坦克发射的子弹列表
myBulletList = []
#定义敌方坦克发射的子弹列表
enemyBulletList = []
#定义存储爆炸效果类列表
explodeList =[]
#定义墙壁列表
wallList = []
#初始化方法
def __init__(self) -> None:
pass
#创建敌方坦克
def createEnemyTank(self):
top = 100
for i in range(MainGame.enemyCount):
left = random.randint(0,600)
speed = random.randint(1,4)
enemyTank = EnemyTank(left,top,speed)
#添加到列表
MainGame.enemyList.append(enemyTank)
#加载敌方坦克
def displayEnemyTank(self):
for enemyTank in MainGame.enemyList:
#判断敌方坦克是否存活
if enemyTank.live:
enemyTank.displayTank()
#调用move进行移动
enemyTank.randMove()
#初始化敌方坦克发射的子弹
#调用检测敌方坦克是否与墙壁发生碰撞
enemyTank.tank_hit_wall()
#调用检测敌方坦克是否与我方坦克发生碰撞
if MainGame.myTank and MainGame.myTank.live:
enemyTank.enemyTank_hit_myTank()
enemyBullet = enemyTank.shot()
#判断子弹是否有值
if enemyBullet:
MainGame.enemyBulletList.append(enemyBullet)
else:#当前敌方坦克已经死亡,从敌方坦克列表移除
MainGame.enemyList.remove(enemyTank)
#显示我方坦克发射的子弹
def displayMyBullet(self):
for myBullet in MainGame.myBulletList:
#判断子弹是否存活
if myBullet.live :
myBullet.displayBullet()
#调用子弹的移动方法
myBullet.move()
#调用我方子弹是否与敌方坦克碰撞
myBullet.myBullet_hit_enemyTank()
#调用检测我方子弹是否与墙壁发生碰撞
myBullet.bullet_hit_wall()
else:
#从子弹列表中删除子弹
MainGame.myBulletList.remove(myBullet)
#显示敌方坦克发射的子弹
def displayEnemyBullet(self):
for enemyBullet in MainGame.enemyBulletList:
#判断子弹是否存活
if enemyBullet.live:
enemyBullet.displayBullet()
#调用子弹移动的方法
enemyBullet.move()
#调用敌方子弹与我方坦克碰撞检测
enemyBullet.enemyBullet_hit_myTank()
#调用检测敌方子弹是否与墙壁发生碰撞
enemyBullet.bullet_hit_wall()
else:
#从子弹列表删除
MainGame.enemyBulletList.remove(enemyBullet)
#循环遍历爆炸效果列表展示爆炸效果
def displayExplodeList(self):
for explode in MainGame.explodeList:
#判断是否存活
if explode.live:
#展示
explode.displayExplode()
else:
#从爆炸效果列表中移除
MainGame.explodeList.remove(explode)
#创建我方坦克
def createMyTank(self):
MainGame.myTank = MyTank(350,300)
#添加音效
music = Music('./img/start.wav')
#播放
music.playMusic()
#创建墙壁
def createWall(self):
top = 220
for i in range(6):
#初始化墙壁
wall = Wall(i*130,top)
#添加到墙壁列表
MainGame.wallList.append(wall)
#加载墙壁
def displayWallList(self):
#循环遍历墙壁列表
for wall in MainGame.wallList:
if wall.live:
wall.displayWall()
else:
#从墙壁列表中移除
MainGame.wallList.remove(wall)
#开始游戏
def startGame(self):
#初始化窗口
pygame.display.init()
#设置窗口大小
MainGame.window = pygame.display.set_mode((SCREEN_WIDTH,SCREEN_HEIGHT))
#设置窗口的标题
pygame.display.set_caption('坦克大战')
#初始化我方坦克
self.createMyTank()
#调用创建敌方坦克
self.createEnemyTank()
#创建墙壁
self.createWall()
while True:
time.sleep(0.02)
#给窗口设置填充色
MainGame.window.fill(BG_COLOR)
#添加文字信息提示
textSurface = self.getTextSurface('敌方坦克剩余数量%d'%len(MainGame.enemyList))
#主窗口显示文字信息
MainGame.window.blit(textSurface,(10,10))
#添加事件监听
self.getEvent()
#调用坦克的显示方法
if MainGame.myTank and MainGame.myTank.live:
MainGame.myTank.displayTank()
else:
#删除我方坦克
del MainGame.myTank
MainGame.myTank = None
#调用坦克移动的方法
if MainGame.myTank and MainGame.myTank.live :
if not MainGame.myTank.stop:
MainGame.myTank.move()
#调用检测我方坦克是否与墙壁发生碰撞
MainGame.myTank.tank_hit_wall()
#调用检测我方坦克是否与敌方坦克发生碰撞
MainGame.myTank.myTank_hit_enemyTank()
#加载敌方坦克
self.displayEnemyTank()
#加载我方坦克发射的子弹
self.displayMyBullet()
#加载敌方坦克发射的子弹
self.displayEnemyBullet()
#加载爆炸效果
self.displayExplodeList()
#加载墙壁
self.displayWallList()
pygame.display.update()
#结束游戏
def endGame(self):
print('谢谢使用,欢迎再次使用')
exit()
#添加文字信息提示
def getTextSurface(self,text):
#初始化字体模块
pygame.font.init()
#获取所有字体
# print(pygame.font.get_fonts())
#获取字体对象
font = pygame.font.SysFont('kaiti',18)
#绘制文字信息
textSurface = font.render(text,True,TEXT_COLOR)
return textSurface
#添加事件监听
def getEvent(self):
#获取所有的事件
eventList = pygame.event.get()
#遍历事件
for event in eventList:
#判断按下是否是关闭
if event.type == pygame.QUIT:
self.endGame()
#判断是否是键盘事件
if event.type == pygame.KEYDOWN:
#判断我方坦克是否消亡
if not MainGame.myTank:
#判断键盘按下的是Esc键
if event.key == pygame.K_ESCAPE:
#调用创建我方坦克的方法
self.createMyTank()
if MainGame.myTank and MainGame.myTank.live:
#判断按下的是上 下 左 右
if event.key == pygame.K_LEFT:
print('按下左键,坦克向左移动')
#修改我方坦克的方向
MainGame.myTank.direction='L'
#修改坦克移动开关
MainGame.myTank.stop=False
elif event.key == pygame.K_RIGHT:
print('按下右键,坦克向右移动')
#修改我方坦克的方向
MainGame.myTank.direction='R'
#修改坦克移动开关
MainGame.myTank.stop=False
elif event.key == pygame.K_UP:
print('按下上键,坦克向上移动')
#修改我方坦克的方向
MainGame.myTank.direction='U'
#修改坦克移动开关
MainGame.myTank.stop=False
elif event.key == pygame.K_DOWN:
print('按下下键,坦克向下移动')
#修改我方坦克的方向
MainGame.myTank.direction='D'
#修改坦克移动开关
MainGame.myTank.stop=False
elif event.key == pygame.K_SPACE:
print('发射子弹')
#子弹列表的数量如果小于3可以初始化子弹
if len(MainGame.myBulletList)<3:
#初始化子弹
myBullet = Bullet(MainGame.myTank)
MainGame.myBulletList.append(myBullet)
#添加音效
music = Music('./img/fire.wav')
music.playMusic()
#判断键盘键是否松开
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_UP or event.key == pygame.K_RIGHT or event.key == pygame.K_DOWN:
if MainGame.myTank and MainGame.myTank.live:
MainGame.myTank.stop = True
class Tank(BaseItem):
def __init__(self,left,top) -> None:
#保存加载的图片
self.images = {
'U':pygame.image.load('./img/p1tankU.gif'),
'D':pygame.image.load('./img/p1tankD.gif'),
'L':pygame.image.load('./img/p1tankL.gif'),
'R':pygame.image.load('./img/p1tankR.gif'),
}
#设置坦克的方向
self.direction = 'D'
#根据坦克方向,获取加载的图片
self.image = self.images.get(self.direction)
#根据图片获取图片的矩形区域
self.rect = self.image.get_rect()
#设置区域的left和top
self.rect.left = left
self.rect.top = top
#速度
self.speed = 5
#坦克移动开关
self.stop = True
#生存状态
self.live = True
#移动之前的位置
self.oldleft = self.rect.left
self.oldtop = self.rect.top
#展示坦克的方法
def displayTank(self):
self.image = self.images.get(self.direction)
#调用blit方法展示坦克
MainGame.window.blit(self.image,self.rect)
#移动坦克
def move(self):
#记录移动之前的位置
self.oldleft = self.rect.left
self.oldtop = self.rect.top
#判断坦克的方向
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<SCREEN_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<SCREEN_HEIGHT:
self.rect.top += self.speed
#射击
def shot(self):
pass
#设置坦克位置为移动之前的位置
def stay(self):
self.rect.left = self.oldleft
self.rect.top = self.oldtop
#检测坦克是否与墙壁发生碰撞
def tank_hit_wall(self):
#循环遍历墙壁列表
for wall in MainGame.wallList:
if pygame.sprite.collide_rect(self,wall):
#设置坦克的坐标为移动之前的位置
self.stay()
#我方坦克
class MyTank(Tank):
#初始化方法
def __init__(self,left,top) -> None:
#调用父类的初始方法
super(MyTank,self).__init__(left,top)
#检测我方坦克是否与敌方坦克发生碰撞
def myTank_hit_enemyTank(self):
#循环遍历敌方坦克列表
for enemyTank in MainGame.enemyList:
if pygame.sprite.collide_rect(self,enemyTank):
self.stay()
#敌方坦克
class EnemyTank(Tank):
def __init__(self,left,top,speed) -> None:
#调用父类的初始化方法
super(EnemyTank,self).__init__(left,top)
#加载保存的图片集
self.images= {
'U':pygame.image.load('./img/enemy1U.gif'),
'D':pygame.image.load('./img/enemy1D.gif'),
'L':pygame.image.load('./img/enemy1L.gif'),
'R':pygame.image.load('./img/enemy1R.gif'),
}
#设置敌方坦克方向
self.direction = self.randDirection()
#根据方向获取图片
self.image = self.images.get(self.direction)
#获取矩形区域
self.rect = self.image.get_rect()
#设置left top
self.rect.left = left
self.rect.top = top
self.speed = speed
#步数
self.step = 60
#随机生成方向
def randDirection(self):
num = random.randint(1,4)
if num == 1:
return 'U'
elif num == 2:
return 'D'
elif num == 3:
return 'L'
elif num == 4:
return 'R'
#随机移动的方法
def randMove(self):
if self.step <=0:
#修改敌方坦克的方向
self.direction = self.randDirection()
#让步数复位
self.step = 60
else:
self.move()
#步数递减
self.step-=1
def shot(self):
#随机生成100以内的数
num = random.randint(0,100)
if num<10:
return Bullet(self)
#检测敌方坦克是否与我方坦克发生碰撞
def enemyTank_hit_myTank(self):
if pygame.sprite.collide_rect(self,MainGame.myTank):
self.stay()
#子弹类
class Bullet(BaseItem):
def __init__(self,tank) -> None:
#加载图片
self.image = pygame.image.load('./img/enemymissile.gif')
#子弹的方向
self.direction = tank.direction
#根据图片获取区域
self.rect = self.image.get_rect()
#设置left top
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
elif 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
elif self.direction == 'L':
self.rect.left = tank.rect.left - self.rect.width / 2 - self.rect.width / 2
self.rect.top = tank.rect.top + tank.rect.width / 2 - self.rect.width / 2
elif self.direction == 'R':
self.rect.left = tank.rect.left + tank.rect.width
self.rect.top = tank.rect.top + tank.rect.width / 2 - self.rect.width / 2
#子弹的速度
self.speed = 6
#是否存活
self.live = True
#展示子弹
def displayBullet(self):
#将图片加载到窗口
MainGame.window.blit(self.image,self.rect)
#移动
def move(self):
if self.direction == 'U':
if self.rect.top>0:
self.rect.top -= self.speed
else: #碰到墙壁
self.live = False
elif self.direction == 'D':
if self.rect.top + self.rect.height < SCREEN_HEIGHT:
self.rect.top += self.speed
else:
self.live = False
elif self.direction == 'L':
if self.rect.left>0:
self.rect.left -= self.speed
else:
self.live = False
elif self.direction == 'R':
if self.rect.left + self.rect.width < SCREEN_WIDTH:
self.rect.left += self.speed
else:
self.live = False
#我方子弹与敌方坦克碰撞检测
def myBullet_hit_enemyTank(self):
#循环遍历敌方坦克列表
for enemyTank in MainGame.enemyList:
if pygame.sprite.collide_rect(self,enemyTank):
#修改敌方坦克与我方子弹的生存状态
enemyTank.live = False
self.live = False
#初始化爆炸效果类
explode = Explode(enemyTank)
#添加爆炸效果类到爆炸效果列表中
MainGame.explodeList.append(explode)
#敌方子弹与我方坦克发生碰撞
def enemyBullet_hit_myTank(self):
if MainGame.myTank and MainGame.myTank.live:
if pygame.sprite.collide_rect(self,MainGame.myTank):
#产生爆炸效果
explode = Explode(MainGame.myTank)
#将爆炸效果添加到爆炸效果列表
MainGame.explodeList.append(explode)
#修改敌方子弹与我方坦克的生存状态
self.live = False
MainGame.myTank.live = False
#检测子弹是否与墙壁发生碰撞
def bullet_hit_wall(self):
#循环遍历墙壁列表
for wall in MainGame.wallList:
if pygame.sprite.collide_rect(self,wall):
#设置子弹生存状态修改
self.live = False
#让墙壁的生命值减减
wall.hp -=1
#判断墙壁生命值是否小于等于0
if wall.hp<=0:
#设置墙壁的生存状态
wall.live = False
#墙壁类
class Wall():
def __init__(self,left,top) -> None:
#加载墙壁图片
self.image = pygame.image.load('./img/steels.gif')
#根据图片获取区域
self.rect = self.image.get_rect()
#设置left top
self.rect.left = left
self.rect.top = top
#生存状态
self.live = True
#生命值
self.hp = 3
#展示墙壁方法
def displayWall(self):
MainGame.window.blit(self.image,self.rect)
#爆炸效果类
class Explode():
def __init__(self,tank) -> None:
#爆炸的位置是当前子弹击中坦克的位置
self.rect = tank.rect
self.images = [
pygame.image.load('./img/blast0.gif'),
pygame.image.load('./img/blast1.gif'),
pygame.image.load('./img/blast2.gif'),
pygame.image.load('./img/blast3.gif'),
pygame.image.load('./img/blast4.gif'),
]
self.step = 0
self.image = self.images[self.step]
#生存状态
self.live = True
#展示爆炸效果
def displayExplode(self):
if self.step<len(self.images):
self.image = self.images[self.step]
self.step+=1
#添加到主窗口
MainGame.window.blit(self.image,self.rect)
else:
#修改存活状态
self.live = False
self.step = 0
#音效类
class Music():
def __init__(self,filename) -> None:
self.filename = filename
#初始化混合器
pygame.mixer.init()
#加载音乐
pygame.mixer.music.load(self.filename)
#播放音乐
def playMusic(self):
pygame.mixer.music.play()
#主方法
if __name__ == '__main__':
#调用主类中startGame()
MainGame().startGame()