Day016-018练习小游戏--坦克大战

mac2025-08-14  14

代码

""" v1.25 坦克大战的简单实现 """ import pygame,time,random _display = pygame.display COLOR_GREEN = pygame.Color(41, 132, 33) # 窗口颜色设置为绿色 COLOR_RED = pygame.Color(200, 0, 0) # 左上角文字设置为红色 version = "v1.25" # 版本信息 class MainGame: # 主逻辑类 # 游戏主窗口 window = None SCREEN_HEIGHT = 500 # 窗口高度:500 --常量 SCREEN_WIDTH = 800 # 窗口宽度:800 --常量 # 创建我方坦克 Tank_p1 = None # 存储所有的敌方坦克 EnemyTank_list = [] # 要创建的敌方坦克的数量 EnemyTank_count = 5 # 存储我方子弹的列表 Bullet_list = [] # 存储敌方子弹的列表 Enemy_bullet_list = [] # 爆炸效果列表 Explode_list = [] # 墙壁列表 Wall_list = [] # 开始游戏方法 def startGame(self): _display.init() # 初始化模块 # 创建窗口,借鉴官方文档说明 MainGame.window = _display.set_mode((MainGame.SCREEN_WIDTH, MainGame.SCREEN_HEIGHT), flags=0, depth=0) # 初始化窗口或屏幕以进行显示 # 创建我方坦克 self.creatMyTank() # 创建敌方坦克 self.creatEnemyTank() # 创建墙壁 self.creatWalls() # 设置游戏标题 _display.set_caption("坦克大战 " + version, "坦克大战") # 设置当前窗口标题 while True: # 给窗口填充一个颜色 MainGame.window.fill(COLOR_GREEN, rect=None, special_flags=0) # 在循环中持续完成事件的获取 self.getEvent() # 将绘制提示文字的小画布贴到系统窗口里 MainGame.window.blit(self.displayCornerText("剩余敌方坦克%d辆" % len(MainGame.EnemyTank_list)), (10, 10)) #调用展示墙壁方法 self.blitWall() # 将我方坦克加入到窗口中 if MainGame.Tank_p1 and MainGame.Tank_p1.live: MainGame.Tank_p1.displayTank() else: del MainGame.Tank_p1 MainGame.Tank_p1 = None # 循环展示敌方坦克 self.blitEnemyTank() # 根据开关的状态,调用坦克的移动方式 if MainGame.Tank_p1 and not MainGame.Tank_p1.stop: MainGame.Tank_p1.removeTank() # 调用我方主坦克与墙壁碰撞的方法 MainGame.Tank_p1.TankhitWalls() # 调用我方主坦克与敌方坦克的碰撞方法 MainGame.Tank_p1.hitEnemyTank() # 调用渲染我方坦克子弹的方法 self.blitBullet() # 调用渲染敌方坦克子弹的方法 self.blitEnemyBullet() # 调用展示爆炸效果的方法 self.displayExplodes() time.sleep(0.02) # 窗口的刷新操作 _display.update() # 创建我方坦克的方法 def creatMyTank(self): # 创建我方坦克 MainGame.Tank_p1 = MyTank(380, 420) # 创建音乐对象 music = Music("img/start.wav") # 调用播放音乐的方法 music.play() # 创建敌方坦克 def creatEnemyTank(self): for i in range(MainGame.EnemyTank_count): # 每次都随机生成left、top值 left = random.randint(1, 7) top = random.randint(0,1) speed = random.randint(3, 6) eTank = EnemyTank(left*100, top*100, speed) MainGame.EnemyTank_list.append(eTank) # 创建墙壁的方法 def creatWalls(self): for i in range(6): wall = Wall(130*i, 240) MainGame.Wall_list.append(wall) # 将墙壁加入到窗口中 def blitWall(self): for wall in MainGame.Wall_list: if wall.live: wall.displayWall() else: MainGame.Wall_list.remove(wall) # 将敌方坦克加入到窗口中 def blitEnemyTank(self): for eTank in MainGame.EnemyTank_list: if eTank.live: eTank.displayTank() # 坦克的移动 eTank.randMove() # 调用敌方坦克与墙壁碰撞的方法 eTank.TankhitWalls() # 调用敌方坦克与我方坦克碰撞的方法 eTank.hitMyTank() # 调用敌方坦克的射击方法 eBullet = eTank.shoot() #如果子弹为None。不加入到列表 if eBullet: #将子弹存储到敌方子弹列表中 MainGame.Enemy_bullet_list.append(eBullet) else: MainGame.EnemyTank_list.remove(eTank) # 将我方坦克子弹加入到窗口中 def blitBullet(self): for bullet in MainGame.Bullet_list: # 如果子弹还活着,就展示出来,否则就从子弹列表中删除 if bullet.live: bullet.displayBullet() # 子弹的移动 bullet.removeBullet() # 调用我方子弹与敌方坦克的碰撞方法 bullet.hitEnemyTank() # 调用我方子弹是否碰到墙壁的方法 bullet.hitWalls() else: MainGame.Bullet_list.remove(bullet) # 将敌方坦克子弹加入到窗口中 def blitEnemyBullet(self): for eBullet in MainGame.Enemy_bullet_list: # 如果子弹还活着,就展示出来,否则就从子弹列表中删除 if eBullet.live: eBullet.displayBullet() # 子弹的移动 eBullet.removeBullet() # 调用敌方子弹与墙壁的碰撞方法 eBullet.hitWalls() if MainGame.Tank_p1 and MainGame.Tank_p1.live: eBullet.hitMyTank() else: MainGame.Enemy_bullet_list.remove(eBullet) # 展示爆炸效果列表 def displayExplodes(self): for explode in self.Explode_list: if explode.live: explode.displayExplode() else: MainGame.Explode_list.remove(explode) # 获取程序期间所有事件(鼠标事件,键盘事件) def getEvent(self): # 1.获取所有事件 eventList = pygame.event.get() # 2.对事件进行判断处理(1.点击关闭按钮 2.按下键盘上的某个按键) for event in eventList: # 判断 event.type(事件类型) 是否为 QUIT(退出),如果是,直接调用程序结束的方法 if event.type == pygame.QUIT: self.endGame() # 判断事件类型是否为按键按下,如果是,继续判断是哪一个按键,来进行对应的处理 if event.type == pygame.KEYDOWN: # 按下ESC按键让我方坦克重生 if event.key ==pygame.K_ESCAPE and not MainGame.Tank_p1: # 调用创建我方坦克的方法 self.creatMyTank() if MainGame.Tank_p1 and MainGame.Tank_p1.live: # 具体是哪一个按键 if event.key == pygame.K_LEFT: print("坦克向左调头,移动") # 改变坦克方向 MainGame.Tank_p1.direction = "L" # 完成移动操作(调用坦克的移动方法) MainGame.Tank_p1.stop = False if event.key == pygame.K_RIGHT: print("坦克向右调头,移动") # 改变坦克方向 MainGame.Tank_p1.direction = "R" # 完成移动操作(调用坦克的移动方法) MainGame.Tank_p1.stop = False if event.key == pygame.K_UP: print("坦克向上调头,移动") # 改变坦克方向 MainGame.Tank_p1.direction = "U" # 完成移动操作(调用坦克的移动方法) MainGame.Tank_p1.stop = False if event.key == pygame.K_DOWN: print("坦克向下调头,移动") # 改变坦克方向 MainGame.Tank_p1.direction = "D" # 完成移动操作(调用坦克的移动方法) MainGame.Tank_p1.stop = False if event.key == pygame.K_SPACE: print("发射子弹") if len(MainGame.Bullet_list) < 3: # 产生一颗子弹 m = Bullet(MainGame.Tank_p1) #将子弹加入到子弹列表 MainGame.Bullet_list.append(m) music = Music("img/fire.wav") music.play() else: print("子弹数量不足") print("当前屏幕中的子弹数量为%d"%len(MainGame.Bullet_list)) # 判断事件类型是否为按键抬起,如果是,坦克停止移动 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.Tank_p1 and MainGame.Tank_p1.live: MainGame.Tank_p1.stop = True # 实现左上角问题提示内容方法 def displayCornerText(self, text): # 初始化字体模块 pygame.font.init() # 选择一个合适的字体 font = pygame.font.SysFont("fangsong", 18) # 将返回的字体对象赋值给 font # 使用对应字体完成相关内容的绘制 textSurface = font.render(text, True, COLOR_RED) return textSurface # 结束游戏方法 def endGame(self): print("游戏结束,谢谢使用!") # 结束python解释器 exit() class BaseItem(pygame.sprite.Sprite): # BaseItem父类,继承精灵父类 def __init__(self): pygame.sprite.Sprite.__init__(self) class Tank(BaseItem): # 坦克类,继承BaseItem父类,具有精灵特性 def __init__(self, left, top): super().__init__() 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 = "U" self.image = self.images[self.direction] # 坦克所在的区域 rect self.rect = self.image.get_rect() # 指定坦克初始化位置 分别距离x,y轴的位置 self.rect.left = left self.rect.top = top self.speed = 5 # 属性:坦克的移动开关 self.stop = True # 属性live,用来记录坦克是否活着 self.live = True # 属性:用来记录坦克移动钱的坐标(用于坦克位置还原使用) self.oldLeft = self.rect.left self.oldTop = self.rect.top # 坦克移动方法 def removeTank(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 < (MainGame.SCREEN_WIDTH - self.rect.height): 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 < (MainGame.SCREEN_HEIGHT - self.rect.height): self.rect.top += self.speed def stay(self): self.rect.left = self.oldLeft self.rect.top = self.oldTop # 坦克与墙壁碰撞的方法 def TankhitWalls(self): for wall in MainGame.Wall_list: if pygame.sprite.collide_rect(wall,self): self.stay() # 坦克射击的方法 def shoot(self): return Bullet(self) # 展示坦克的方法(将坦克这个surface(表面)加载到窗口) def displayTank(self): # 1.重新设置坦克图片 self.image = self.images[self.direction] # 2.将坦克加入到窗口中 MainGame.window.blit(self.image, self.rect) class MyTank(Tank): # 我方坦克 def __init__(self, left, top): # 继承父类的初始化设置 super().__init__(left, top) # 主动碰到敌方坦克的方法 def hitEnemyTank(self): for eTank in MainGame.EnemyTank_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) 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[self.direction] # 坦克所在的区域 rect self.rect = self.image.get_rect() # 指定坦克初始化位置 分别距离x,y轴的位置 self.rect.left = left self.rect.top = top self.speed = speed self.stop = True # 步数属性,用来控制敌方坦克的随即移动 self.step = 50 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 = 50 else: self.removeTank() self.step -= 1 def shoot(self): num = random.randint(1,1000) if num < 25: return Bullet(self) # 与我方坦克的碰撞方法 def hitMyTank(self): if MainGame.Tank_p1 and MainGame.Tank_p1.live: if pygame.sprite.collide_rect(MainGame.Tank_p1,self): # 让敌方坦克停下来 self.stay() #def displayEnemtTank(self): # 坦克的展示方法,因为是继承父类的方法,所以可写可不写 #super().displayTank() class Bullet(BaseItem): # 子弹类 ,继承BaseItem 父类,具有精灵特性 def __init__(self,tank): # 图片 self.image = pygame.image.load("img/enemymissile.gif") # 方向(与坦克的方向一致) self.direction = tank.direction # 位置 self.rect = self.image.get_rect() 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 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.height self.rect.top = tank.rect.top + tank.rect.width/2 - self.rect.width/2 # 速度 self.speed = 7 # live属性:用来记录子弹是否活着 self.live = True # 子弹移动方法 def removeBullet(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 < MainGame.SCREEN_HEIGHT - self.rect.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 < MainGame.SCREEN_WIDTH - self.rect.width: self.rect.left += self.speed else: # 修改状态值 self.live = False # 展示子弹方法 def displayBullet(self): MainGame.window.blit(self.image, self.rect) # 我方子弹碰撞敌方坦克的方法 def hitEnemyTank(self): for eTank in MainGame.EnemyTank_list: if pygame.sprite.collide_rect(eTank,self): # 产生一个爆炸效果 explode = Explode(eTank) # 将爆炸效果加入到爆炸效果列表 MainGame.Explode_list.append(explode) self.live = False eTank.live = False # 敌方子弹与我方坦克的碰撞方法 def hitMyTank(self): if pygame.sprite.collide_rect(self,MainGame.Tank_p1): # 产生爆炸效果,并加入到爆炸效果列表中 explode = Explode(MainGame.Tank_p1) MainGame.Explode_list.append(explode) # 修改子弹状态 self.live = False # 修改我方坦克的状态 MainGame.Tank_p1.live = False # 子弹与墙壁的碰撞 def hitWalls(self): for wall in MainGame.Wall_list: if pygame.sprite.collide_rect(wall,self): # 修改子弹live 属性 self.live = False # 修改墙壁生命值属性 wall.hp -= 1 if wall.hp <= 0: wall.live = False class Explode: # 爆炸效果类 def __init__(self,tank): self.rect = tank.rect self.step = 0 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.image = self.images[self.step] self.live = True # 爆炸效果展示方法 def displayExplode(self): if self.step < len(self.images): MainGame.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("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() MainGame().startGame()

运行效果:

最新回复(0)