python-坦克游戏
一、总结
''' 总结:
1. event事件,pygame.event:event.type指动作,按下或者松开/QUIT/鼠标移动等;event.key是键盘事件,指键盘上的具体按键。
2.pygame.sprite.collide_rect:使用矩形检测两个精灵之间的碰撞.
3.B.blit(A,)的功能是把一张图A粘贴到另一张图B上,这意味着B上的图将被A上的图覆盖,且永久不能恢复。blit()的原型是
blit(source, dest, area=None, special_flags = 0),返回值为rect对象,返回被改变的画面区域.source是Surface对象,即一张图;dest参数
指定绘制的位置,可为元组/Rect对象;
'''
二、游戏框架及代码
#加载主窗口 #pygame官方网址:www.pygame.org ''' 添加事件: 1 点击关闭,关闭窗口 2 按下键盘的时候,判断键盘按下的是什么键,分别对不同的键做处理''' ''' 左上角文字绘制: 左上角敌方坦克的数量6(默认6)''' ''' 加载我方坦克 1 我方坦克切换方向 2 我方坦克移动 3 优化我方坦克移动的方法 4 按下方向键坦克一直移动,松开,坦克停止 ''' ''' 加载敌方坦克: 1 完善敌方坦克初始化方法 2 创建敌方坦克并展示 ''' ''' 1 优化左上角文字显示,将敌方坦克的数量进行修改 2 敌方坦克的随机移动 思路:新增一个变量步数,当移动时候步数进行递减 当步数<=0时修改敌方坦克的方向,并将步数复位 ''' ''' 1 完善子弹类 2 完成我方坦克发射子弹并完成子弹的移动 优化: 1 如果子弹碰到墙壁,让子弹消失 2 最多可以发射3颗,不能一直发射 ''' ''' 我方子弹与敌方坦克的碰撞:精灵类sprite类已实现。 ''' ''' 1 完善爆炸效果类 2 在窗口中展示爆炸效果 ''' ''' 1 敌方子弹与我放坦克的碰撞 2 添加爆炸效果 3 让我方坦克无限重生 1) 按下键盘的ESC让重生 2) 重生及重新创建我方坦克 ''' ''' 添加墙壁 1 完善墙壁类,初始化方法 2 初始化墙壁,并将墙壁存储到列表中,在窗口中加载墙壁 ''' ''' 新增: 1 子弹不能穿墙 子弹碰撞到墙壁时候,让子弹消失 2 墙壁被击中,墙壁的生命值处理 ''' '''新增: 1 坦克不能穿墙 坦克碰撞到墙壁,不能再移动 不能再移动及坐标不能发生变化''' '''新增: 1 我方坦克与敌方坦克发生碰撞: 我方坦克不能继续移动 stay() 2 敌方坦克与我方坦克发生碰撞: 敌方坦克不能继续移动 stay()''' '''新增: 1 完善音效类 2 添加开场音效 3 我方坦克发射子弹添加音效''' from _ast import In from builtins import * from tkinter.tix import _dummyButton from pygame import sprite import pygame, time, random from pygame.sprite import Sprite from twisted.conch.insults.text import _TEXT_COLORS SCREEN_WIDTH=800 SCREEN_HEIGHT=500 BG_COLOR=pygame.Color(0,0,0) TEXT_COLOR=pygame.Color(255,0,0) #定义一个基类 class BaseItem(Sprite): def __init__(self,color,width,height): pygame.sprite.Sprite.__init__(self) class MainGame(): window=None my_tank=None #存储敌方坦克的列表 enemyTankList=[] #定义敌方坦克的数量 enemyTankCount=5 #存储我方子弹的列表 myBulletList=[] #存储敌方子弹的列表 enemyBulletList=[] #存储爆炸效果的列表 explodeList=[] #存储墙壁的列表 wallList=[] def __init__(self): pass #开始游戏 def startGame(self): #加载主窗口 #初始化窗口 pygame.display.init() #设置窗口的大小积显示 MainGame.window=pygame.display.set_mode([SCREEN_WIDTH,SCREEN_HEIGHT]) #初始化我方坦克 self.createMytank() #初始化敌方坦克,并将敌方坦克添加到列表中 self.createEnemyTank() #初始化墙壁 self.createWall() #设置窗口的标题 pygame.display.set_caption('坦克大战1.03') while True: #使坦克的速度慢一点 time.sleep(0.02) #给窗口填充颜色 MainGame.window.fill(BG_COLOR) #获取事件 self.getEvent() #绘制文字 MainGame.window.blit(self.getTextSuface('敌方坦克剩余数量%d'%len(MainGame.enemyTankList)),(10,10)) #调用坦克显示的方法 #判断我方坦克是否存活 if MainGame.my_tank and MainGame.my_tank.live: MainGame.my_tank.displayTank() else: #删除我方坦克 del MainGame.my_tank MainGame.my_tank=None #循环遍历敌方坦克列表,展示敌方坦克 self.blitEnemyTank() #循环遍历显示我方坦克列表 self.blitMyBullet() #循环遍历敌方子弹列表,展示敌方子弹 self.blitEnemyBullet() #循环遍历爆炸列表,展示爆炸效果 self.blitExplode() #循环遍历墙壁列表,展示墙壁 self.blitWall() #调用移动方法 #MainGame.my_tank.move() #如果坦克的开关是开启,才可以移动 if MainGame.my_tank and MainGame.my_tank.live: if not MainGame.my_tank.stop: MainGame.my_tank.move() #检测我方坦克是否与墙壁发生碰撞 MainGame.my_tank.hitWall() #检测我方坦克是否与敌方坦克发生碰撞 MainGame.my_tank.myTank_hit_enemyTank() pygame.display.update() #循环遍历墙壁列表,展示墙壁 def blitWall(self): for wall in MainGame.wallList: #判断墙壁是否存活 if wall.live: #调用墙壁的显示方法 wall.displayWall else: #从墙壁列表移出 MainGame.wallList.remove(wall) #调用墙壁的展示方法 wall.displayWall() #初始化墙壁 def createWall(self): for i in range(6): #初始化墙壁 wall=Wall(i*130,220) #将墙壁添加到列表中 MainGame.wallList.append(wall) #创建我方坦克的方法 def createMytank(self): MainGame.my_tank=MyTank(350,300) #创建music对象 music=Music('/Users/姓名/Desktop/puke/tanke1/start.wav') #播放音乐 music.play() #初始化敌方坦克,并将敌方坦克添加到列表中 def createEnemyTank(self): top=100 #循环生成敌方坦克 for i in range(MainGame.enemyTankCount): left=random.randint(0,600) speed=random.randint(1,4) enemy=EnemyTank(left,top,speed) MainGame.enemyTankList.append(enemy) #EnemyTank(left,top,speed) #循环展示爆炸效果 def blitExplode(self): for explode in MainGame.explodeList: #判断是否活着 if explode.live: #展示 explode.displayExplode() else: #在爆炸列表中移除 MainGame.explodeList.remove(explode) #循环遍历敌方坦克列表,展示敌方坦克 def blitEnemyTank(self): for enemyTank in MainGame.enemyTankList: #先判断当前敌方坦克是否活着 if enemyTank.live: enemyTank.displayTank() enemyTank.randMove() #调用检测是否与墙壁碰撞 enemyTank.hitWall() #检测敌方坦克是否与我方坦克发生碰撞 if MainGame.my_tank and MainGame.my_tank.live: enemyTank.enemyTank_hit_myTank() #发射子弹 enemyBullet=enemyTank.shot() #判断敌方子弹是否为None,如果不为None则添加到子弹列表中 if enemyBullet: #将敌方子弹存储到敌方子弹列表中 MainGame.enemyBulletList.append(enemyBullet) else:#不活着,从敌方坦克列表中移除 MainGame.enemyTankList.remove(enemyTank) #循环遍历我方子弹存储列表 def blitMyBullet(self): for myBullet in MainGame.myBulletList: ''' myBullet.displayBullet() #调用子弹的移动方法 myBullet.move() ''' #判断当前的子弹是否是活着的状态,如果是则进行显示及移动 if myBullet.live: myBullet.displayBullet() #调用子弹的移动方法 myBullet.move() #调用检测我方子弹是否与敌方坦克发生碰撞 myBullet.myBullet_hit_enemyTank() #检测我方子弹是否与墙壁碰撞 myBullet.hitWall() else: MainGame.myBulletList.remove(myBullet) #循环遍历敌方子弹列表,展示敌方子弹 def blitEnemyBullet(self): for enemyBullet in MainGame.enemyBulletList: #判断敌方子弹是否存活 if enemyBullet.live: enemyBullet.displayBullet() enemyBullet.move() #调用敌方子弹与我方坦克碰撞的方法 enemyBullet.enemyBullet_hit_myTank() #检测敌方子弹是否与墙壁碰撞 enemyBullet.hitWall() else: MainGame.enemyBulletList.remove(enemyBullet) #结束游戏 def endGame(self): print('谢谢使用,欢迎再次使用') exit() #左上角文字的绘制 def getTextSuface(self,text): #初始化字体模块 pygame.font.init() #查看所有的字体颜色 #print(pygame.font.get_fonts()) #获取font字体对象 font=pygame.font.SysFont('songti',15) #绘制文字信息 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.my_tank: #判断按下的是ESC键,让坦克重生 if event.key==pygame.K_ESCAPE: #让坦克重生及调用创建坦克的方法 self.createMytank() if MainGame.my_tank and MainGame.my_tank.live: #判断按下的是上/下/左/右 if event.key==pygame.K_LEFT: #切换方向 MainGame.my_tank.direction='L' #修改坦克的开关状态 MainGame.my_tank.stop=False #MainGame.my_tank.move() print('按下的是左键,坦克向左移动') elif event.key==pygame.K_RIGHT: MainGame.my_tank.direction='R' #修改坦克的开关状态 MainGame.my_tank.stop=False #MainGame.my_tank.move() print('按下的是右键,坦克向右移动') elif event.key==pygame.K_UP: MainGame.my_tank.direction='U' #修改坦克的开关状态 MainGame.my_tank.stop=False #MainGame.my_tank.move() print('按下的是上键,坦克向上移动') elif event.key==pygame.K_DOWN: MainGame.my_tank.direction='D' #修改坦克的开关状态 MainGame.my_tank.stop=False #MainGame.my_tank.move() print('按下的是下键,坦克向下移动') elif event.key==pygame.K_SPACE: print('发射子弹') '''#创建我方坦克发射的子弹 myBullet=Bullet(MainGame.my_tank) MainGame.myBulletList.append(myBullet)''' #如果当前我方子弹列表的大小小于等于3才可以进行创建 if len(MainGame.myBulletList)<3: #创建我方坦克发射的子弹 myBullet=Bullet(MainGame.my_tank) MainGame.myBulletList.append(myBullet) #给我方坦克发射子弹添加音效 music=Music('/Users/姓名/Desktop/puke/tanke1/.') music.play() #松开方向键,坦克停止,修改坦克的开关状态 #判断释放松开的键是上/下/左/右时才停止坦克移动 if event.type==pygame.KEYUP and (event.key==pygame.K_UP or event.key==pygame.K_DOWN or event.key==pygame.K_LEFT or event.key==pygame.K_RIGHT): if MainGame.my_tank and MainGame.my_tank.live: MainGame.my_tank.stop=True class Tank(BaseItem): #添加距离左边left,距离上边top def __init__(self,left,top): #保存加载的图片 self.images={'U':pygame.image.load('/Users/姓名/Desktop/puke/tanke1/U.png'), 'D':pygame.image.load('/Users/姓名/Desktop/puke/tanke1/D.png'), 'L':pygame.image.load('/Users/姓名/Desktop/puke/tanke1/L.png'), 'R':pygame.image.load('/Users/姓名/Desktop/puke/tanke1/R.png'),} #方向 self.direction='U' #根据当前图片的方向获取图片 self.image=self.images[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 move(self): #移动后记录原始的坐标 self.oldLeft=self.rect.left self.oldTop=self.rect.top #判断坦克的方向进行移动 if self.direction == 'L' and self.rect.left>0: self.rect.left -= self.speed elif self.direction == 'U' and self.rect.top>0: self.rect.top -= self.speed elif self.direction == 'D' and self.rect.top+self.rect.height<SCREEN_HEIGHT: self.rect.top += self.speed elif self.direction == 'R' and self.rect.left+self.rect.height<SCREEN_WIDTH: self.rect.left += self.speed #射击 def shot(self): return Bullet(self) def stay(self): self.rect.left=self.oldLeft self.rect.top=self.oldTop #检测坦克是否与墙壁发生碰撞 def hitWall(self): for wall in MainGame.wallList: if pygame.sprite.collide_rect(self, wall): #将坐标设置为移动之前的坐标 self.stay() #展示坦克 def displayTank(self): #获取展示的对象 self.image=self.images[self.direction] #调用blit方法展示,使用pygame.transform.scale(self.image,(50,50))修改self.image图片的大小 MainGame.window.blit(pygame.transform.scale(self.image,(50,50)),self.rect) #我方坦克 class MyTank(Tank): def __init__(self,left,top): super(MyTank,self).__init__(left,top) #检测我方坦克与敌方坦克发生碰撞 def myTank_hit_enemyTank(self): #循环遍历敌方坦克列表 for enemyTank in MainGame.enemyTankList: if pygame.sprite.collide_rect(self, enemyTank): self.stay() #敌方坦克 class EnemyTank(Tank): def __init__(self,left,top,speed): #调用父类的初始化方法 super(EnemyTank,self).__init__(left,top) #加载图片集 self.images={'U':pygame.image.load('/Users/姓名/Desktop/puke/tanke1/enemyU.png'), 'D':pygame.image.load('/Users/姓名/Desktop/puke/tanke1/enemyD.png'), 'L':pygame.image.load('/Users/姓名/Desktop/puke/tanke1/enemyL.png'), 'R':pygame.image.load('/Users/姓名/Desktop/puke/tanke1/enemyR.png')} #方向,随机生成敌方坦克的方向 self.direction=self.randDirecrion() #根据方向获取图片 self.image=self.images[self.direction] #区域 self.rect=self.image.get_rect() #对left和top进行赋值 self.rect.left=left self.rect.top=top #速度 self.speed=speed #移动开关键 self.flag=True #新增加一个步数变量,step self.step=100 #敌方坦克与我方坦克是否发生碰撞 def enemyTank_hit_myTank(self): if pygame.sprite.collide_rect(self,MainGame.my_tank): self.stay() #方向,随机生成敌方坦克的方向 def randDirecrion(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.randDirecrion() #让步数复位 self.step=100 else: self.move() #让步数递减 self.step-=1 #重写shot方法 def shot(self): #随机生成100以内的数 num=random.randint(1,100) if num<10: return Bullet(self) #子弹类 class Bullet(BaseItem): def __init__(self,tank): #加载图片 self.image=pygame.image.load('/Users/姓名/Desktop/puke/tanke1/enemymissile.png') #坦克的方向决定子弹的方向 self.direction=tank.direction #获取区域 self.rect=self.image.get_rect() #子弹的left和top与方向有关 if self.direction=='U': self.rect.left=tank.rect.left-self.rect.width/2+tank.rect.width/2 self.rect.top=tank.rect.top-self.rect.height #print('tank.rect.width==',tank.rect.left,' ',tank.rect.width,' ','self.rect=',self.rect.left) elif self.direction=='L': self.rect.left=tank.rect.left-self.rect.width self.rect.top=tank.rect.top+tank.rect.width/2-self.rect.height/2 elif self.direction=='R': self.rect.left=tank.rect.left+tank.rect.height self.rect.top=tank.rect.top+tank.rect.width/2-self.rect.height/2 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 #子弹的速度 self.speed=6 #子弹的状态,是否碰到墙壁,如果碰到墙壁,修改此状态 self.live=True #移动子弹 def move(self): if self.direction=='U': if self.rect.top>0: self.rect.top-=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 elif self.direction=='L': if self.rect.left>0: self.rect.left-=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 #子弹是否碰撞墙壁 def hitWall(self): #循环遍历墙壁列表 for wall in MainGame.wallList: if pygame.sprite.collide_rect(self,wall): self.live=False #墙壁的生命值减少 wall.hp-=1 if wall.hp<=0: #修改墙壁的生存状态 wall.live=False #显示子弹类 def displayBullet(self): #将图片surface加载到窗口 MainGame.window.blit(self.image,self.rect) #我方子弹与敌方坦克的碰撞 def myBullet_hit_enemyTank(self): #循环遍历敌方坦克列表,判断是否发生碰撞 for enemyTank in MainGame.enemyTankList: if pygame.sprite.collide_rect(enemyTank,self): #修改敌方坦克和我放坦克的状态 enemyTank.live=False self.live=False #创建爆炸对象 explode=Explode(enemyTank) #将爆炸对象添加到爆炸列表中 MainGame.explodeList.append(explode) #敌方子弹与我方坦克的碰撞 def enemyBullet_hit_myTank(self): if MainGame.my_tank and MainGame.my_tank.live: if pygame.sprite.collide_rect(MainGame.my_tank, self): #产生爆炸对象 explode=Explode(MainGame.my_tank) #将爆炸对象添加到爆炸列表中 MainGame.explodeList.append(explode) #修改敌方子弹与我方坦克的状态 self.live=False MainGame.my_tank.live=False #墙壁类 class Wall(): def __init__(self,left,top): #加载墙壁图片 self.image=pygame.image.load('/Users/姓名/Desktop/puke/tanke1/steels.png') #获取墙壁的区域 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): #爆炸的位置由当前子弹打中的坦克位置决定 self.rect=tank.rect self.images=[ pygame.image.load('/Users/姓名/Desktop/puke/tanke1/blast00.png'), pygame.image.load('/Users/姓名/Desktop/puke/tanke1/blast01.png'), pygame.image.load('/Users/姓名/Desktop/puke/tanke1/blast02.png'), pygame.image.load('/Users/姓名/Desktop/puke/tanke1/blast03.png'), pygame.image.load('/Users/姓名/Desktop/puke/tanke1/blast04.png'), ] 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): self.filename=filename #初始化音乐混合器 pygame.mixer.init() #加载音乐 pygame.mixer.music.load(self.filename) #播放音乐 def showMusic(self): pygame.mixer.music.play() if __name__=='__main__': MainGame().startGame() #MainGame().getTextSuface()
游戏开发模版:
https://blog.csdn.net/zha6476003/article/details/82940350/
浙公网安备 33010602011771号