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