打ち上げ花火

講師から一言
オブジェクト指向の題材として打ち上げ花火を選んだ点を高く評価しています。

連続して打ち上げる花火をクラス化して色や形を変えてインスタンスを生成する、まさにオブジェクト指向で作るにふさわしい作品だと思います。

高校で習う三角関数(sin,cos)を使って火花の動きをみごとに再現できています。コードも完結で洗練されています。


Pythonで記述したコード
import pygame
import random
import math

# 初期化
pygame.init()

# 画面サイズ
WIDTH = 800
HEIGHT = 482
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("打ち上げ花火")
背景=pygame.image.load("背景.png")
猫たち=pygame.image.load("猫たち.png")
打ち上げ音=pygame.mixer.Sound("pyu.wav")
花火=pygame.mixer.Sound("bom.wav")
BGM=pygame.mixer.Sound("wind.wav")
n=0
BGM.play(-1)
# 色の定義
BLACK = (0, 0, 0)

# 花火を定義するクラス
class Firework:
    def __init__(self):
        self.x = random.randint(200, WIDTH - 200)
        self.y = HEIGHT
        self.size = random.randint(3, 5)
        self.color = [random.randint(100, 255) for _ in range(3)]
        self.speed = random.uniform(6, 8)
        self.exploded = False
        self.particles = []

    def update(self):
        global n
        n+=1
        if not self.exploded:
            # 花火が上昇する
            if n%2==0:
                打ち上げ音.play()
            if n%3==0:
                花火.play()
            self.y -= self.speed
            # 一定の高さで爆発
            if self.speed < 0.5:
                self.explode()
            else:
                self.speed -= 0.1
        else:
            # 爆発後、粒子を更新
            for particle in self.particles:
                particle.update()

    def explode(self):
        # 爆発したら粒子を生成(等間隔の角度で)
        self.exploded = True
        num_particles = 100  # より多くの粒子で美しい円形を描く
        for i in range(num_particles):
            angle = i * (2 * math.pi / num_particles)  # 等間隔の角度
            speed = random.uniform(2, 5)
            self.particles.append(Particle(self.x, self.y, speed, angle, self.color))

    def draw(self, screen):
        if not self.exploded:
            pygame.draw.circle(screen, self.color, (int(self.x), int(self.y)), self.size)
        else:
            for particle in self.particles:
                particle.draw(screen)

# 粒子を定義するクラス
class Particle:
    def __init__(self, x, y, speed, angle, color):
        self.x = x
        self.y = y
        self.speed_x = math.cos(angle) * speed
        self.speed_y = math.sin(angle) * speed
        self.color = color
        self.size = random.randint(2, 4)
        self.lifetime = random.randint(40, 60)  # 粒子の寿命を長くして綺麗に表示

    def update(self):
        # 粒子が飛び散る
        self.x += self.speed_x
        self.y += self.speed_y
        self.lifetime -= 1
        self.size = max(0, self.size - 0.03)  # 粒子がゆっくりと小さくなる

    def draw(self, screen):
        if self.lifetime > 0:
            pygame.draw.circle(screen, self.color, (int(self.x), int(self.y)), int(self.size))

# メインループ
def main():
    clock = pygame.time.Clock()
    fireworks = []

    running = True
    while running:
        screen.fill(BLACK)
        screen.blit(背景,(0,0))
        screen.blit(猫たち,(0,200))

        # イベント処理
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False

        # 一定確率で新しい花火を追加
        if random.randint(0, 100) < 3:
            fireworks.append(Firework())

        # 花火の更新と描画
        for firework in fireworks:
            firework.update()
            firework.draw(screen)

        # 終了した花火を削除
        fireworks = [f for f in fireworks if not (f.exploded and all(p.lifetime <= 0 for p in f.particles))]

        pygame.display.flip()
        clock.tick(60)

    pygame.quit()

if __name__ == "__main__":
    main()