見出し画像

ScratchからPythonへ・・・その2  紙吹雪が一言でできた!

経緯

に紙吹雪のプログラムを作ってもらった。Scratch的に初歩的な段階から作っていった。どういうことが生成AIは得意か不得意かを知りたいと思っている。生成AIは簡単なことはさらさらとやってくれるが、どうも分岐の問題は苦手のようである。
そこで、今回は紙吹雪の問題を直接お願いしてみた。

なお今回のリートン(wrtn:GPT-4 turbo)を使っている

紙吹雪のプログラム

まずは、つぎの質問をしてみた。ちゃんとプログラムを書いてくれないことがあるので最初にベテランプログラマーとしてお願いした。

あなたはPythonのベテランプログラマーですね。いろんな色の紙片が降ってくる紙吹雪のpythonのプログラムを作ってください。

フミオ

帰ってきた回答は次の通りです。謙虚な人ですね。


私はPythonのコーディングを直接行うことはできませんが、Pythonで紙吹雪をシミュレートする簡単なプログラムコードを説明することはできます。Pygameなどのライブラリを使用して描画とアニメーションを処理することができます。

以下は、Pygameを使用して紙吹雪を降らせる基本的なアイディアです。このコードは直接実行可能ではなく、PygameがインストールされたPython環境で使用するための概念的な説明です。

リートン

そしてコードです。

import pygame
import random

# Pygameの初期化
pygame.init()

# 色の設定
WHITE = (255, 255, 255)
COLORS = [(255, 0, 0), (0, 255, 0), (0, 0, 255),
          (255, 255, 0), (255, 0, 255), (0, 255, 255)]

# スクリーンサイズの設定
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("紙吹雪のシミュレーション")

# 紙片を表すクラス
class Confetti:
    def __init__(self, x, y, color):
        self.x = x
        self.y = y
        self.color = color
        self.size = random.randint(5, 10)
        self.shape = random.choice(['rect', 'circle'])
        self.vel_x = random.randint(-3, 3)
        self.vel_y = random.randint(1, 6)

    def draw(self, screen):
        if self.shape == 'rect':
            pygame.draw.rect(screen, self.color, (self.x, self.y, self.size, self.size))
        else:
            pygame.draw.circle(screen, self.color, (self.x, self.y), self.size // 2)

    def fall(self):
        self.x += self.vel_x
        self.y += self.vel_y
        # 画面外に出たら、上に戻す
        if self.y > SCREEN_HEIGHT:
            self.y = 0
            self.x = random.randint(0, SCREEN_WIDTH)

# 紙吹雪のリストの生成
confetti_list = [Confetti(random.randint(0, SCREEN_WIDTH), random.randint(0, SCREEN_HEIGHT), random.choice(COLORS)) for _ in range(100)]

# メインループ
running = True
while running:
    screen.fill(WHITE)  # 画面を白でクリア
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    # 紙吹雪の描画と更新
    for confetti in confetti_list:
        confetti.draw(screen)
        confetti.fall()

    pygame.display.flip()  # 描画内容をスクリーンに適用
    pygame.time.Clock().tick(30)  # フレームレートを30に設定

pygame.quit()  # Pygameの終了

そして、結果です。

このコードは、色とりどりの紙吹雪が画面上から降ってくるシミュレーションを作成するためのものです。Confettiクラスは紙片一つ一つを表し、その形(四角または円)、大きさ、色、落下速度などがランダムに設定されます。メインループでは、すべての紙片を描画し、下に移動させ、画面下端に到達した紙片を画面上端に戻すことで、連続して降り続ける紙吹雪を作成します。

リートン

素晴らしいですね。一言のお願いでプログラムができてしまいました。

分析


このコードでリストというのがわかりにくかったのでちょっと聞いてみました。

リストが理解しにくいですが、簡単に説明してください

フミオ

リートンは次の回答をしてくれました。僕の期待していたこととは違ったのですが、コードの構造ということで付け加えておきます。その前にここでリストを使っているのはScratchのクローンですね。最初、一番上から降ってくるのではなく、最初、100個の紙片をランダムに配置してそこから下に落ちていくということで画面にランダムに落ちてくるのがハッキリします。

プログラム構造

もちろんです。Pythonのプログラムで「紙吹雪」をシミュレートする際には、以下のようなステップで進めます。画面の設定:画面のサイズやタイトルを決めます。
色の定義:紙吹雪の色をいくつか定義します。
紙吹雪クラスの作成:紙吹雪の形や色、サイズ、動きを定義するクラスを作ります。
紙吹雪のリスト:紙吹雪のオブジェクトをたくさん作成して、リストに保存します。
メインループ:このループ内で、次のようなことを繰り返します:
画面をクリア(一旦白い画面に戻す)します。
リスト内の各紙吹雪オブジェクトに対して、描画(ドロー)し、落下(フォール)させる処理を行います。
画面を更新します。
ゲームイベントをチェックし、閉じるボタンが押されれば、プログラムを終了します。
描画 & 更新:各紙吹雪の現在位置に、定めた色の形(四角か円)を描画し、位置情報を更新して紙吹雪が下に落ちるようにします。画面の一番下に達すると、上に戻します。
フレームレートの設定:このコードでは、秒間30フレームでアニメーションが滑らかに動くように設定しています。


このコードは、多くの色とりどりの紙吹雪が画面の上から下に向かって無限に降り続ける様子を描画するためのものです。利用するにはPython環境にpygameライブラリがインストールされている必要があります。

リートン

関数として保存

一言で紙吹雪ができるのなら、関数として保存してほかの作品に使いたい。

なにか、結婚式の写真の前に紙吹雪を降らすために、全体を関数化して、mainの一部にその関数を持ってくるということはできますか

フミオ

はい、それは可能です。PythonとPygameライブラリを使用することで、ゲームや他のグラフィカルなアプリケーションにおいてアニメーション効果を作成することができます。紙吹雪を関数化して、それをメインのコードで呼び出すことにより、紙吹雪を降らせるアニメーションを制御できます。



以下は、そのアイディアの疑似コードです。実際のPygameプロジェクトで使用するためには、適切なPygameセットアップとイベントループが必要になりますが、基本的なコンセプトは以下のようになります。

リートン
import pygame
import random

# 紙吹雪の設定をするためのクラス
class Confetti:
    def __init__(self, screen):
        self.screen = screen
        self.x = random.randint(0, screen.get_width())
        self.y = random.randint(0, screen.get_height())
        self.size = random.randint(5, 15)
        self.color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
        self.fall_speed = random.randint(2, 5)

    def fall(self):
        self.y += self.fall_speed
        if self.y > self.screen.get_height():
            self.y = 0 - self.size
            self.x = random.randint(0, self.screen.get_width())

# 紙吹雪を順に描画する関数
def draw_confetti(screen, confetti_list):
    screen.fill((255, 255, 255))  # 最初に背景を白に設定
    for confetti in confetti_list:
        pygame.draw.circle(screen, confetti.color, (confetti.x, confetti.y), confetti.size)
        confetti.fall()  # 紙吹雪を落下させる

# メイン関数
def main():
    pygame.init()
    screen_width, screen_height = 800, 600
    screen = pygame.display.set_mode((screen_width, screen_height))
    pygame.display.set_caption("Wedding Confetti")
    
    num_confettis = 100
    confetti_list = [Confetti(screen) for _ in range(num_confettis)]
    
    running = True
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
                
        # 紙吹雪の描画
        draw_confetti(screen, confetti_list)
        
        # 画面の更新
        pygame.display.flip()
        # FPSの設定
        pygame.time.Clock().tick(30)

    pygame.quit()

if __name__ == "__main__":
    main()

結果です。

ちょっともたついた感じにもなりますが、次で深々と降る雪を作ってみましょう。

雪のお地蔵様

今度のサンプルは横向きの動きをいれてなくて、白い雪が降ってくるというイメージですね。また、お願いしました。

若干の修正をしましたが、コードはこれです。

import pygame
import random

# 紙吹雪の設定をするためのクラス
class Confetti:
    def __init__(self, screen):
        self.screen = screen
        self.x = random.randint(0, screen.get_width())
        self.y = random.randint(0, screen.get_height())
        self.size = random.randint(5, 15)
        self.color = (255, 255, 255 )
        self.fall_speed = random.randint(2, 5)

    def fall(self):
        self.y += self.fall_speed
        if self.y > self.screen.get_height():
            self.y = 0 - self.size
            self.x = random.randint(0, self.screen.get_width())   # ... 既存のコード ...

# 紙吹雪を順に描画する関数
def draw_confetti(screen, confetti_list, jizou_img):
    screen.fill((127, 127, 127))  # 最初に背景を白に設定

    # お地蔵様の画像を画面の中央あたりに配置
    jizou_position = (screen.get_width() // 2 - jizou_img.get_width() // 2, 
                      screen.get_height() // 2 - jizou_img.get_height() // 2)
    screen.blit(jizou_img, jizou_position)

    for confetti in confetti_list:
        pygame.draw.circle(screen, confetti.color, (confetti.x, confetti.y), confetti.size)
        confetti.fall()  # 紙吹雪を落下させる

# メイン関数
def main():
    pygame.init()
    screen_width, screen_height = 800, 600
    screen = pygame.display.set_mode((screen_width, screen_height))
    pygame.display.set_caption("Wedding Confetti")

    # お地蔵様の画像をロード
    jizou_img = pygame.image.load('jizou.png')

    num_confettis = 100
    confetti_list = [Confetti(screen) for _ in range(num_confettis)]

    running = True
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False

        # 紙吹雪の描画(お地蔵様の画像を含む)
        draw_confetti(screen, confetti_list, jizou_img)

        # 画面の更新
        pygame.display.flip()
        # FPSの設定
        pygame.time.Clock().tick(30)

    pygame.quit()

if __name__ == "__main__":
    main()

結果が次のようになりました。

上記のコードでは、お地蔵様の画像をロードしてjizou_imgに格納し、draw_confetti関数に引数として追加しています。draw_confetti関数内では画面を白でクリアした後にお地蔵様の画像を描画し、その上に紙吹雪を描画しています。
お地蔵様の画像はpygame.image.load()を用いて読み込んでおり、screen.blit()を利用して特定の位置に描画しています。画像のサイズや画面サイズによっては位置の調整が必要になるかもしれません。また、パスを指定する際にはその画像があなたのスクリプトの実行ファイルと同じディレクトリにあることを確認してください。

リートン


良い感じかなと思いますがどうでしょう。

2023/12/13


この記事が気に入ったらサポートをしてみませんか?