首先,我们得分析这个项目的结构,设计出它的框架
坦克大战游戏项目开发
需求分析
1.分析项目需要多少个类
2.分析每个类有哪些方法
1.坦克类(敌方坦克,我方坦克)
移动、射击、展示
2.子弹类
移动、展示
3.墙壁类
属性:是否可以通过
4.爆炸效果类
展示
5.音效类
播放音乐
6.主类
开始游戏
结束游戏
好了,直接上代码,不用担心看不懂,几乎每行都会有注释
import pygame import time import random SCREEN_WIDTH = 800 SCREEN_HEIGHT = 600 BG_COLOR = pygame.Color(0,0,0) TEXT_COLOR = pygame.Color(255,0,0) #定义一个基类 class BaseItem(pygame.sprite.Sprite): def __init__(self): 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.creatMyTank() #初始化敌方坦克,并添加到列表中 self.creatEnemyTank() # 初始化墙壁 self.creatWall() #设置窗口标题 pygame.display.set_caption('坦克大战1.0') while True: #让坦克的速度慢一点 time.sleep(0.05) #给窗口设置填充色 MainGame.window.fill(BG_COLOR) #获取事件 self.getevent() #绘制文字 MainGame.window.blit(self.getTextSurface('敌方坦克剩余数量:%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() #调用坦克移动的方法 #如果坦克的开关是开 才可以启动 if MainGame.my_tank and MainGame.my_tank.live: if not MainGame.my_tank.stop: MainGame.my_tank.move() #检测我方坦克是否与墙体发生碰撞 MainGame.my_tank.tank_hit_wall() #检测我方坦克是否与敌方坦克发生碰撞 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) # 初始化墙壁 def creatWall(self): for i in range(6): wall = Wall(i*150,230) MainGame.wallList.append(wall) def creatMyTank(self): MainGame.my_tank = MyTank(300, 300) #初始化音乐 music = Music('img/start.wav') #播放音乐 music.play() # 循环爆炸效果列表,进行展示 def blitExplode(self): for explode in MainGame.explodeList: #判断是否活着 if explode.live: explode.displayExplode() else: MainGame.explodeList.remove(explode) #循环敌方坦克列表,进行展示 def blitEnemyBullet(self): for EnenmyBullet in MainGame.enemyBulletList: # 判断当前子弹是否存活,是的话则展示 if EnenmyBullet.live: EnenmyBullet.displayBullet() # 调用子弹移动的方法 EnenmyBullet.move() #调用敌方子弹击中我方坦克的方法 EnenmyBullet.enemyBullet_hit_myTank() #调用子弹碰撞墙壁的方法 EnenmyBullet.bullet_hit_wall() else: # 删除子弹 MainGame.enemyBulletList.remove(EnenmyBullet) # 循环我方子弹列表,进行展示 def blitMyBullet(self): for MyBullet in MainGame.myBulletList: #判断当前子弹是否存活,是的话则展示 if MyBullet.live: MyBullet.displayBullet() # 调用子弹移动的方法 MyBullet.move() #调用我们子弹与敌方坦克发生碰撞的方法 if MainGame.my_tank and MainGame.my_tank.live: MyBullet.myBullet_hit_enemyTank() # 调用子弹碰撞墙壁的方法 MyBullet.bullet_hit_wall() else: #删除子弹 MainGame.myBulletList.remove(MyBullet) #循环敌方坦克列表进行展示 def blitEnemyTank(self): for enemyTank in MainGame.enemyTankList: #判断敌方坦克状态是否存活 if enemyTank.live: enemyTank.displayTank() enemyTank.randMove() # 调用检测敌方坦克是否与墙体发生碰撞 enemyTank.tank_hit_wall() # 调用检测敌方坦克是否与我方坦克发生碰撞 if MainGame.my_tank and MainGame.my_tank.live: enemyTank.enemyTank_hit_MyTank() # 发射子弹 enemyBullet = enemyTank.shoot() # 判断子弹的是否为None if enemyBullet: # 将敌方坦克子弹存储到子弹列表中 MainGame.enemyBulletList.append(enemyBullet) else: MainGame.enemyTankList.remove(enemyTank) # 初始化敌方坦克,并添加到列表中 def creatEnemyTank(self): top = 100 #循环生成敌方坦克 for i in range(MainGame.enemyTankCount): left = random.randint(1,700) speed = random.randint(1,7) enemy = EnemyTank(left,top,speed) MainGame.enemyTankList.append(enemy) #结束游戏 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): #获取所有事件 event_list = pygame.event.get() for event in event_list: #判断按下的是关闭还是键盘按下 #如果是退出,关闭窗口 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.creatMyTank() 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('发射子弹') if len(MainGame.myBulletList) < 3: myBullet = Bullet(MainGame.my_tank) MainGame.myBulletList.append(myBullet) #加载音乐 music = Music('img/fire.wav') music.play() #松开按键,坦克停止移动,修改坦克开关 if event.type == pygame.KEYUP: #判断松开的是上下左右才停止移动 if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT or event.key == pygame.K_UP or event.key == pygame.K_DOWN: 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('img/p1tankU.gif'), 'R':pygame.image.load('img/p1tankR.gif'), 'L':pygame.image.load('img/p1tankL.gif'), 'D':pygame.image.load('img/p1tankD.gif') } #方向 self.direction = 'U' #根据当前图片方向获取图片的 surface self.image = self.images[self.direction] #根据图片获取区域 self.rect = self.image.get_rect() #设置区域的 left 和 top self.rect.left = left self.rect.top = top #速度 决定移动的快慢 self.speed = 10 #坦克的开关 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': 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 shoot(self): return Bullet(self) 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() #展示 def displayTank(self): #获取展示的对象 self.image = self.images[self.direction] #调用blit方法展示 MainGame.window.blit(self.image,self.rect) class MyTank(Tank): def __init__(self,left,top): super(MyTank,self).__init__(left,top) pass #检测我方坦克与敌方坦克发生碰撞 def myTank_hit_enemyTank(self): for enemy in MainGame.enemyTankList: if pygame.sprite.collide_rect(self,enemy): self.stay() class EnemyTank(Tank): def __init__(self,left,top,speed): #调用父类的初始化方法 super(EnemyTank,self).__init__(left,top) #加载图片集 self.images = { 'U':pygame.image.load('img/enemy1U.gif'), 'R':pygame.image.load('img/enemy1R.gif'), 'L':pygame.image.load('img/enemy1L.gif'), 'D':pygame.image.load('img/enemy1D.gif') } #方向 随机生成敌方坦克的方向 self.direction = self.randDirection() #根据方向获取图片 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 #步数 self.step = 30 #敌方坦克与我方坦克发生碰撞 def enemyTank_hit_MyTank(self): if pygame.sprite.collide_rect(self,MainGame.my_tank): self.stay() #随机生成敌方坦克的方向 def randDirection(self): num = random.randint(1,4) if num == 1: return 'U' elif num == 2: return 'R' elif num == 3: return 'L' elif num == 4: return 'D' def randMove(self): if self.step <=0: #修改方向 self.direction = self.randDirection() #恢复步数 self.step = 40 else: self.move() #步数递减 self.step -= 1 #重写shoot def shoot(self): num = random.randint(1,100) if num <= 5: return Bullet(self) class Explode(): def __init__(self,tank): #爆炸效果位置由坦克被击中的位置决定 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 Wall(): def __init__(self,left,top): #加载图片 self.image = pygame.image.load('img/steels.gif') #获取区域 self.rect = self.image.get_rect() #设置位置 self.rect.left = left self.rect.top = top #设置存活状态 self.live = True #设置生命值 self.hp = 5 #展示墙的效果 def displayWall(self): MainGame.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 play(self): pygame.mixer.music.play() class Bullet(BaseItem): def __init__(self,tank): #加载图片 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 = 10 # 用来记录子弹是否活着 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 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) # 修改我方坦克和敌方方子弹的状态 MainGame.my_tank.live = False self.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 if wall.hp <= 0: #修改墙的状态 wall.live = False #展示 def displayBullet(self): MainGame.window.blit(self.image,self.rect) if __name__ == '__main__': MainGame().startGame() # MainGame().getTextSuface()
最终效果如下
ps:代码中的敌方坦克数量,墙体数量等都是自定义的,我方坦克阵亡后按ESC键重生!
以上代码中的图片素材与py文件必须要对应!
以上代码中的图片素材与py文件必须要对应!
以上代码中的图片素材与py文件必须要对应!
重要的事情说三遍!