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() 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) 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('坦克大战1.05') # 设置窗口标题 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() if not MainGame.myTank.stop: MainGame.myTank.move() MainGame.myTank.tank_hit_wall() # 检测与墙壁碰撞 MainGame.myTank.myTank_hit_enemyTank() # 检测与敌方坦克碰撞 else: del MainGame.myTank MainGame.myTank = None 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() font = pygame.font.SysFont('kaiti', 18) return font.render(text, True, TEXT_COLOR) 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: if event.key == pygame.K_ESCAPE: self.createMyTank() if MainGame.myTank and MainGame.myTank.live: if event.key == pygame.K_LEFT: MainGame.myTank.direction = 'L' MainGame.myTank.stop = False elif event.key == pygame.K_RIGHT: MainGame.myTank.direction = 'R' MainGame.myTank.stop = False elif event.key == pygame.K_UP: MainGame.myTank.direction = 'U' MainGame.myTank.stop = False elif event.key == pygame.K_DOWN: MainGame.myTank.direction = 'D' MainGame.myTank.stop = False elif event.key == pygame.K_SPACE and len(MainGame.myBulletList) < 3: MainGame.myBulletList.append(Bullet(MainGame.myTank)) if event.type == pygame.KEYUP: if event.key in (pygame.K_LEFT, pygame.K_UP, pygame.K_RIGHT, 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[self.direction] self.rect = self.image.get_rect() self.rect.left, self.rect.top = left, top self.speed = 5 self.stop = True self.live = True self.oldleft, self.oldtop = left, top def displayTank(self): # 显示坦克 MainGame.window.blit(self.images[self.direction], self.rect) def move(self): # 移动坦克 self.oldleft, self.oldtop = self.rect.left, self.rect.top if self.direction == 'L' and self.rect.left > 0: self.rect.left -= self.speed elif self.direction == 'R' and self.rect.left + self.rect.height < SCREEN_WIDTH: 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 def shot(self): # 发射子弹 return Bullet(self) def stay(self): # 保持原位 self.rect.left, self.rect.top = self.oldleft, 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().__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().__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] self.rect = self.image.get_rect() self.rect.left, self.rect.top = left, top self.speed, self.step = speed, 60 def randDirection(self): # 随机生成方向 return ['U', 'D', 'L', 'R'][random.randint(0, 3)] def randMove(self): # 随机移动 if self.step <= 0: self.direction, self.step = self.randDirection(), 60 else: self.move() self.step -= 1 def shot(self): # 敌方射击 return Bullet(self) if random.randint(0, 100) < 10 else None 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() 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.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, self.live = 6, True def displayBullet(self): # 显示子弹 MainGame.window.blit(self.image, self.rect) def move(self): # 子弹移动 if 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 == 'L' and self.rect.left > 0: self.rect.left -= self.speed elif self.direction == 'R' and 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, self.live = False, False MainGame.explodeList.append(Explode(enemyTank)) def enemyBullet_hit_myTank(self): # 敌方子弹命中检测 if MainGame.myTank and MainGame.myTank.live and pygame.sprite.collide_rect(self, MainGame.myTank): self.live, MainGame.myTank.live = False, False MainGame.explodeList.append(Explode(MainGame.myTank)) def bullet_hit_wall(self): # 子弹碰撞墙壁检测 for wall in MainGame.wallList: if pygame.sprite.collide_rect(self, wall): self.live, wall.hp = False, wall.hp-1 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() self.rect.left, self.rect.top = left, top self.live, self.hp = True, 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(f'./img/blast{i}.gif') for i in range(5)] self.step, self.live = 0, True def displayExplode(self): # 显示爆炸动画 if self.step < len(self.images): MainGame.window.blit(self.images[self.step], self.rect) self.step += 1 else: self.live = False if __name__ == '__main__': MainGame().startGame()