pygame泡泡坦克大战_射击游戏

""" pygame泡泡坦克大战.py 在游戏中用鼠标操作我方坦克射击彩色泡泡,打击敌方坦克,有三叉泡泡道具,连发道具,生命道具。
NPC坦克会时不时的瞄准我方坦克进行攻击,游戏可是有一定的难度哦,不过有了三叉和连发道具后就能所向披靡了。
本程序相对于前一个本版主要改动的内容为NPCTank增加了Shell属性,Tank的发射方法增加了Shell参数。各个类已经单独列为模块。
本程序的前身是李兴球先生用scratch2.0制作的泡泡坦克大战。

"""
__author__ = "李兴球"
__date__ = "2018年12月左右"

import os,math
import pygame
from pygame.locals import *
from random import randint,choice
from prop import Prop              # 从道具模块导入道具类
from explosion import Explosion    # 从爆炸模块导入爆炸类          
from shell import Shell            # 从炮弹模块导入炮弹类
from npctank import NPCTank        # 从npctank导入NPCTank类,敌方AI坦克
from tank import Tank              # 坦克模块导入Tank类,这是我方坦克
        
def collision_check():
    global npc_dead_amounts
    "玩家炮弹组和npc的碰撞检测"
    sprite_dict = pygame.sprite.groupcollide(group_player_shell,group_npc,True,True) # 返回的是一个字典
    if sprite_dict:  # 返回的可能是这样:{<Shell sprite(in 0 groups)>: [<NPCTank sprite(in 0 groups)>, <NPCTank sprite(in 0 groups)>]}                                                               #  有可能一次击中多个npc
        #print(sprite_dict)
        npc_dead_amounts += len(sprite_dict.values())                               # 统计阵亡的坦克数量
        hitted_tank = list(sprite_dict.values())[0]            
        position = hitted_tank[0].rect.center
        Explosion(explosion_images,position,group_explosion,screen,explosion_sound)                 # 生成爆炸效果实例对象
        
    "玩家和npc的碰撞检测"
    collided_npc_tank = pygame.sprite.spritecollideany(player,group_npc)            # 返回被撞到的npc
    if collided_npc_tank and not player.died():                                     # 注意防止连续碰撞
        player.die()
        collided_npc_tank.die()
        npc_dead_amounts += 1                                                       # 统计阵亡的坦克数量
        group_npc.remove(collided_npc_tank)
        position_npc = collided_npc_tank.rect.center
        Explosion(explosion_images,position_npc,group_explosion,screen,explosion_sound)
        
        position_player = player.rect.center
        Explosion(explosion_images,position_player,group_explosion,screen,explosion_sound)
        
    "玩家炮弹和npc炮弹碰撞检测,即我方炮弹可以抵销敌方炮弹"
    sprite_dict2 = pygame.sprite.groupcollide(group_player_shell,group_npc_shell,True,True) # 返回的是一个字典
    if sprite_dict2:                                              #字典的key是炮弹,只是利用它取个坐标
        shell = list(sprite_dict2.keys())[0]
        Explosion(explosion_images,shell.rect.center,group_explosion,screen,explosion_sound)
        
     
    "玩家和npc炮弹的碰撞检测"
    hit_shell = pygame.sprite.spritecollideany(player,group_npc_shell)            # 返回敌方的炮弹
    if hit_shell and not player.died():
         player.die()
         hit_shell.die()                                                          # 使用die方法                                                      
         position_shell = hit_shell.rect.center
         Explosion(explosion_images,position_shell,group_explosion,screen,explosion_sound)
        
         position_player = player.rect.center
         Explosion(explosion_images,position_player,group_explosion,screen,explosion_sound)

def playmusic(music):
    pygame.mixer.music.load(music)
    pygame.mixer.music.play(-1,0)
    
def display_cover(cover_image):
    """显示封面的函数"""
    clock = pygame.time.Clock()
    continue_game = True
    running = True
    while running:
        for event in pygame.event.get():
            if event.type == QUIT:
                continue_game = False
                running = False
                break
            if event.type == KEYDOWN:
                if event.key == K_SPACE:
                    running = False
                    break
        screen.blit(cover_image,(0,0))
        pygame.display.update()
        clock.tick(30)
            
    return continue_game


def main():
    running = True
    while running:
        for event in pygame.event.get():
            if event.type == QUIT:running = False
            if event.type == npc_produce_EVENT :
                # 定时产生NPC,把Shell类也传进去了,做为npc的一个属性,在它的shoot方法中生成炮弹会使用到
                NPCTank(npc_image,npc_shell_image,player,screen,group_npc,group_npc_shell,Shell)
            if event.type == prop_produce_EVENT:
                Prop(prop_images,group_prop,player,screen) # 定时产生道具
            if event.type == MOUSEBUTTONUP:
                if event.button == 1:
                    player.shoot(Shell)    # 发射炮弹
                    if player.three_fire > 0: player.three_fire -= 1
                    if player.three_fire == 0 and player.shell_image != shell_image:
                        player.shell_image =  shell_image                    
                
        if player.continue_fire > 0 :
            player.shoot(Shell)
            player.continue_fire -= 1
            if player.three_fire > 0: player.three_fire -= 1
            
        if player.three_fire > 0  and player.shell_image != three_shell_image: # 更换为三叉泡泡弹
            player.shell_image = three_shell_image        
             
        mousexy = pygame.mouse.get_pos()
        player.forward(mousexy)
        player.update() 
        group_player_shell.update()         # 玩家发射的炮弹组
        group_npc.update()                  # npc组
        group_npc_shell.update()            # npc炮弹组
        group_prop.update()                 # 道具组更新
        
        if player.invincible_time > 0:      # 这个值大于0,说明玩家坦克已阵亡,让它减小直到为0
            player.invincible_time -=1
            
        if player.invincible_time == 0:     # 等于0的时候才做碰撞检测
           collision_check()                # 碰撞检测         
            
        screen.fill((150,0,0))              # 重画背景色
        player.draw()                       # 重画玩家的坦克
        group_player_shell.draw(screen)     # 重画所有玩家发射的炮弹
        group_npc.draw(screen)              # 重画所有npc
        group_npc_shell.draw(screen)        # 重画所有npc发射的炮弹
        group_prop.draw(screen)             # 重画所有道具

        for bomb in  group_explosion:       # 这里不用group的draw方法,因为它要切换造型
            bomb.draw()        
        
        pygame.display.set_caption("生命数:" + str(player.lives) + ",敌方坦克阵亡数:" + str(npc_dead_amounts))
        pygame.display.update()        
        clock.tick(30)
        if npc_dead_amounts > 100:
            running = False         

    if npc_dead_amounts > 100:
        finish(pygame.image.load(fisnish_image))
    else:
        pygame.quit()

def finish(image):
    """显示结尾图形"""    
    clock = pygame.time.Clock()    
    running = True
    while running:
        for event in pygame.event.get():
            if event.type == QUIT or event.type == MOUSEBUTTONDOWN:                
                running = False
                break 
        screen.blit(image,(0,0))
        pygame.display.update()
        clock.tick(30)            
    pygame.quit()
    
    
if __name__ == "__main__":

    npc_dead_amounts = 0                                                         # 敌方坦克阵亡数量
    cover_image  = os.getcwd() + os.sep + "images" + os.sep  + "封面.png"
    fisnish_image  = os.getcwd() + os.sep + "images" + os.sep  + "finish.png"
    prop_images = [ "life.png","continuous_fire.png","three_fire.png"]           # 道具图片表
    prop_images = [ os.getcwd() + os.sep + "images" + os.sep + image for image in prop_images] 
    explosion_images = [ "explosion" + str(i) + ".png" for i in range(1,6)]
    explosion_images = [ os.getcwd() + os.sep + "explosion" + os.sep + image for image in explosion_images]
     
    npc_image = os.getcwd() + os.sep + "images" + os.sep + "绿坦克.png"
    shell_image = os.getcwd() + os.sep + "images" + os.sep + "ball-c.png"
    three_shell_image = os.getcwd() + os.sep + "images" + os.sep + "three_shell.png"
    npc_shell_image = os.getcwd() + os.sep + "images" + os.sep + "ball-a.png" 
    player_image = os.getcwd() + os.sep + "images" + os.sep + "蓝坦克.png"
    width,height = 960,720
    game_title = "泡泡坦克大战"
    
    pygame.init()
    screen = pygame.display.set_mode((width,height))
    pygame.display.set_caption(game_title)
    shell_image = pygame.image.load(shell_image).convert_alpha()                    # 泡泡弹
    three_shell_image = pygame.image.load(three_shell_image).convert_alpha()        # 三叉泡泡弹
    npc_shell_image = pygame.image.load(npc_shell_image).convert_alpha()
    explosion_images = [pygame.image.load(image).convert_alpha() for image in explosion_images]
    s = [ pygame.image.load(image).convert_alpha() for image in prop_images]        # 道具图层表
    prop_images = {}.fromkeys(['life','continue','three'])                          # 道具字典
    prop_images['life'] = s[0]
    prop_images['continue'] = s[1]
    prop_images['three'] = s[2]    

    group_player_shell = pygame.sprite.Group()          # 玩家炮弹组
    group_npc_shell = pygame.sprite.Group()             # NPC炮弹组
    group_npc = pygame.sprite.Group()                   # NPC组
    group_explosion = pygame.sprite.Group()             # 爆炸效果组
    group_prop = pygame.sprite.Group()                  # 道具组
    
    player = Tank(player_image,shell_image,screen,group_player_shell)
    clock = pygame.time.Clock()    
    
    npc_produce_EVENT = USEREVENT + 1                   # npc自动产生事件
    pygame.time.set_timer(npc_produce_EVENT,400)        # 每隔400毫秒产生一个npc

    prop_produce_EVENT = USEREVENT + 2                  # 道具自动产生事件
    pygame.time.set_timer(prop_produce_EVENT,10000)     # 每秒生成一个,到了屏幕最下面会自动消失

    explosion_sound = os.getcwd() + os.sep + "sound" + os.sep + "BOMB2.wav"
    explosion_sound = pygame.mixer.Sound(explosion_sound)
    "播放背景音乐"
    bgmusic = os.getcwd() + os.sep + "sound" + os.sep + "Protozoa.wav"
    playmusic(bgmusic)
    "准备增加显示封面的函数"
    if display_cover(pygame.image.load(cover_image)):
        main()
    else:
        pygame.quit()