pygameでブロック崩し風のゲームを作ってみた

## はじめに

pythonとpygameでブロック崩し風のゲーム作りたいな。

## 説明

・白い四角 : 自機
・赤い丸 : ブロックを崩す玉
・青い四角 : ブロック
・タイトル画面をクリックするとゲーム画面にいく
・ブロックを全部崩した場合や赤い玉を拾えなかった場合、3秒後にタイトルに戻る
・ゲーム中にクリックするとポーズ画面になり「Pause」と表示する
・最後クリックするとポーズが終わりゲームに戻る

## ソースコード

```py main.py
import pygame
import random

# Pygameの初期化
pygame.init()

# ウィンドウの設定
width, height = 800, 600
win = pygame.display.set_mode((width, height))
pygame.display.set_caption("Breakout")

# 色の定義
black = (0, 0, 0)
white = (255, 255, 255)
blue = (0, 0, 255)
red = (255, 0, 0)
green = (0, 255, 0)

# フレームレート
clock = pygame.time.Clock()
fps = 60

# パドルの設定
paddle_width = 100
paddle_height = 10
paddle_x = (width - paddle_width) // 2
paddle_y = height - 40
paddle_speed = 10

# ボールの設定
ball_size = 10
ball_x = width // 2
ball_y = height // 2
ball_speed_x = 4
ball_speed_y = -4

# ブロックの設定
block_rows = 5
block_cols = 10
block_width = width // block_cols
block_height = 20

# フォントの設定
font_large = pygame.font.Font(None, 74)
font_small = pygame.font.Font(None, 36)

def draw_text(text, font, color, surface, x, y):
    text_obj = font.render(text, True, color)
    text_rect = text_obj.get_rect()
    text_rect.center = (x, y)
    surface.blit(text_obj, text_rect)

def title_screen():
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                exit()
            if event.type == pygame.MOUSEBUTTONDOWN:
                return

        win.fill(black)
        draw_text("Breakout", font_large, white, win, width / 2, height / 2 - 50)
        draw_text("Click to start", font_small, white, win, width / 2, height / 2 + 50)
        pygame.display.update()
        clock.tick(fps)

def pause_screen(background):
    paused = True
    while paused:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                exit()
            if event.type == pygame.MOUSEBUTTONDOWN:
                paused = False

        win.blit(background, (0, 0))
        draw_text("Pause", font_large, white, win, width / 2, height / 2)
        pygame.display.update()
        clock.tick(fps)

def game():
    paddle_x = (width - paddle_width) // 2
    ball_x, ball_y = width // 2, height // 2
    ball_speed_x, ball_speed_y = 4, -4
    blocks = [pygame.Rect(col * block_width, row * block_height, block_width, block_height)
              for row in range(block_rows) for col in range(block_cols)]
    game_clear, game_over = False, False
    running = True

    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                exit()
            if event.type == pygame.MOUSEBUTTONDOWN:
                background = win.copy()
                pause_screen(background)

        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT] and paddle_x > 0:
            paddle_x -= paddle_speed
        if keys[pygame.K_RIGHT] and paddle_x < width - paddle_width:
            paddle_x += paddle_speed

        ball_x += ball_speed_x
        ball_y += ball_speed_y

        # 壁との衝突
        if ball_x <= 0 or ball_x >= width - ball_size:
            ball_speed_x = -ball_speed_x
        if ball_y <= 0:
            ball_speed_y = -ball_speed_y
        if ball_y >= height:
            game_over = True
            running = False

        # パドルとの衝突
        paddle_rect = pygame.Rect(paddle_x, paddle_y, paddle_width, paddle_height)
        ball_rect = pygame.Rect(ball_x, ball_y, ball_size, ball_size)
        if paddle_rect.colliderect(ball_rect):
            ball_speed_y = -ball_speed_y

        # ブロックとの衝突
        for block in blocks[:]:
            if block.colliderect(ball_rect):
                ball_speed_y = -ball_speed_y
                blocks.remove(block)

        # 画面の描画
        win.fill(black)
        pygame.draw.rect(win, white, paddle_rect)
        pygame.draw.ellipse(win, red, ball_rect)
        for block in blocks:
            pygame.draw.rect(win, blue, block)

        # ブロックが全て破壊された場合
        if not blocks:
            game_clear = True
            running = False

        pygame.display.update()
        clock.tick(fps)

    return game_clear, game_over

def main():
    while True:
        title_screen()
        game_clear, game_over = game()

        if game_clear:
            win.fill(black)
            draw_text("Game Clear!", font_large, green, win, width / 2, height / 2)
            pygame.display.update()
            pygame.time.wait(3000)
        elif game_over:
            win.fill(black)
            draw_text("Game Over...", font_large, red, win, width / 2, height / 2)
            pygame.display.update()
            pygame.time.wait(3000)

if __name__ == "__main__":
    main()
    pygame.quit()


```

## 起動

```sh
$ python main.py
```

## ゲーム画面

![スクリーンショット 2024-07-03 11.49.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327773/5b9c296a-aaa5-1d40-2d48-1dbe2fd02dd5.png)


![スクリーンショット 2024-07-03 11.49.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327773/e2d6c7a0-f64a-fa59-515b-77572516cf0c.png)


## 終わり

できた。