AIでプログラミング ゲーム2のコード

元記事はこれです。この記事の最後のコードをここに記してます。

AI プログラミング ゲーム作り2

今日は、Ubuntu=Lynuxでやっていきます。CopiltもGeminiもアプリがありますが、WEBで検索してログインすればWEBでやれます。 いくつかレベルを上げつつ、作りたいと伝えた…


このファイルをテキストで~.pyのファイルにして、pythonインストールして>python ファイル名で実行できます

import pygame
import sys
import random

# ===== 定数 =====
WIDTH, HEIGHT = 800, 600
WHITE = (255, 255, 255)
BLUE = (0, 150, 255)
RED = (255, 100, 100)
BLACK = (0, 0, 0)
GREEN = (100, 255, 100)
YELLOW = (255, 255, 100)

MAX_BALLS = 3  # 画面上のボール上限

# ===== Paddle =====
class Paddle:
    def __init__(self):
        self.width = 100
        self.height = 15
        self.rect = pygame.Rect(WIDTH//2 - self.width//2, HEIGHT - 50, self.width, self.height)
        self.speed = 7
        self.expand_time = 0

    def move(self, keys):
        if keys[pygame.K_LEFT] and self.rect.left > 0:
            self.rect.x -= self.speed
        if keys[pygame.K_RIGHT] and self.rect.right < WIDTH:
            self.rect.x += self.speed

    def expand(self):
        self.width += 40
        self.rect.width = self.width
        self.expand_time = pygame.time.get_ticks()

    def update(self):
        if self.expand_time and pygame.time.get_ticks() - self.expand_time > 5000:
            self.width = 100
            self.rect.width = self.width
            self.expand_time = 0

    def draw(self, screen):
        pygame.draw.rect(screen, BLUE, self.rect)

# ===== Ball =====
class Ball:
    def __init__(self, x=None, y=None, speed_x=4, speed_y=-4):
        self.size = 15
        self.rect = pygame.Rect(x if x else WIDTH//2, y if y else HEIGHT//2, self.size, self.size)
        self.speed_x = speed_x
        self.speed_y = speed_y

    def move(self):
        self.rect.x += self.speed_x
        self.rect.y += self.speed_y

        if self.rect.left <= 0 or self.rect.right >= WIDTH:
            self.speed_x *= -1
        if self.rect.top <= 0:
            self.speed_y *= -1

    def bounce_paddle(self, paddle):
        if self.rect.colliderect(paddle.rect):
            offset = (self.rect.centerx - paddle.rect.centerx) / (paddle.rect.width / 2)
            self.speed_x = offset * 5
            self.speed_y *= -1

    def bounce_block(self):
        self.speed_y *= -1

    def reset_position(self):
        self.rect.x = WIDTH//2
        self.rect.y = HEIGHT//2
        self.speed_x = 4
        self.speed_y = -4

    def draw(self, screen):
        pygame.draw.ellipse(screen, WHITE, self.rect)

# ===== Block =====
class Block:
    def __init__(self, x, y, w, h, block_type="normal"):
        self.rect = pygame.Rect(x, y, w, h)
        self.type = block_type  # "normal", "powerup", "multiball"

    def draw(self, screen):
        color = RED
        if self.type == "powerup":
            color = GREEN
        elif self.type == "multiball":
            color = YELLOW
        pygame.draw.rect(screen, color, self.rect)

# ===== PowerUp =====
class PowerUp:
    def __init__(self, x, y):
        self.size = 20
        self.rect = pygame.Rect(x, y, self.size, self.size)
        self.speed = 4

    def move(self):
        self.rect.y += self.speed

    def draw(self, screen):
        pygame.draw.rect(screen, GREEN, self.rect)

# ===== Game =====
class Game:
    def __init__(self):
        pygame.init()
        self.screen = pygame.display.set_mode((WIDTH, HEIGHT))
        pygame.display.set_caption("ブロック崩し OOP版")
        self.clock = pygame.time.Clock()
        self.font = pygame.font.SysFont(None, 36)

        # 効果音・BGM
        try:
            pygame.mixer.music.load("bgm.mp3")  # 適当なBGMファイル
            pygame.mixer.music.play(-1)
            self.sound_block = pygame.mixer.Sound("block.wav")
            self.sound_powerup = pygame.mixer.Sound("powerup.wav")
            self.sound_multiball = pygame.mixer.Sound("multiball.wav")
        except:
            self.sound_block = self.sound_powerup = self.sound_multiball = None

        self.paddle = Paddle()
        self.balls = [Ball()]
        self.blocks = self.create_blocks()
        self.powerups = []

        self.score = 0
        self.lives = 3
        self.stage = 1
        self.game_over = False

    def create_blocks(self):
        blocks = []
        rows, cols = 5, 8
        block_width = WIDTH // cols
        block_height = 30
        for row in range(rows):
            for col in range(cols):
                # ランダムで特殊ブロック
                r = random.random()
                if r < 0.1:
                    btype = "powerup"
                elif r < 0.2:
                    btype = "multiball"
                else:
                    btype = "normal"
                blocks.append(Block(col * block_width, row * block_height + 50, block_width - 2, block_height - 2, btype))
        return blocks

    def reset_game(self):
        self.score = 0
        self.lives = 3
        self.stage = 1
        self.blocks = self.create_blocks()
        self.powerups.clear()
        self.paddle = Paddle()
        self.balls = [Ball()]
        self.game_over = False

    def update(self):
        keys = pygame.key.get_pressed()
        self.paddle.move(keys)
        self.paddle.update()

        for ball in self.balls[:]:
            ball.move()
            ball.bounce_paddle(self.paddle)

            # ボール落下
            if ball.rect.bottom >= HEIGHT:
                self.balls.remove(ball)
                if not self.balls:
                    self.lives -= 1
                    if self.lives > 0:
                        self.balls = [Ball()]
                        self.paddle = Paddle()
                    else:
                        self.game_over = True
                continue

            # ブロック衝突
            hit_index = ball.rect.collidelist([b.rect for b in self.blocks])
            if hit_index != -1:
                hit_block = self.blocks.pop(hit_index)
                ball.bounce_block()
                self.score += 100
                if self.sound_block: self.sound_block.play()

                if hit_block.type == "powerup":
                    self.powerups.append(PowerUp(hit_block.rect.centerx, hit_block.rect.centery))
                elif hit_block.type == "multiball":
                    if self.sound_multiball:
                        self.sound_multiball.play()

                    # 生成候補(2球)
                    spawn_candidates = [
                        Ball(hit_block.rect.centerx, hit_block.rect.centery, speed_x=4, speed_y=-4),
                        Ball(hit_block.rect.centerx, hit_block.rect.centery, speed_x=-4, speed_y=-4)
                    ]

                    # 上限を超えない分だけ追加
                    for new_ball in spawn_candidates:
                        if len(self.balls) < MAX_BALLS:
                            self.balls.append(new_ball)


        # パワーアップ処理
        for p in self.powerups[:]:
            p.move()
            if p.rect.colliderect(self.paddle.rect):
                self.paddle.expand()
                if self.sound_powerup: self.sound_powerup.play()
                self.powerups.remove(p)
            elif p.rect.top > HEIGHT:
                self.powerups.remove(p)

        # ステージクリア
        if not self.blocks:
            self.stage += 1
            for ball in self.balls:
                ball.speed_x *= 1.1
                ball.speed_y *= 1.1
            self.blocks = self.create_blocks()
            
            # クリア後はボールをパドル位置に戻す
            for ball in self.balls:
                ball.rect.centerx = self.paddle.rect.centerx
                ball.rect.bottom = self.paddle.rect.top - 1
                ball.speed_x = 4
                ball.speed_y = -4
        
    def draw(self):
        self.screen.fill(BLACK)
        self.paddle.draw(self.screen)
        for ball in self.balls:
            ball.draw(self.screen)
        for block in self.blocks:
            block.draw(self.screen)
        for p in self.powerups:
            p.draw(self.screen)

        score_text = self.font.render(f"Score: {self.score}  Stage: {self.stage}  Lives: {self.lives}", True, WHITE)
        self.screen.blit(score_text, (10, 10))

        if self.game_over:
            over_text = self.font.render("GAME OVER - Press SPACE to Restart", True, WHITE)
            self.screen.blit(over_text, (WIDTH//2 - over_text.get_width()//2, HEIGHT//2))

        pygame.display.flip()

    def run(self):
        while True:
            # ===== 1. イベント処理 =====
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                # ゲームオーバー時にスペースで再スタート
                if self.game_over and event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
                    self.reset_game()

            # ===== 2. ゲーム状態更新 =====
            if not self.game_over:
                self.update()

            # ===== 3. 描画 =====
            self.draw()

            # ===== 4. フレームレート制御 =====
            self.clock.tick(60)


# ===== 実行 =====
if __name__ == "__main__":
    Game().run()