""" takenoko.py """

import math
import pygame
import random
import sys
from pygame.locals import *

pygame.init()
pygame.key.set_repeat(5, 5)
SURFACE = pygame.display.set_mode((400, 300))
FPSCLOCK = pygame.time.Clock()
pygame.display.set_caption("TAKENOKO GARI")
sysfont = pygame.font.SysFont(None, 24)

#三角関数(sin, cos)数値リスト化
circle_x = [math.cos(math.radians(i)) for i in range(360)]
circle_y = [math.sin(math.radians(i)) for i in range(360)]

class MySprite(pygame.sprite.Sprite):
    """ スプライト設定 """
    def __init__(self, filename):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(filename)
        self.width = self.image.get_width()
        self.height = self.image.get_height()
        self.x = 0
        self.y = 0
        self.alpha = 255
        self.rect = Rect(self.x, self.y, self.width, self.height)
        
    #スプライト表示
    def locate(self, x=9999, y=9999):
        if x < 9999:
            self.x = x
        if y < 9999:
            self.y = y
        self.image.set_alpha(self.alpha)
        self.rect = Rect(self.x, self.y, self.width, self.height)
        SURFACE.blit(self.image, self.rect)

class Hand(MySprite):
    """手オブジェクト(MySpriteクラスから継承)"""
    def __init__(self):
        super().__init__("hand_open.gif")
        self.status = 1
        self.image_hand_open = pygame.image.load("hand_open.gif")
        self.image_hand_closed = pygame.image.load("hand_closed.gif")
        self.image_hand_damaged = pygame.image.load("hand_damaged.gif")
        
    #手閉じる
    def close(self):
        self.status = 2
        self.image = self.image_hand_closed
        
    #手開く
    def open(self):
        self.status = 1
        self.image = self.image_hand_open
        
    #ダメージ有り
    def damaged(self):
        self.status += 1
        if self.status >= 10 and self.status < 100:
            self.image = self.image_hand_damaged
        elif self.status >=100:
            self.status = 1
            self.image = self.image_hand_open

class Takenoko(MySprite):
    """たけのこオブジェクト(MySpriteクラスから継承)"""
    def __init__(self):
        super().__init__("takenoko_right.gif")
        self.type = 0
        self.direction = 0
        self.angle = 0
        self.status = 0
        self.radius = 0
        self.base_x = 0
        self.base_y = 0
        self.vx = 0
        self.vy = 0
        self.point = 0
        self.alpha = 0
        self.image_takenoko_green = pygame.image.load("takenoko_green.gif")
        self.image_takenoko_gold = pygame.image.load("takenoko_gold.gif")
        self.image_takenoko_pair_right = pygame.image.load("takenoko_pair_right.gif")
        self.image_takenoko_pair_left = pygame.image.load("takenoko_pair_left.gif")
        self.image_takenoko_right = pygame.image.load("takenoko_right.gif")
        self.image_takenoko_left = pygame.image.load("takenoko_left.gif")
        
    #たけのこ表示オン
    def on(self, takenoko_type, x, y, direction, angle, group):
        self.type = takenoko_type
        self.direction = direction
        self.angle = angle
        self.group = group
        if self.type == 1: #たけのこ単独(直線)
            self.status = 1
            self.x = x
            self.y = y
            self.vx = circle_x[self.angle]*5
            self.vy = circle_y[self.angle]*5
            self.point = 200
            self.alpha = 0
            self.image = self.image_takenoko_green
        elif self.type == 2: #たけのこ単独(直線、金のたけのこ)
            self.status = 150
            self.x = x
            self.y = y
            self.vx = circle_x[self.angle]*10
            self.vy = circle_y[self.angle]*10
            self.point = 5000
            self.alpha = 0
            self.image = self.image_takenoko_gold
        elif self.type == 3: #たけのこ単独(波)
            self.status = 1
            self.x = x
            self.base_y = y
            self.point = 500
            self.alpha = 255
            if self.direction == 0:
                self.image = self.image_takenoko_pair_right
            else:
                self.image = self.image_takenoko_pair_left
        elif self.type == 4: #たけのこ集団(回転)
            self.status = 1
            self.radius = 0
            self.base_x = x
            self.base_y = y
            self.point = 100
            self.alpha = 0
            if self.direction == 0:
                self.image = self.image_takenoko_right
            else:
                self.image = self.image_takenoko_left
                
    #たけのこ動作
    def move(self, hand_status, hand_x, hand_y):
        if self.type == 1 or self.type == 2: #たけのこ単独(直線)
            self.status += 1
            self.x += self.vx
            self.y += self.vy
            if self.x < 0:
                self.x = 0
                self.vx = -self.vx
            elif self.x > 350:
                self.x = 350
                self.vx = -self.vx
            elif self.y < 0:
                self.y = 0
                self.vy = -self.vy
            elif self.y > 250:
                self.y = 250
                self.vy = -self.vy
            if self.status > 0 and self.status < 200:
                self.alpha += 10
                if self.alpha > 255:
                    self.alpha  = 255
            elif self.status < 300:
                self.alpha -= 10
                if self.alpha < 0:
                    self.alpha = 0
                    self.status = 0
                    return(0, 0, 0, self.group)
        elif self.type == 3: #たけのこ単独(波)
            if self.direction == 0:
                self.x += 6
                if self.x > 400:
                    self.status = 0
                    return(0, 0, 0, self.group)
            else:
                self.x -= 6
                if self.x < -50:
                    self.status = 0
                    return(0, 0, 0, self.group)                    
            self.y = circle_y[self.angle]*100 + self.base_y
            self.angle += 7
            if self.angle >= 360:
                self.angle -= 360       
        elif self.type == 4: #たけのこ集団(回転)
            self.x = circle_x[self.angle]*self.radius + self.base_x
            self.y = circle_y[self.angle]*self.radius + self.base_y
            self.radius += 2
            if self.direction == 0: #反時計回り
                self.angle += 3
                if self.angle >= 360:
                    self.angle -= 360
            else: #時計回り
                self.angle -= 3
                if self.angle < 0:
                    self.angle += 360
            if self.status == 1:
                self.alpha += 10
                if self.alpha > 255:
                    self.alpha  = 255
            if self.radius > 300:
                self.status = 2
                self.alpha -= 10
                if self.alpha < 0:
                    self.alpha = 0
                    self.status = 0
                    return(0, 0, 0, self.group)
        if hand_status >= 2 and hand_status <= 4: #手づかみ→衝突処理
            if ((self.x - hand_x)**2 + (self.y - hand_y)**2) < 2000:
                self.status = 0
                self.alpha = 0
                return(self.point, self.x, self.y, self.group)
        return(0, 0, 0, self.group)

class Kamemushi(MySprite):
    """カメムシオブジェクト(MySpriteクラスから継承)"""
    def __init__(self):
        super().__init__("kamemushi_right.gif")
        self.status = 0
        self.angle = 0
        self.speed = 0
        self.vx = 0
        self.vy = 0
        self.alpha = 0
        self.image_kamemushi_right = pygame.image.load("kamemushi_right.gif")
        self.image_kamemushi_left = pygame.image.load("kamemushi_left.gif")
        
    #カメムシ表示オン
    def on(self, x, y, hand_x, hand_y):
        self.status = 1
        self.angle = vector_to_angle(x, y, hand_x, hand_y)
        self.speed = 2
        self.x = x
        self.y = y
        self.alpha = 0
        self.image = self.image_kamemushi_right
        
    #カメムシ動作
    def move(self, hand_x, hand_y):
        self.alpha += 5
        if self.alpha > 255:
            self.alpha  = 255
        (self.vx, self.vy) = angle_to_vectr(self.angle)
        self.x += self.vx * self.speed
        self.y += self.vy * self.speed
        if self.vx > 0:
            self.image = self.image_kamemushi_right
        elif self.vx <0:
            self.image = self.image_kamemushi_left
        a = self.angle - vector_to_angle(self.x, self.y, hand_x, hand_y) #カメムシ動作方向と手の向き比較
        if a > 180:
            a -= 360
        if a < -180:
            a += 360        
        if a > 0:
            self.angle -= 3
            if self.angle < 0:
                self.angle += 360
        elif a < 0:
            self.angle += 3
            if self.angle > 359:
                self.angle -= 360
        if self.alpha == 255 and ((self.x - hand_x)**2 + (self.y - hand_y)**2) < 800: #衝突判定処理
            self.status = 0
            self.alpha = 0
            return(1) #返り値(衝突あり)
        return(0)

class Kamakiri(MySprite):
    """カマキリオブジェクト(MySpriteクラスから継承)"""
    def __init__(self):
        super().__init__("kamakiri_right.gif")
        self.status = 0
        self.angle = 0
        self.direction = 0
        self.speed = 0
        self.vx = 0
        self.vy = 0
        self.alpha = 255
        self.image_kamakiri_right = pygame.image.load("kamakiri_right.gif")
        self.image_kamakiri_left = pygame.image.load("kamakiri_left.gif")
        
    #カマキリ表示オン
    def on(self):
        self.status = 1
        self.direction = random.randint(0, 1)
        self.x = random.randint(0, 350)
        if self.direction == 0:
            self.angle = random.randint(250, 290)
            self.y = -50
        else:
            self.angle = random.randint(70, 110)
            self.y = 300
        self.speed = 2
        self.alpha = 255
        (self.vx, self.vy) = angle_to_vectr(self.angle)
        self.vx *= self.speed
        self.vy *= self.speed
        if self.vx >= 0:
            self.image = self.image_kamakiri_right
        else:
            self.image = self.image_kamakiri_left
        
    #カマキリ動作
    def move(self, hand_x, hand_y):
        self.x += self.vx
        self.y += self.vy
        if hand_x > self.x:
            self.vx += 0.2
            if self.vx > 5:
                self.vx = 5
        else:
            self.vx -= 0.2
            if self.vx < -5:
                self.vx = -5
        if self.x < 0:
            self.x = 0
            self.vx = -self.vx
        elif self.x > 350:
            self.x = 350
            self.vx = -self.vx
        if self.y < -50:
            self.status = 0
            self.alpha = 0
        elif self.y > 300:
            self.status = 0
            self.alpha = 0
        if self.vx >= 0:
            self.image = self.image_kamakiri_right
        else:
            self.image = self.image_kamakiri_left
        if ((self.x - hand_x)**2 + (self.y - hand_y)**2) < 800: #衝突判定処理
            self.status = 0
            self.alpha = 0
            return(1) #返り値(衝突あり)
        return(0)
        
class Point:
    """得点表示オブジェクト"""
    def __init__(self):
        self.x = 0
        self.y = 0
        self.status = 0
        self.point = 0
        
    #得点表示オン        
    def on(self, x, y, point):
        self.x = x
        self.y = y + 15
        self.status = 255
        self.point = point
        
    #得点表示~消滅
    def indication(self):
        self.status -= 5
        if self.status > 100:
            if self.point < 2000:
                count_image = sysfont.render(
                    "{:^6}".format(self.point), True, (self.status, self.status, self.status))
                SURFACE.blit(count_image, (self.x, self.y))
            else:
                count_image = sysfont.render(
                    "{:^6}".format(self.point), True, (self.status, 0, 0))
                SURFACE.blit(count_image, (self.x, self.y))
        else:
            self.status = 0

def score_indication(score, best_score, counter):
    """ スコア表示 """
    count_image = sysfont.render(
        "Best Score: {}".format(best_score), True, (255, 255, 255))
    SURFACE.blit(count_image, (10, 2))
    count_image = sysfont.render(
        "Your Score: {}".format(score), True, (255, 255, 255))
    SURFACE.blit(count_image, (165, 2))
    second = 60-int(counter/30)
    if second == 0:
        font_color = (255, 0, 0)
    elif second <= 3:
        font_color = (255, 255, 0)
    else:
        font_color = (255, 255, 255)
    count_image = sysfont.render(
        "Timer: {}".format(second), True, font_color)
    SURFACE.blit(count_image, (320, 2))

def vector_to_angle(x1, y1, x2, y2):
    """ ベクトルの角度計算(x1,y1座標に対するx2,y2座標の角度) """
    r1 = math.degrees(math.atan2(-(y2-y1), x2-x1))
    if r1 < 0:
        r1 = 360 + r1
    r1 = int(r1)
    return(r1)

def angle_to_vectr(angle):
    """ 角度からベクトル計算 """
    vx = circle_x[angle]
    vy = -circle_y[angle]
    return(vx, vy)

def main():
    """ メインルーチン """
    #変数&オブジェクト初期設定(ループ前)
    best_score = 0
    score = 0
    counter = 0
    screen_flag = 0
    bestscore_flag = 0
    mousepos = []
    group_point = [0 for i in range(80)] #たけのこ集団別得点リスト
    hand = Hand() #手オブジェクト
    takenoko = [Takenoko() for i in range(80)] #たけのこオブジェクトリスト
    point_ind = [Point() for i in range(80)] #得点表示オブジェクトリスト
    kamemushi = Kamemushi() #カメムシオブジェクト
    kamakiri = Kamakiri() #カマキリオブジェクト

    #イメージ設定
    image_background = pygame.image.load("background_bamboo.jpg")
    image_title = pygame.image.load("title.gif")
    image_message_start = pygame.image.load("message_start.gif")
    image_gameover = pygame.image.load("gameover.gif")
    image_message_bestscore = pygame.image.load("message_bestscore.gif")

    #効果音
    sound_hand = pygame.mixer.Sound("hand.wav")
    sound_hand.set_volume(0.2)
    sound_catch = pygame.mixer.Sound("catch.wav")
    sound_catch.set_volume(0.2)
    sound_takenoko_circle = pygame.mixer.Sound("takenoko_circle.wav")
    sound_takenoko_circle.set_volume(0.03)
    sound_bonus = pygame.mixer.Sound("bonus.wav")
    sound_bonus.set_volume(0.5)
    sound_insect = pygame.mixer.Sound("insect.wav")
    sound_insect.set_volume(0.6)
    sound_damaged = pygame.mixer.Sound("damaged.wav")
    sound_damaged.set_volume(0.6)
    sound_beep = pygame.mixer.Sound("beep.wav")
    sound_beep.set_volume(0.3)
    sound_gameover = pygame.mixer.Sound("gameover.wav")
    sound_gameover.set_volume(0.6)
    sound_bestscore = pygame.mixer.Sound("bestscore.wav")
    sound_bestscore.set_volume(0.6)
    
    #BGM
    pygame.mixer.music.load("bgm.wav")
    pygame.mixer.music.set_volume(0.5)

    while True:

        #変数設定(タイトル)
        a = 0
        counter = 0
        screen_flag = 0

        #画面塗りつぶし(背景描写)
        SURFACE.blit(image_background,(0, 0), (0, (counter/6), 400, int(counter/6)+299))
        
        #タイトル&クレジット表示
        SURFACE.blit(image_title,(25,30))
        SURFACE.blit(image_message_start,(50,215))
        count_image = sysfont.render(
            "© 2017 KUNISAN.JP", True, (255, 255, 255))
        SURFACE.blit(count_image, (125, 270))

        #スコア表示
        score_indication(score, best_score, counter)

        #マウスカーソル表示
        pygame.mouse.set_visible(True)

        #ループ1 (タイトル画面)
        while screen_flag <= 1:
                   
            #ウィンドウ閉じるボタン&マウスボタン
            for event in pygame.event.get():
                if event.type == QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == MOUSEBUTTONDOWN:
                    if screen_flag == 0:
                        screen_flag = 1
                elif event.type == MOUSEBUTTONUP:
                    if screen_flag == 1:
                        screen_flag = 2

            #画面アップデート
            pygame.display.update()
            FPSCLOCK.tick(30)


        #変数設定(ゲーム)
        (a, b, c) = (0, 0, 0)
        (x, y) = (0, 0)
        (takenoko_x, takenoko_y, takenoko_direction) = (0, 0, 0)
        takenoko_counter = 0
        takenoko_group_counter = 0
        counter = 0
        score = 0
        bestscore_flag = 0
        point = 0
        point_x = 0
        point_y = 0
        kamemushi_x = 0
        kamemushi_y = 0
        group_number = 0
        point_ind_counter = 0
        hand.open()
        for i in range(len(takenoko)):
            takenoko[i].status = 0
        for i in range(len(group_point)):
            group_point[i] = 0
        for i in range(len(point_ind)):
            point_ind[i].status = 0
        kamemushi.status = 0
        kamakiri.status = 0

        #BGM再生
        pygame.mixer.music.play()

        #マウスカーソル非表示
        pygame.mouse.set_visible(False)
        
        #ループ2 (メインループ)
        while counter <= 1800:

            counter += 1

            #ウィンドウ閉じるボタン&マウスボタン
            for event in pygame.event.get():
                if event.type == QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == MOUSEBUTTONDOWN:
                    if hand.status < 10:
                        hand.close()
                        sound_hand.play()
                elif event.type == MOUSEBUTTONUP:
                    if hand.status < 10:
                        hand.open()

            #画面塗りつぶし(背景描写)
            SURFACE.blit(image_background,(0, 0), (0, (counter/6), 400, int(counter/6)+299))

            #たけのこ単独(直線)発生
            if random.randint(0, 50-int(counter/100)) == 0 and counter >= 30: #開始から1秒以降               
                takenoko_x = random.randint(0, 350)
                takenoko_y = random.randint(0, 250)
                takenoko_angle = random.randint(0, 359)
                if takenoko[takenoko_counter].status == 0 and ((x - takenoko_x)**2 + (y - takenoko_y)**2) > 5000:
                    if counter >= 1200 and random.randint(0, 19) == 0: #金のたけのこ出現条件(開始から40秒以降)
                        takenoko[takenoko_counter].on(2, takenoko_x, takenoko_y, 0, takenoko_angle, 0)
                    else:
                        takenoko[takenoko_counter].on(1, takenoko_x, takenoko_y, 0, takenoko_angle, 0)
                takenoko_counter += 1
                if takenoko_counter >= len(takenoko):
                    takenoko_counter = 0

            #たけのこ単独(波)発生
            if (counter % 200 == 0 or random.randint(0, 99) == 0) and counter >= 300: #開始から10秒以降               
                takenoko_direction = random.randint(0, 1)
                if takenoko_direction == 0:
                    takenoko_x = -50
                else:
                    takenoko_x = 400
                takenoko_y = random.randint(0, 50) + 100
                takenoko_angle = random.randint(0, 359)
                if takenoko[takenoko_counter].status == 0:
                    takenoko[takenoko_counter].on(3, takenoko_x, takenoko_y, takenoko_direction, takenoko_angle, 0)
                takenoko_counter += 1
                if takenoko_counter >= len(takenoko):
                    takenoko_counter = 0


            #たけのこ集団(回転)発生
            if random.randint(0,120-int(counter/20)) == 0 and counter >= 600: #開始から20秒以降               
                takenoko_x = random.randint(0, 350)
                takenoko_y = random.randint(0, 250)
                takenoko_direction = random.randint(0, 1)
                takenoko_group_counter += 1
                if takenoko_group_counter >= len(group_point):
                    takenoko_group_counter = 1
                for i in range(0, 359, 60):
                    if takenoko[takenoko_counter].status == 0 and ((x - takenoko_x)**2 + (y - takenoko_y)**2) > 5000:
                        sound_takenoko_circle.play()
                        takenoko[takenoko_counter].on(4, takenoko_x, takenoko_y, takenoko_direction, i, takenoko_group_counter)
                    takenoko_counter += 1
                    if takenoko_counter >= len(takenoko):
                        takenoko_counter = 0

            #たけのこ移動&当たり判定&表示        
            for i in range(len(takenoko)):
                if takenoko[i].status > 0:
                    (point,point_x,point_y,group_number) = takenoko[i].move(hand.status, x, y)
                    if point > 0:
                        sound_catch.play()
                        if group_number > 0: #たけのこ集団の場合の得点処理
                            group_point[group_number] += point
                            if group_point[group_number] >= 600:
                                sound_bonus.play()
                                group_point[group_number] = 2000
                            score += group_point[group_number]
                            point_ind[point_ind_counter].on(point_x, point_y, group_point[group_number])
                            point_ind_counter += 1
                        else: #たけのこ単独の場合の得点処理
                            score += point
                            if point >= 5000:
                                sound_bonus.play()
                            point_ind[point_ind_counter].on(point_x, point_y, point)
                            point_ind_counter += 1
                        if point_ind_counter >= len(point_ind):
                            point_ind_counter = 0
                    else: 
                        takenoko[i].locate()

            #手表示
            (x, y) = pygame.mouse.get_pos()
            (x, y) = (x-25, y-25)
            hand.locate(x,y)
            if hand.status >= 2 and hand.status < 10:
                hand.status += 1
                if hand.status > 5:
                    hand.status = 5
            elif hand.status >= 10:
                hand.damaged()

            #カメムシ発生
            if counter >= 1200 and counter <= 1230 and kamemushi.status == 0: #開始から40秒以降
                a = random.randint(0,350)
                b = random.randint(0,250)
                if ((x - a)**2 + (y - b)**2) > 25000:
                    sound_insect.play()
                    kamemushi.on(a, b, x, y)

            #カメムシ移動&表示
            if kamemushi.status > 0:
                a = kamemushi.move(x, y)
                if counter == 1560:
                    kamemushi.speed = 3
                if a == 1:
                    sound_damaged.play()
                    hand.status = 10
                else:
                    kamemushi.locate()

            #カマキリ発生
            if counter >= 1440 and random.randint(0,80) == 0 and kamakiri.status == 0: #開始から48秒以降
                sound_insect.play()
                kamakiri.on()

            #カマキリ移動&表示
            if kamakiri.status > 0:
                a = kamakiri.move(x, y)
                if a == 1:
                    sound_damaged.play()
                    hand.status = 10
                else:
                    kamakiri.locate()

            #得点表示
            for i in range(len(point_ind)):
                point_ind[i].indication()

            #スコア&タイマー表示
            if score > best_score:
                best_score = score
                bestscore_flag = 1
            if counter == 1710 or counter == 1740 or counter == 1770:
                sound_beep.play()
            score_indication(score, best_score, counter)

            #画面アップデート
            pygame.display.update()
            FPSCLOCK.tick(30)
            
            #BGM再生確認&リピート
            if pygame.mixer.music.get_busy() == 0:
                pygame.mixer.music.play()

        #変数設定(ゲームオーバー)
        a = 0
        counter = 0
        screen_flag = 0

        #BGM停止
        pygame.mixer.music.stop()
        sound_gameover.play()

        #ゲームオーバー表示
        SURFACE.blit(image_gameover,(100,75))

        #ループ3 (ゲームオーバー)
        while screen_flag <= 1:

            counter += 1
            if counter >= 180:
                screen_flag = 2
                   
            #ウィンドウ閉じるボタン&マウスボタン
            for event in pygame.event.get():
                if event.type == QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == MOUSEBUTTONDOWN:
                    if screen_flag == 0 and counter >= 90:
                        screen_flag = 1
                elif event.type == MOUSEBUTTONUP:
                    if screen_flag == 1:
                        screen_flag = 2

            if counter == 60 and bestscore_flag == 1:
                SURFACE.blit(image_message_bestscore,(50,215))
                sound_bestscore.play()

            #画面アップデート
            pygame.display.update()
            FPSCLOCK.tick(30)

if __name__ == '__main__':
    main()