import pygame import math from pygame.locals import * import numpy as np import random import os #サイズ設定 screen_size = np.array([560,600]) block_size = np.array([60,15]) ball_size = 10 #初期化 pygame.init() clock = pygame.time.Clock() #画面設定 surface = pygame.display.set_mode(screen_size) #ブロッククラス class Block(): def __init__(self, loc, typ): #ブロックの色 self.block_clr_list = [[0,0,0],[0,255,0],[255,140,0],[255,0,0],[135,17,238],[120,250,255],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[150,150,150]] #ブロックの形状、位置の設定 self.block = pygame.Rect(loc,block_size) #ブロックのタイプ self.typ = typ self.block_color = self.block_clr_list[self.typ] self.vs = np.array([1,0]) def attack(self, bomb=False): #衝突時の処理 if bomb and self.typ != 10: self.typ = 0 elif self.typ == 2: self.typ = 1 self.block_color = [255,255,0] elif not (self.typ in [0,10]):#!= 0: self.typ = 0 #ボールクラス class Ball(): def __init__(self, loc, vs): #設定 self.start = loc self.loc = loc self.vs = vs self.color = [255,255,255] def fall(self): #落ちた時の処理 self.color = [255,255,255] self.loc = self.start vabs = 8 angle = 90 + random.uniform(15,30) * random.sample([-1,1], k=1)[0] self.vs = np.array([math.cos(math.radians(angle)) * vabs, math.sin(math.radians(angle)) * vabs]) #バークラス class Bar(): def __init__(self, loc, size): #設定 self.loc = np.array(loc) self.size = np.array(size) self.bar = pygame.Rect(self.loc-(self.size/2), self.size) #ゲーム実行部分 def main(path): points = np.array([[ball_size,0],[-ball_size,0],[0,ball_size],[0,-ball_size]]) hoko = np.array([0,0,1,1]) #ボールの落下方向の設定 vabs = 8 angle = 90 + random.uniform(15,30) * random.sample([-1,1], k=1)[0] vs = np.array([math.cos(math.radians(angle)) * vabs, math.sin(math.radians(angle)) * vabs]) #ボールの設定 ball = (Ball([280,300], vs)) #デフォルトのマップ block_map = np.array([[1,1,1,1,1,1,1,1], [1,1,1,1,1,1,1,1], [2,1,1,1,1,1,1,2], [2,1,1,1,1,1,1,2], [1,5,1,1,1,1,1,1], [1,1,1,1,1,1,5,1], [1,1,1,1,1,1,1,1], [1,2,3,1,1,3,2,1], [1,1,4,1,1,4,1,1], [0,0,0,0,0,0,0,0], [1,1,2,1,1,2,1,1], [1,1,1,2,2,1,1,1]]) #0:無 #1:普通のブロック #2:硬化ブロック(2回当てないと消えない) #3:爆弾ブロック(隣接する4ブロックも一緒に消す) #4:お邪魔ブロック(消えるとボールがしばらく見えなくなる) #5:浮動ブロック(横に動く) map_name = 'Default' #マップのcsvファイルが存在した場合 if os.path.isfile(path): with open(path, 'r') as f: block_map = np.array([[int(i) for i in row.split(',')] for row in f.readlines()]) map_name = path #マップのサイズ y_lim,x_lim = block_map.shape #ブロックの設定 blocks = [] for x in range(8): for y in range(y_lim): blocks.append(Block(np.array([40,40]) + block_size * np.array([x,y]), block_map[y,x])) #バーの設定 bar = Bar([280,550],[80,10]) stop = True running = True cnt = 0 blk_cnt = 0 #スタート画面の設定 font = pygame.font.Font(None, 30) text = font.render("PRESS TO START", True, (255, 255, 255)) #スタート画面 クリックされるまで繰り返し while stop: surface.fill((50,50,50)) surface.blit(text, [190, 80]) pygame.draw.circle(surface, ball.color, ball.loc, ball_size) mouseX, mouseY = pygame.mouse.get_pos() bar.bar.left = np.clip(mouseX-bar.size[0]/2,0,screen_size[0]-bar.size[0]) pygame.draw.rect(surface,"WHITE", bar.bar) pygame.display.update() for event in pygame.event.get(): # イベント if event.type == pygame.MOUSEBUTTONDOWN and event.button == pygame.BUTTON_LEFT:# 左釦押下 stop = False if (event.type == pygame.QUIT) or (event.type == KEYDOWN and event.key == K_ESCAPE): stop = False running = False pygame.quit() return "end" #落ちた階数のカウント fall_num = 0 st_time = pygame.time.get_ticks() #ゲーム本編 while running: #画面設定 surface.fill((50,50,50)) #ボール不可視化解除 if blk_cnt >= 20: ball.color = [255,255,255] #ボール移動 if cnt >= 30: ball.loc = [np.clip(l+v, 0+ball_size, s-ball_size) for l,v,s in zip(ball.loc, ball.vs, screen_size)] #ボールの壁での跳ね返り ball.vs = np.array([-v if l<=0+ball_size or l>=s-ball_size else v for l,v,s in zip(ball.loc, ball.vs, screen_size)]) #ボールをバーで跳ね返す if bar.bar.collidepoint(ball.loc + np.array([0,ball_size])): angle = -130 + ball.loc[0] - bar.bar.left ball.vs = np.array([math.cos(math.radians(angle)) * vabs, math.sin(math.radians(angle)) * vabs]) #ボールを落としたとき if ball.loc[1] >= screen_size[1] - ball_size: fall_num += 1 ball.fall() cnt = 0 #バーの移動 mouseX, mouseY = pygame.mouse.get_pos() bar.bar.left = np.clip(mouseX-bar.size[0]/2,0,screen_size[0]-bar.size[0]) #ブロックの処理 trig = 0 new_vs = ball.vs for num,block in enumerate(blocks): if block.typ == 5: #浮動ブロックの移動処理 block.block.left += block.vs[0] if not(40 <= block.block.left <= 460) or len(block.block.collidelistall([piece.block for piece in blocks[0:num]+blocks[num+1:] if piece.typ != 0])) > 0: block.vs *= -1 block.block.left += block.vs[0] #ブロックとボールの衝突処理 coll_cnt = 0 for p,h in zip(points, hoko): if block.block.collidepoint(ball.loc+p) and block.typ != 0: new_vs[h] = -1 * ball.vs[h] coll_cnt = 1 if coll_cnt == 1: if block.typ == 3: #爆発ブロック衝突時の処理 block.block.scale_by_ip(1.5,1.5) idx = block.block.collidelistall([piece.block for piece in blocks]) for i in idx: blocks[i].attack(bomb=True) elif block.typ == 4: #お邪魔ブロック衝突時の処理 ball.color = [50,50,50] blk_cnt = 0 block.attack() #壊れていないブロックの表示 if block.typ != 0: pygame.draw.rect(surface, block.block_color, block.block) pygame.draw.rect(surface, (10,10,10), block.block,1) if block.typ != 10: trig = 1 ball.vs = new_vs #ブロック衝突時のボールの反射 pygame.draw.circle(surface, ball.color, ball.loc, ball_size) #ボールの表示 pygame.draw.rect(surface,"WHITE", bar.bar) #バーの表示 #画面更新 pygame.display.update() #フレームレート設定 clock.tick(60) cnt += 1 blk_cnt += 1 if trig==0: #クリア時の処理 ed_time = pygame.time.get_ticks() text = font.render(map_name + " CLEAR!", True, (0, 255, 0)) surface.blit(text, [150, 80]) result = ed_time - st_time mini, result = divmod(result,60000) sec,mill = divmod(result,1000) result_txt = font.render('time :{:02}:{:02}.{:03}'.format(mini,sec,mill), True, (0, 255, 0)) surface.blit(result_txt, [150, 130]) fall_txt = font.render('fall :{:02}'.format(fall_num), True, (0, 255, 0)) surface.blit(fall_txt, [150, 180]) pygame.display.update() return "continue" #ゲーム終了時処理 for event in pygame.event.get(): if (event.type == pygame.QUIT) or (event.type == KEYDOWN and event.key == K_ESCAPE): return "end" break else: continue break game = True level = 1 #ゲームの実行 while game: path = 'map_' + str(level) + '.csv' #マップのファイルの相対パス定義 #ゲーム本編の実行 isend = main(path) #ゲームを終わらせるか if isend == "end": pygame.quit() break end = True #クリア後の待機画面 while end: for event in pygame.event.get(): if (event.type == pygame.QUIT) or (event.type == KEYDOWN and event.key == K_ESCAPE): end = False game = False pygame.quit() if (event.type == pygame.MOUSEBUTTONDOWN and event.button == pygame.BUTTON_LEFT): end = False level += 1