一、实现功能包括:多架敌机随机出现,生命数3,死亡时倒计时后重新开局,炸弹随机降落,统计击败敌机数,三张地图每局随机出现,击败敌机数达到10时出现大飞机,大飞机发射子弹更密集等。
二、pycharm源码文件以及图片素材资源已在主页上传,代码以及运行结果如下:
import time import random from PIL import Image import pygame from pygame.constants import * #己方飞机类 class Player(pygame.sprite.Sprite): # 存放所有飞机的子弹的组 bullets = pygame.sprite.Group() def __init__(self,screen): # 这个精灵的初始化方法 必须调用 pygame.sprite.Sprite.__init__(self) # 创建一个玩家飞机图片,当做真正的飞机 self.image = pygame.image.load("./feiji/hero1.png") #通过图片获得矩阵 self.rect = self.image.get_rect() # rect:矩形 # 定义飞机初始化坐标 self.rect.topleft = [Manager.bg_size[0] / 2 - 100 / 2,600] # 飞机速度 self.speed = 10 #记录当前窗口对象 self.screen = screen #子弹图片 self.bullet_image = "./feiji/bullet.png" # 飞机子弹频率 1~100,表示每0.01秒百分之几的概率发射 self.bullet_frequency = 10 def key_control(self): # 监听键盘事件 key_pressed = pygame.key.get_pressed() if key_pressed[K_w] or key_pressed[K_UP]: self.rect.top -= self.speed if key_pressed[K_s] or key_pressed[K_DOWN]: self.rect.bottom += self.speed if key_pressed[K_a] or key_pressed[K_LEFT]: # 定义飞机左行驶尽头边界 if self.rect.left >= 10 : self.rect.left -= self.speed if key_pressed[K_d] or key_pressed[K_RIGHT]: #定义飞机右行驶尽头边界 if self.rect.right <= Manager.bg_size[0]: self.rect.right += self.speed if key_pressed[K_SPACE]: # 随机发射子弹 if random.randint(0,99) in range(self.bullet_frequency): bullet = Bullet(self.screen ,self.rect.left + 50 - Image.open(self.bullet_image).size[0]/2 ,self.rect.top - Image.open(self.bullet_image).size[1]) # 将己方子弹子弹改为 bullet.image = pygame.image.load(self.bullet_image) Player.bullets.add(bullet) #键盘监听控制飞机,飞机的显示 def update(self): self.key_control() self.display() def display(self): # 粘贴飞机坐标 self.screen.blit(self.image, self.rect) #更新子弹坐标 for i in Player.bullets: i.player_fire() # 对应子弹的update方法 Player.bullets.update() # 把所有子弹全部添加到屏幕 Player.bullets.draw(self.screen) #敌方飞机类 class Enemyplayer(pygame.sprite.Sprite): # 放子弹的列表,类属性,通过类名调用 bullets = pygame.sprite.Group() def __init__(self,screen,image ): # 这个精灵的初始化方法 必须调用 pygame.sprite.Sprite.__init__(self) #记录窗口 self.screen = screen #获取敌方飞机图片 self.image = pygame.image.load(image) #通过图片获得矩阵 self.rect = self.image.get_rect() #敌方飞机坐标初始化 self.rect.topleft = [Manager.bg_size[0]/2 - 50/2,0] # 放子弹的列表,类属性,通过类名调用 self.bullets = pygame.sprite.Group() # 子弹图片 self.bullet_image = "./feiji/bullet1.png" #敌方飞机子弹频率 1~100,平均一秒发射几个 self.bullet_frequency = 3 #敌机移动方向 self.direciton= "left" #飞机是否向下移动 self.direciton_up = False #敌机速度 self.speed = 4 def display(self): #粘贴敌机到窗口 self.screen.blit(self.image,self.rect.topleft) #敌方飞机自动开火方法 def auto_fire(self): #控制敌方子弹频率 if random.randint(1, 100) in range(0,self.bullet_frequency): #通过飞机坐标跟子弹分辨率大小调用子弹对象 bullet = Bullet(self.screen,self.rect.left + 25 - Image.open(self.bullet_image).size[0]/2 ,self.rect.top + Image.open(self.bullet_image).size[1] + 20) #将敌方子弹子弹改为 bullet.image = pygame.image.load(self.bullet_image) #向Bullet子弹对象列表增加一个子弹对象 Enemyplayer.bullets.add(bullet) #敌方飞机自动飞行方法 def auto_move(self): if self.direciton == "left": self.rect.left -= self.speed if self.direciton_up : self.rect.bottom += self.speed elif self.direciton == "right": self.rect.right += self.speed if self.direciton_up: self.rect.bottom += self.speed if self.rect.left <= 0 : self.direciton = "right" elif self.rect.right >=Manager.bg_size[0]: self.direciton = "left" #使敌方飞机飞出窗口时消除该敌方飞机对象 def kill_enemy(self): if self.rect.top > Manager.bg_size[1]: self.kill() #敌方飞机自动移动,自动发射以及显示 def update(self): self.auto_move() self.auto_fire() self.display() self.kill_enemy() #子弹类 class Bullet(pygame.sprite.Sprite): def __init__(self,screen,x,y): # 这个精灵的初始化方法 必须调用 pygame.sprite.Sprite.__init__(self) self.screen = screen self.image = pygame.image.load("./feiji/bullet.png") #通过图片获得矩阵 self.rect = self.image.get_rect() # 初始化子弹坐标 self.rect.topleft = [x , y ] #子弹速度 self.speed = 8 #己方飞机开火 def player_fire(self): self.rect.top -= self.speed+4 #敌方飞机开火 def enemy_fire(self): self.rect.bottom += self.speed/2 def update(self): # 如果子弹移出屏幕上方 则销毁子弹对象 if self.rect.top > Manager.bg_size[1] or self.rect.bottom < 0 : self.kill() self.enemy_fire() # 把所有子弹全部添加到屏幕 Enemyplayer.bullets.draw(self.screen) # 炸弹类 class Bombshell(pygame.sprite.Sprite): def __init__(self,screen): # 这个精灵的初始化方法 必须调用 pygame.sprite.Sprite.__init__(self) self.screen = screen # 传入炸弹图片 self.image = pygame.image.load("./feiji/bomb-2.gif") # 炸弹矩形获取 self.rect = self.image.get_rect() # 炸弹速度 self.speed = 2 self.direciton = "left" # 炸弹初始坐标 self.rect.topleft = [0,0] def auto_move(self): # 往左移动 if self.direciton == "left": self.rect.left -= self.speed self.rect.bottom += self.speed # 往右移动 elif self.direciton == "right": self.rect.right += self.speed self.rect.bottom += self.speed #左右移动边界 if self.rect.left <= 0: self.direciton = "right" elif self.rect.right >= Manager.bg_size[0]: self.direciton = "left" # 使敌方炸弹飞出窗口时消除该敌方飞机对象 def kill_bomb(self): if self.rect.top > Manager.bg_size[1]: self.kill() def display(self): # 粘贴炸弹到窗口 self.screen.blit(self.image, self.rect.topleft) def update(self): self.auto_move() self.display() self.kill_bomb() class Bomb(object): # 初始化爆炸 def __init__(self, screen, type): self.screen = screen if type == 'enemy': # 加载爆炸资源 self.mImages = [ pygame.image.load("./feiji/enemy0_down" + str(v) + ".png") for v in range(1, 5)] else: # 加载爆炸资源 self.mImages = [pygame.image.load( "./feiji/hero_blowup_n" + str(v) + ".png") for v in range(1, 5)] self.mImages += self.mImages # 设置当前爆炸播放索引 self.mIndex = 0 # 爆炸位置 self.mPos = [0, 0] # 是否可见 self.mVisible = False # 设置位置 def action(self, rect): # 触发爆炸方法draw # 爆炸的坐标 self.mPos[0] = rect.left self.mPos[1] = rect.top # 打开爆炸的开关 self.mVisible = True # 绘制爆炸 def draw(self): if not self.mVisible: return self.screen.blit(self.mImages[self.mIndex], (self.mPos[0], self.mPos[1])) self.mIndex += 1 if self.mIndex >= len(self.mImages): # 如果下标已经到最后 代表爆炸结束 # 下标重置 mVisible重置 self.mIndex = 0 self.mVisible = False # 地图 class GameBackground(object): # 初始化地图,传入参数窗口跟地图编号 def __init__(self, screen,num): self.mImage1 = pygame.image.load("./feiji/img_bg_level_"+str(num)+".jpg") self.mImage2 = pygame.image.load("./feiji/img_bg_level_"+str(num)+".jpg") # 窗口 self.screen = screen # 辅助移动地图 self.y1 = 0 self.y2 = -Manager.bg_size[1] # -768 # 移动地图 def move(self): self.y1 += 2 self.y2 += 2 if self.y1 >= Manager.bg_size[1]: self.y1 = 0 if self.y2 >= 0: self.y2 = -Manager.bg_size[1] # 绘制地图 def draw(self): self.screen.blit(self.mImage1, (0, self.y1)) self.screen.blit(self.mImage2, (0, self.y2)) # 背景音乐类 class GameSound(pygame.sprite.Sprite): def __init__(self): #这个精灵的初始化方法必须调用 pygame.sprite.Sprite.__init__(self) pygame.mixer.init() # 音乐模块初始化 pygame.mixer.music.load('./feiji/bg2.ogg') #载入背景音乐 pygame.mixer.music.set_volume(0.5) # 声音大小,0.5表示一半大小的声音 self.__bomb = pygame.mixer.Sound('./feiji/bomb.wav') # 背景音乐 def playBackgroundMusic(self): pygame.mixer.music.play(-1) # 开始播放音乐,数字表示播放次数,-1表示循环播放 # 爆炸音乐 def playBombSound(self): self.__bomb.play() class Manager(object): #对应图片的窗口大小 bg_size = (512,768) #玩家生命数 life_num = 3 #生成敌方飞机的定时器 create_enemy_id = 10 #游戏结束定时器 create_game_over_id = 11 #游戏结束标志 gameover = False #倒计时数 over_time = 3 #boss最大数量 boss_num = 10 # 是否存在boss have_boss = False #初始化击败敌方飞机数 defeat_num = 0 def __init__(self): pygame.init() # 创建一个窗口 self.screen = pygame.display.set_mode(Manager.bg_size) # 生成音乐对象 self.gamesound = GameSound() # 己方飞机精灵组 self.players = pygame.sprite.Group() # 敌方飞机精灵组 self.enemyplayers = pygame.sprite.Group() # 敌方炸弹精灵组 self.bombshells = pygame.sprite.Group() # 创建一个背景图片 self.background = pygame.image.load(r"./feiji/background.png") #创建一个可移动地图 ,随机取一种地图, self.move_background_num = random.randint(1,5) self.move_background=GameBackground(self.screen,self.move_background_num) def player(self): # 调用一个飞机对象 player = Player(self.screen) # 将该飞机对象增加到己方飞机精灵组中 self.players.add(player) def enemyplayer(self): # 调用一个敌方飞机对象 enemyplayer = Enemyplayer(self.screen,"./feiji/enemy0.png") # 将该飞机对象增加到己方飞机精灵组中 self.enemyplayers.add(enemyplayer) #增加多个敌机对象 def add_enemy(self): enemyplayer = Enemyplayer(self.screen,"./feiji/enemy0.png") enemyplayer.direciton_up = True x = random.randint(0,Manager.bg_size[0]) #敌机随机出现 enemyplayer.rect.topleft = (x,0) #如果敌机出现在窗口较左边,则敌机优先向右飞行 if x <= Manager.bg_size[0] / 2: enemyplayer.direciton = "right" #向敌机精灵组增加一个敌机精灵 self.enemyplayers.add(enemyplayer) #判断碰撞 def judge_bomb(self,player_bomb,enemy_bomb): delete_sprite = False if Manager.life_num == 1: delete_sprite = True # 参1:碰撞对象1 ;参2:碰撞对象2 ;参3:判断调出碰撞对象1还是2还是一起的爆炸图片 ; 参3:是否删除爆炸对象1 def judge(x1,x2,who,delete1): # 判断碰撞对象1(精灵组)与2(精灵组)的碰撞 iscollide = pygame.sprite.groupcollide(x1, x2, delete1, True) if iscollide and (who == "player" or who == "both"): Manager.life_num -= 1 if Manager.life_num == 0: # 游戏结束 Manager.gameover = True pygame.time.set_timer(Manager.create_game_over_id,1000) if iscollide: #取出爆炸对象1 items = list(iscollide.items())[0] x = items[0] if who == "player": # 传入爆炸位置,打开爆炸图片输出按钮 player_bomb.action(x.rect) elif who == "enemy": #x = items[1][0] # 传入敌方爆炸图片的位置 enemy_bomb.action(x.rect) # 敌方爆炸击败数加1 Manager.defeat_num += 1 # 爆炸的声音 elif who == "both": # 传入爆炸位置,打开爆炸图片输出按钮 player_bomb.action(x.rect) # 取出爆炸对象2 y = items[1][0] # 传入爆炸对象2的爆炸图片的位置 enemy_bomb.action(y.rect) # 敌方爆炸击败数加1 Manager.defeat_num += 1 # 爆炸删除子弹精灵组 # Enemyplayer.bullets.empty() #爆炸音乐 self.gamesound.playBombSound() # 判断玩家飞机(精灵组)与敌方子弹(精灵组)的碰撞 judge(self.players, Enemyplayer.bullets, "player", delete_sprite) # 判断玩家飞机(精灵组)与敌方炸弹(精灵组)的碰撞 judge(self.players, self.bombshells, "player", delete_sprite) # 判断敌方飞机(精灵组)与我方子弹(精灵组)的碰撞 judge(self.enemyplayers, Player.bullets, "enemy", True) # 判断玩家飞机(精灵组)与敌方飞机(精灵组)的碰撞 judge(self.players, self.enemyplayers, "both", delete_sprite) #召唤boss def add_boss(self): enemy_boss_player = Enemyplayer(self.screen,"./feiji/enemy1.png") enemy_boss_player.bullet_frequency *= 2 enemy_boss_player.bullet_image ='./feiji/bullet2.png' self.enemyplayers.add(enemy_boss_player) # 绘制文字 rgb 红绿蓝 0 - 255 # 参1要绘制的文字 参2 x轴坐标 参3y轴坐标 参4文字大小 参5 文字颜色 参6 背景颜色 def drawText(self, text, x, y, textHeight = 30, fontColor = (255, 255, 255), backgroudColor = None): # 通过字体文件获得字体对象 参数1 字体文件 参数2 字体大小 font_obj = pygame.font.Font('./feiji/baddf.ttf', textHeight) # 1文字 2是否抗锯齿 3文字颜色 4背景颜色 text_obj = font_obj.render(text, True, fontColor, backgroudColor) # 配置要显示的文字 # 获得要显示的对象的rect text_rect = text_obj.get_rect() # 设置显示对象的坐标 text_rect.topleft = (x, y) # 绘制字 到指定区域 参1是文字对象 参2 矩形对象 self.screen.blit(text_obj, text_rect) def show_over_text(self): # 游戏结束 倒计时后重新开始 self.drawText('gameover %d' % Manager.over_time, 100, Manager.bg_size[1] / 2, textHeight=50, fontColor=[255, 0, 0]) #显示击败敌机数 def show_defeatnum_text(self): # 显示击败敌机数 self.drawText('击败敌机数: %d' % Manager.defeat_num, Manager.bg_size[0]-150, 0, textHeight=20, fontColor=[255, 0, 0]) # 显示剩余生命数 self.drawText('剩余生命数: %d' % Manager.life_num, Manager.bg_size[0] - 150, 20, textHeight=20, fontColor=[255, 0, 0]) def game_over(self): # 结束后倒计时 Manager.over_time -= 1 self.show_over_text() if Manager.over_time == 0: # 倒计时结束后游戏重新开始,相应变量返回初始化 Manager.over_time = 3 Manager.gameover = False self.game_start() def game_start(self): # 重新开始游戏,有些类属性要清空 # 击败敌机数回 0 Manager.defeat_num = 0 # 生命数数回 3 Manager.life_num = 3 #boss按钮恢复 Manager.have_boss = False #清空飞机类属性的子弹精灵组 Player.bullets.empty() # 清空敌方飞机类属性的子弹精灵组 Enemyplayer.bullets.empty() #重新运行游戏 manager = Manager() manager.main() def main(self): # 播放背景音乐 self.gamesound.playBackgroundMusic() # 增加一个己方飞机对象 self.player() # 增加一个敌方飞机对象 self.enemyplayer() # 开启生成敌方飞机定时器 pygame.time.set_timer(Manager.create_enemy_id, 2000) # 初始化一个己方飞机爆炸对象 player_bomb = Bomb(self.screen, 'player') # 初始化一个敌机爆炸的对象 enemy_bomb = Bomb(self.screen, 'enemy') while True: # 调用地图移动方法 self.move_background.move() # 向窗口不断添加背景图 self.move_background.draw() # 窗口显示击败敌机数 self.show_defeatnum_text() # 击败敌机数50时,召唤boss if Manager.defeat_num == 10 and Manager.have_boss == False: self.add_boss() Manager.have_boss = True # 随机增加炸弹,平均每十秒增加一个炸弹 if random.randint(0, 1000) == 1: bombshell = Bombshell(self.screen) # 在窗口最上方左右之间随机出现 bombshell.rect.topleft = (random.randint(0, Manager.bg_size[0]), -103) self.bombshells.add(bombshell) # 对应飞机类里的update方法 self.players.update() self.enemyplayers.update() # 不断显示敌方子弹,此为类方法 Enemyplayer.bullets.update() # 显示炸弹 self.bombshells.update() #调用爆炸对象调出爆炸图片 player_bomb.draw() enemy_bomb.draw() if self.players.sprites(): #调用判断碰撞方法 self.judge_bomb(player_bomb,enemy_bomb) #游戏结束播放倒计时文字 if Manager.gameover: self.show_over_text() # 不断更新窗口 pygame.display.update() # 遍历所有的事件、 for event in pygame.event.get(): # 判断事件类型如果是pygame的退出 if event.type == QUIT: # 执行pygame退出 pygame.quit() # python程序的退出 exit() elif event.type == Manager.create_enemy_id: # 创建一个敌机 self.add_enemy() elif event.type == Manager.create_game_over_id: if Manager.gameover: #游戏结束 self.game_over() time.sleep(0.01) if __name__ == "__main__": manager = Manager() manager.main()
三、运行结果: