import math
import os
import pygame

# from pygame.locals import *
import random
class Tools:#工具类
    @classmethod
    def getSample(cls,startNum,step=46,count=1):#startNum开始间隔46单位总共抽取count个元素的列表
        result=[]
        for i in range(count):
            result.append(startNum+i*46+random.randint(1,10))
        return result
    @classmethod
    def loadImg(cls,imgFile):#添加照片
        return pygame.image.load(imgFile)

    @classmethod
    def getBgImgs(cls,_type="开头照片"):#获取介绍图片列表
        imgs=cls.readGifs(_type)
        result=[cls.loadImg(img) for img in imgs]
        return result



    @classmethod
    def isHasRes(cls):#判断此游戏所欲要的资源文件是否在
        holderFileDic={"img":["bg.png","bullet.png","enemy2.png","player.png","ufo.png"],"wav":["bg.wav","exp.wav","laser.wav"]} #对应的目录和里面的资源
        for holder,fileList in holderFileDic.items():
            for file in fileList:
                resPath=cls.getRes(file,holder) #获取对应的目录和文件
                if not os.path.exists(resPath):#判断是否存在
                    return False
        return True

    @classmethod
    def distance(cls,bCoord, eCoord):#计算子弹和敌人飞船的距离
        """
        bCoord:子弹坐标
        eCoord:敌人飞船坐标
        """
        a = bCoord[0] - eCoord[0]
        b = bCoord[1] - eCoord[1]
        return math.sqrt(a * a + b * b)  # 开根号
    @classmethod
    def getRes(cls,fileName="player.png",fileType="img"):#根目录res中返回响应资源的绝对路径
        path=os.path.join(os.getcwd(),"res")
        if fileType=="img":#图片
            return os.path.join(path,"img",fileName)
        elif fileType=="wav":#声音
            return os.path.join(path,"wav",fileName)

    @classmethod
    def readGifs(cls, gifFiles="无人机"):#读取gif的帧图片返回列表
        path = os.path.join(os.getcwd(), "res")
        path = os.path.join(path, "img", gifFiles)
        _list=[]
        for root, dirs, files in os.walk(path):
            for file in files:
                _list.append(file)

            _list=[f"{path}\{index+1}.png" for index in range(len(_list))]
        return _list
    @classmethod
    def setImgScale(cls,img,width=0,height=0):#调整图片大小
        return pygame.transform.scale(img,(width,height))



class DATA:#游戏中的常量
    width=1200 #游戏宽度
    height=700 #游戏高度
    overFont = 'SimSun'#游戏结束时候的提示字体,宋体显示
    overFontSize=64
    overColor=(255,255,255) #结束提示语字体颜色
    scoreFont = 'SimSun' #分数显示字体
    scoreColor=(255,255,0) #分数字体颜色
    scoreFontSize=32
    title="保卫家园"
    authorText="作者：叶城县第三中学 努尔阿力木,指导老师：西尔艾力·库都斯"  #作者信息

class Base(pygame.sprite.Sprite):#基类
    def __init__(self,imgs,step=0, screenW=0, screenH=0,X=0,Y=0,angle=90,parent=None):
        super(Base, self).__init__()
        self.img = self.loadImg(imgs)
        self.Y = Y
        self.X = X
        self.step = step
        self.screenW = screenW
        self.screenH = screenH
        self.angle = angle
        self.parent=parent
        self.size=(0,0)
        self.fps=1  #帧的切换速度
        self.isHit=False #是否被击中
    def getRect(self):#获取矩形信息，坐标是左上角的坐标
        return pygame.Rect(self.X,self.Y,self.img.get_rect().width,self.img.get_rect().height)

    def loadImg(self,imgs):#加载图片
        self.curIndex=0 #当前显示的图片索引
        if isinstance(imgs,list):#动画
            self.gifs=[pygame.image.load(img) for img in imgs]
        else:
            self.gifs=[pygame.image.load(imgs)]

        return self.gifs[self.curIndex]
    def getRadius(self):#获取自己得边框外接圆得半径

        return max(self.size[0],self.size[1])
    def move(self):
        pass
    def changeSize(self,width=100,height=100):#更改角色大小
        self.img=Tools.setImgScale(self.img,width,height)
    def getCenterCoord(self):#获取图像中心坐标
        return self.getRect().center

        # return (self.X+self.size[0]/2,self.Y+self.size[1]/2)

    def getCoord(self):#获取位置
        return (self.X,self.Y)
    def update(self,scaleW=50,scaleH=50,isDis=False,startScale=0.4):#更新背景图片，达到动画效果
        Y=self.Y
        if self.curIndex < len(self.gifs)-1:
            self.curIndex = self.curIndex +self.fps
        else:
            self.curIndex = 0
        if isDis:
            scale=startScale+Y/self.screenH if Y>0 else 0.4 #缩放比例
        else:
            scale=1

        self.img=self.gifs[math.floor(self.curIndex)]
        self.size=(scaleW*scale,scaleH*scale)
        self.changeSize(scaleW*scale,scaleH*scale)
        self.parent.screen.blit(self.img, self.getCoord())


class Bullet(Base):#子弹类
    def __init__(self, img, step=0, screenW=0, screenH=0, X=0, Y=0, angle=90,parent=None,direction="top"):

        super().__init__(img, step, screenW, screenH, X, Y, angle,parent)
        self.direction=direction

    def setCurCoord(self):#子弹曲线走
        speed =0.1

        # 子弹运动的角度和速度
        velocity_x = speed * math.cos(math.radians(self.angle))
        velocity_y = -speed * math.sin(math.radians(self.angle))
        gravity = 0.1 #重力

        self.X += velocity_x
        velocity_y += gravity
        self.Y += velocity_y
    def hit(self): #子弹击中
        global score
        for e in self.parent.enemies:
            eRect=e.getRect()
            if (self.getRect().colliderect(eRect)):#
                e.explode()
                self.parent.enemies.remove(e)
                e.isHit=True
                self.parent.score += 1
                return True
        return False


    def move(self):#玩家移动
        if self.direction=="top":#往上射击
            self.Y -= self.step
        elif self.direction=="down":
            self.Y += self.step
        elif self.direction=="left":
            self.X -= self.step
        elif self.direction=="right":#往右射击
            self.X += self.step
        if self in self.parent.bullets:
            if self.Y < 0 or self.Y > DATA.height or self.X < 0 or self.X > DATA.width:
                self.parent.bullets.remove(self)

class Enemy(Base):#敌人类
    exGifs = None
    def __init__(self, img,step=1, screenW=0, screenH=0, X=0,Y=0,angle=90,parent=None):
        super().__init__(img, step, screenW, screenH, X, Y, angle,parent)
        self.Y=random.randint(-300,-30)
        self.step=random.uniform(0.05,0.15)
        # self.img=Tools.setImgScale(self.img,50,50)

        # self.exGifs =None #爆炸的图片先加载
        # self.step=0.1

    def move(self,isUp=True):#玩家移动
        if  not isUp:#往下开火
            self.step=-self.step
        self.Y += self.step
        self.isCollide()
        # 防止飞机出界
        if self.Y >self.screenH-40 :
            self.parent.isOver=True
            # self.Y=random.randint(-300,-30)
            # self.X = random.randint(0, self.screenW - 60)

    def isCollide(self):  # 判断是否与无人机碰撞

        playerRect=self.parent.player.getRect()
        rect=self.getRect()
        cord1=playerRect.center
        coord2=rect.center
        dis=Tools.distance(cord1,coord2)
        if dis<min(rect.width,rect.height)/2+min(playerRect.width,playerRect.height)/2-20:
        # if self.getRect().colliderect(playerRect):
            self.parent.isOver = True
            self.parent.isOver=True

    def reset(self):#初始位置
        self.X = random.randint(0, self.screenW - 60)
        self.Y = random.randint(-500,-30)
    def explode(self):#被击中后爆炸
        curIndex=0
        if curIndex < len(self.exGifs)-1:
            curIndex = self.curIndex +1
        else:
            curIndex = 0
        img=self.exGifs[math.floor(curIndex)]
        img=Tools.setImgScale(img,100,100)
        self.parent.screen.blit(img,self.getCoord())





class Player(Base):#玩家类
    def __init__(self, img, step=0, screenW=0, screenH=0,X=0,Y=0,angle=90,parent=None):
        super().__init__(img, step, screenW, screenH, X, Y, angle,parent)
        self.X = random.randint(10, screenW - 60)
        self.Y = screenH-random.randint(80,200)
        self.Hdirection=True #水平方向
        self.step=0.1
    def move(self):#玩家移动
        # print("plyer",self.getCoord())
        if self.Hdirection:
            self.X += self.step
            # 防止飞机出界
            if self.X >self.screenW-100 :
                self.X = self.screenW-100
            if self.X < 0:
                self.X = 0
        else:
            self.Y += self.step
            # 防止飞机出界
            if self.Y > self.screenH - 100:
                self.Y = self.screenH - 100
            if self.Y <0:
                self.Y =0

        self.getCenterCoord()

class Button: #按钮类
    def __init__(self, x, y, width, height, text, color=None,textColor=None):#按钮属性
        self.rect = pygame.Rect(x, y, width, height)#创建矩形
        self.text = text
        self.color = color
        self.textColor=textColor #字体颜色

    def draw(self, game,rect=None,y=400,offsetX=0):#在主类中画出按钮
        self.rect=pygame.Rect((DATA.width-rect.width)/2+offsetX,y,self.rect.width,self.rect.height)
        pygame.draw.rect(game.screen, self.color, self.rect)
        font = pygame.font.SysFont(DATA.scoreFont, 20)
        textSurface = font.render(u"{}".format(self.text), True,self.textColor)
        textRect = textSurface.get_rect(center=self.rect.center)
        game.screen.blit(textSurface, textRect)

class Game:#游戏主类
    enemies = [] #所有敌人
    bullets=[] #所有子弹
    score=0
    isOver=False #是否游戏结束
    isDownShot=False
    isLeftShot=False #向左侧射击
    isRightShot=False
    isTopShot=False
    isStart=False #游戏开始
    flag=False
    def __init__(self):#初始话
        pygame.init()
        self.screen=pygame.display.set_mode((DATA.width,DATA.height))
        pygame.display.set_caption(DATA.title)
        icon = pygame.image.load(Tools.getRes("ufo.png"))
        pygame.display.set_icon(icon)
        self.bgImg = pygame.image.load(Tools.getRes("大海.png"))
        self.runnig=True
        self.restartBtn=Button(420, 400, 100, 50, "重新开始",(128,128,0),(255,255,255)) #重新开始按钮
        # self.tipsBtn=Button(400, 330, 300, 50, "开始任务",(128,128,0),(255,255,255)) #提示按钮
        self.quitBtn=Button(560, 400, 100, 50, "退出游戏", (128,0,0),(255,215,0)) #退出按钮

        self.bgImgs = Tools.getBgImgs()
        self.FontImgs = Tools.getBgImgs("文本介绍")
        # self.bgFontImgs = Tools.setImgScale(bgImg1, DATA.width, DATA.height)

    def addScreen(self,imgName="bg.png",coord=(0,0)):#图片添加到窗口中coord位置
        self.screen.blit(pygame.image.load(imgName),coord)
    def addBgSound(self):
        # 添加背景音效
        pygame.mixer.music.load(Tools.getRes("bg.wav","wav"))
        pygame.mixer.music.play(-1)  # 单曲循环
    def start(self):#开始
        if Tools.isHasRes() and self.isStart:
            self.baoSound = pygame.mixer.Sound(Tools.getRes("exp.wav","wav")) #爆炸声
            self.addBgSound()
            self.addPlayer()
            self.addEnemy()


    def addPlayer(self):#添加玩家
        self.player=Player(img=Tools.readGifs("无人机"),screenW=DATA.width,screenH=DATA.height,parent=self)
    def addEnemy(self):#添加敌人
        Enemy.exGifs=[pygame.image.load(img) for img in Tools.readGifs("爆炸")]

        count=random.randint(15,20) #随机确定敌人数量
        Xlist=Tools.getSample(random.randint(0,80),random.randint(46,80),count) #敌人横坐标列表
        Xlist=[item for item in Xlist if item<DATA.width-46]
        for X in Xlist:
            self.enemies.append(Enemy(img=Tools.getRes("enemy2.png"),screenW=DATA.width,screenH=DATA.height,X=X,parent=self))
    def addBullet(self):#添加子弹
        if not self.isOver:#游戏没结束
            X=self.player.getCenterCoord()[0]
            Y=self.player.getCenterCoord()[1]
            # print(X,Y)
            #子弹出来得位置
            if self.isDownShot:
                Y = Y+self.player.size[1]/2+4
                direction="down"
            elif self.isLeftShot:
                X=X-self.player.size[0]/2+2
                direction = "left"
            elif self.isRightShot:
                X=X+self.player.size[0]/2+2
                direction = "right"
            else:
                Y=Y-self.player.size[1]/2+4
                direction = "top"
            self.bullets.append(Bullet(Tools.getRes("bullet.png"),2,DATA.width,DATA.height,X=X,Y=Y,parent=self,direction=direction))
    def showBullet(self):#显示字典
        for b in self.bullets:
            b.update(20,20,isDis=True,startScale=0.2)
            flag=b.hit()
            if flag:  # 看看是否击中了敌人
                self.bullets.remove(b)
                self.baoSound.play()
            b.move()
    def addDoBtn(self,rect=None,offsetX=100,y=350):
        text = u"准备好接受任务了吗！".format(self.score)
        font = pygame.font.SysFont(DATA.overFont, DATA.overFontSize)
        render = font.render(text, True, (255,255,0))
        rect = render.get_rect()
        self.screen.blit(render, ((DATA.width - rect.width) / 2, 350))
        self.restartBtn.draw(self, rect, offsetX=100, y=450)
        self.quitBtn.draw(self, rect, offsetX=300, y=450)
        # self.restartBtn.draw(self, rect, offsetX=offsetX, y=y)
        # self.quitBtn.draw(self, rect, offsetX=offsetX, y=y)

    def showScore(self):#显示分数
        text = "分数: {}".format(self.score)
        # pygame.font.init() #初始化字体
        # font=pygame.font.Font(DATA.scoreFont,DATA.scoreFontSize)
        font=pygame.font.SysFont(DATA.scoreFont,DATA.scoreFontSize)
        score_render = font.render(u"{}".format(text), True,DATA.scoreColor)
        self.screen.blit(score_render, (10, 10))

    def initDirection(self):#方向初始化
        self.isLeftShot=False
        self.isRightShot=False
        self.isTopShot=False
        self.isDownShot=False
    def clearScreen(self):#清空屏幕
        pygame.mixer.music.stop()  # 单曲循环
        self.bullets.clear()
        self.enemies.clear()  # 清空敌人



    def checkIsOver(self):#判断是否结束
        if self.isOver:
            text = u"     你输了！    ".format(self.score)
            # text = u"恭喜，任务完成了！".format(self.score)

            if self.score>=50:
                text = u"恭喜，任务完成了！".format(self.score)
            font = pygame.font.SysFont(DATA.overFont, DATA.overFontSize)
            render = font.render(text, True, DATA.overColor)
            rect=render.get_rect()
            game.restartBtn.text = "重新开始"
            self.screen.blit(render, ((DATA.width-rect.width)/2,250))
            self.restartBtn.draw(self,rect,offsetX=100,y=350)
            self.quitBtn.draw(self,rect,offsetX=300,y=350)
            '''游戏结束时下面显示作者和指导老师信息'''
            authFont = pygame.font.SysFont(DATA.overFont, 20)
            authRender = authFont.render(DATA.authorText, True, (0,0,0))
            rect = authRender.get_rect()
            self.screen.blit(authRender, ((DATA.width - rect.width) / 2, DATA.height-50))
            # self.screen.blit(authRender, (100, 560))
            self.clearScreen()
    def addIntroduce(self,index=0):#添加介绍
        bgImg=self.bgImgs[index]
        bgImg = Tools.setImgScale(bgImg, DATA.width, DATA.height)
        self.screen.blit(bgImg,(0,0))
    def getRect(self):
        return self.screen.get_rect()

def proEnemys(game):
    for enemy in game.enemies:
        enemy.update(80, 80, True, startScale=0.3)
        enemy.move()
        if enemy.isHit:
            game.enemies.remove(enemy)
            curIndex = 0
            if curIndex < len(game.exGifs) - 1:
                curIndex = curIndex + 1
            else:
                curIndex = 0
            img = game.exGifs[math.floor(curIndex)]  # 爆炸效果
            img = Tools.setImgScale(img, 10, 10)
            game.screen.blit(img, enemy.getCoord())
def proEvents(game):#处理事件
    for event in pygame.event.get():
        # game.initDirection()
        if event.type == pygame.QUIT:
            game.runnig = False
        # 通过键盘事件控制飞机的移动
        if event.type == pygame.KEYDOWN:  # 按下就移动
            if event.key == pygame.K_RIGHT:
                game.player.step = 2
                game.player.Hdirection = True

            elif event.key == pygame.K_LEFT:
                game.player.step = -2
                game.player.Hdirection = True

            elif event.key == pygame.K_DOWN:
                game.player.step = 2
                game.player.Hdirection = False  # 垂直飞
            elif event.key == pygame.K_UP:
                game.player.step = -2
                game.player.Hdirection = False

            elif event.key == pygame.K_SPACE:
                game.isTopShot = True
                game.addBullet()  # 添加子弹
                game.isLeftShot = False
                game.isRightShot = False
                game.isDownShot = False

                # 创建一颗子弹
            elif event.key == pygame.K_RETURN:  # 点击ALT
                game.isDownShot = True  # 按enter向下开火
                game.addBullet()  # 添加子弹
                game.isLeftShot = False
                game.isRightShot = False
                game.isTopShot = False

            elif event.key == pygame.K_n:  # 向左开火
                game.isLeftShot = True  # 按enter向下开火
                game.addBullet()  # 添加子弹
                game.isRightShot = False
                game.isTopShot = False
                game.isDownShot = False
            elif event.key == pygame.K_m:  # 向右开火
                game.isRightShot = True  # 按enter向下开火
                game.addBullet()  # 添加子弹
                game.isLeftShot = False
                game.isTopShot = False
                game.isDownShot = False

        elif event.type == pygame.MOUSEBUTTONDOWN:  # 判断是否点击按钮
            if game.restartBtn.rect.collidepoint(event.pos):  # 点击矩形区域
                game.start()
                game.isOver = False
                game.score = 0
                game.isStart=True
                game.start()

            elif game.quitBtn.rect.collidepoint(event.pos):  # 退出按钮被点击
                game.runnig = False
        elif event.type == pygame.KEYUP:  # 抬起来就不动
            game.player.step = 0



if __name__ == '__main__':
    game=Game()
    game.start()
    gifs=Tools.readGifs()
    lastTime = pygame.time.get_ticks()
    bgImg=Tools.loadImg(Tools.getRes("bg1.png"))
    bgImg=Tools.setImgScale(bgImg,DATA.width,DATA.height)

    rect=game.getRect() #屏幕长方形
    index=0
    while game.runnig:

        try:
            proEvents(game)
            if game.flag:
                rect=pygame.Rect(DATA.width-300,DATA.height/2+100,300,100)
                game.addDoBtn(rect)
            pygame.display.flip()  # 全部更新
        except:
            continue
        if not game.isStart:
            if pygame.time.get_ticks() - lastTime >= 2000:
                lastTime=pygame.time.get_ticks()
                if index + 1 < len(game.bgImgs):
                    index += 1
                else:
                    game.flag=True
                    game.restartBtn.text="接受任务"
                    # game.isStart=True
                    # game.start()
                    # game.addDoBtn()
                    # game.doBtn.draw(game, pygame.Rect(100,100,100,40))
            game.addIntroduce(index)
            continue
        game.flag=False
        game.screen.blit(bgImg, (0, 0))  # 添加背景图片
        proEnemys(game)
        if not game.isOver:#游戏没有结束
            game.player.update(120,120,startScale=0.4,isDis=True)
            game.player.move()
            game.showBullet()
        game.checkIsOver()
        game.showScore()  # 显示分数
        if len(game.enemies)<5 and not game.isOver: #敌人少了就添加敌人
            game.addEnemy()
        # pygame.display.update()
        if game.score>=50:
            game.isOver=True










