""" 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()