【Pyxel】Pyxel x chatGPT でメガデモ

巷で噂のchatGPTを触ってみました。

「pyxelでメガデモを作ってください」とお願いすると、出来上がってきたのがこれ。

charGPTさんの回答
>「メガデモ」は、デモシーンの文化に由来する、視覚効果、音楽、そしてプログラミング技術を駆使して作られたアート作品です。
Pyxelを使って簡易的なメガデモを作る場合、以下の要素を組み合わせることができます：
> 動的な背景効果 (例: ノイズ、波形、グラデーション)
3D風オブジェクトの回転や動き (例: 立方体や球体の擬似3Dアニメーション)
テキストスクロール (例: 左右または上下に流れるテキスト)
サウンドループ (例: シンプルなループ音楽)
以下は、Pyxelで簡易メガデモを作成するサンプルコードです。
```
import pyxel
import math
import random

class MegaDemo:
    def __init__(self):
        pyxel.init(160, 120, title="Pyxel Mega Demo", fps=30)
        pyxel.sound(0).set(
            "c3e3g3c4g3e3c3c3 g3c4e4g4e4c4g3g3",  # 音階
            "p",  # 波形
            "7",  # 音量
            "n",  # エフェクト
            30,   # テンポ
        )
        pyxel.play(0, 0, loop=True)
        self.angle = 0
        self.scroll_text = "Pyxel Mega Demo! " * 10
        self.text_x = pyxel.width
        pyxel.run(self.update, self.draw)

    def update(self):
        # アニメーション更新
        self.angle += 0.02
        self.text_x -= 1
        if self.text_x < -len(self.scroll_text) * 4:
            self.text_x = pyxel.width

        # 終了処理
        if pyxel.btnp(pyxel.KEY_Q):
            pyxel.quit()

    def draw(self):
        pyxel.cls(0)
        self.draw_background_effect()
        self.draw_rotating_cube()
        self.draw_scrolling_text()

    def draw_background_effect(self):
        """動的な背景ノイズ"""
        for y in range(pyxel.height):
            for x in range(pyxel.width):
                color = (x + y + pyxel.frame_count) % 16
                pyxel.pset(x, y, color)

    def draw_rotating_cube(self):
        """3D風の回転立方体"""
        size = 20
        half_size = size / 2
        vertices = [
            [-half_size, -half_size, -half_size],
            [half_size, -half_size, -half_size],
            [half_size, half_size, -half_size],
            [-half_size, half_size, -half_size],
            [-half_size, -half_size, half_size],
            [half_size, -half_size, half_size],
            [half_size, half_size, half_size],
            [-half_size, half_size, half_size],
        ]
        
        # 回転
        rotated_vertices = [
            self.rotate_vertex(v, self.angle, self.angle / 2, self.angle / 3)
            for v in vertices
        ]

        # 投影
        projected_vertices = [
            self.project_vertex(v) for v in rotated_vertices
        ]

        # 辺のリスト
        edges = [
            (0, 1), (1, 2), (2, 3), (3, 0),  # 前面
            (4, 5), (5, 6), (6, 7), (7, 4),  # 背面
            (0, 4), (1, 5), (2, 6), (3, 7),  # 接続
        ]

        # 辺を描画
        for edge in edges:
            v1, v2 = edge
            x1, y1 = projected_vertices[v1]
            x2, y2 = projected_vertices[v2]
            pyxel.line(int(x1), int(y1), int(x2), int(y2), 7)

    def draw_scrolling_text(self):
        """横スクロールするテキスト"""
        pyxel.text(self.text_x, 100, self.scroll_text, pyxel.frame_count % 16)

    def rotate_vertex(self, vertex, angle_x, angle_y, angle_z):
        """頂点を回転させる"""
        x, y, z = vertex

        # x軸回転
        cos_x, sin_x = math.cos(angle_x), math.sin(angle_x)
        y, z = y * cos_x - z * sin_x, y * sin_x + z * cos_x

        # y軸回転
        cos_y, sin_y = math.cos(angle_y), math.sin(angle_y)
        x, z = x * cos_y - z * sin_y, x * sin_y + z * cos_y

        # z軸回転
        cos_z, sin_z = math.cos(angle_z), math.sin(angle_z)
        x, y = x * cos_z - y * sin_z, x * sin_z + y * cos_z

        return [x, y, z]

    def project_vertex(self, vertex):
        """3D座標を2Dに投影"""
        x, y, z = vertex
        distance = 100
        factor = distance / (distance - z) if (distance - z) != 0 else 1
        x = x * factor + pyxel.width / 2
        y = y * factor + pyxel.height / 2
        return [x, y]

# アプリケーションを実行
MegaDemo()
```
動作はこんな感じです
![test5.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3927925/1e9c45ab-e55c-7218-1ef2-1c35d590d5d6.gif)

[動作確認はこちら](https://sanbunnoichi1962.web.fc2.com/pyxel_experiment.html#chatgpt_de_megademo)

ちょっと趣向を変えて、
「pyxelとpymunkでメガデモを作ってください」とお願いしてみました。

chatGPTさんの回答
>PyxelとPymunkを組み合わせてメガデモ（グラフィックと物理シミュレーションのデモ）を作るのは面白そうですね！以下にそのプロジェクトの概要を説明し、サンプルコードを提供します。
概要
Pyxel はレトロスタイルのゲーム開発に特化したPythonライブラリで、簡単にグラフィックスや音楽を作成できます。
Pymunk は2D物理シミュレーションライブラリで、物理演算や衝突判定を手軽に実装できます。
メガデモの内容:
レトロなピクセルアートで描画される背景とエフェクト。
物理演算で動くオブジェクト（ボールや箱など）。
インタラクティブな要素（クリックでオブジェクトを発射するなど）。
```
import pyxel
import pymunk
import random
import math

# 画面サイズ
WIDTH, HEIGHT = 256, 256

# Pymunkのスペース設定
space = pymunk.Space()
space.gravity = (0, 900)

# オブジェクトとパーティクルのリスト
objects = []
particles = []

# 境界線の作成
def create_static_boundaries():
    static_lines = [
        pymunk.Segment(space.static_body, (0, HEIGHT), (WIDTH, HEIGHT), 1),  # 底辺
        pymunk.Segment(space.static_body, (0, 0), (0, HEIGHT), 1),          # 左壁
        pymunk.Segment(space.static_body, (WIDTH, 0), (WIDTH, HEIGHT), 1),  # 右壁
    ]
    for line in static_lines:
        line.elasticity = 0.8
        line.friction = 0.5
    space.add(*static_lines)

# ボールを生成
def create_ball(x, y):
    mass = 1
    radius = random.randint(5, 10)
    moment = pymunk.moment_for_circle(mass, 0, radius)
    body = pymunk.Body(mass, moment)
    body.position = x, y
    shape = pymunk.Circle(body, radius)
    shape.elasticity = 0.8
    shape.friction = 0.5
    space.add(body, shape)
    objects.append((body, shape))
    create_particles(x, y, color=pyxel.frame_count % 16 + 1)

# パーティクルを生成
def create_particles(x, y, color):
    for _ in range(20):
        angle = random.uniform(0, 2 * math.pi)
        speed = random.uniform(50, 150)
        dx = math.cos(angle) * speed
        dy = math.sin(angle) * speed
        particles.append({"x": x, "y": y, "dx": dx, "dy": dy, "life": 30, "color": color})

# 動くプラットフォームを生成
def create_moving_platform():
    body = pymunk.Body(body_type=pymunk.Body.KINEMATIC)
    body.position = WIDTH // 2, HEIGHT - 50
    shape = pymunk.Segment(body, (-50, 0), (50, 0), 5)
    shape.elasticity = 0.9
    space.add(body, shape)
    return body

# Pyxelアプリ
class App:
    def __init__(self):
        pyxel.init(WIDTH, HEIGHT, title="Enhanced Pyxel + Pymunk Demo")
        pyxel.sound(0).set("c3e3g3c4", "p", "7", "n", 25)
        pyxel.sound(1).set("g3c4e4g4", "t", "6", "f", 15)
        pyxel.sound(2).set("e3c4g3", "n", "7", "f", 10)
        pyxel.play(0, 0, loop=True)
        create_static_boundaries()
        self.platform = create_moving_platform()
        pyxel.run(self.update, self.draw)

    def update(self):
        if pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT):
            create_ball(pyxel.mouse_x, pyxel.mouse_y)
            pyxel.play(1, 1)

        # パーティクルの更新
        for particle in particles[:]:
            particle["x"] += particle["dx"] * 1 / 60
            particle["y"] += particle["dy"] * 1 / 60
            particle["life"] -= 1
            if particle["life"] <= 0:
                particles.remove(particle)

        # プラットフォームの動き
        t = pyxel.frame_count / 60
        self.platform.position = (WIDTH // 2 + math.sin(t) * 50, HEIGHT - 50)

        # Pymunkのステップ
        space.step(1 / 60)

    def draw(self):
        pyxel.cls(0)

        # パーティクルの描画
        for particle in particles:
            pyxel.pset(int(particle["x"]), int(particle["y"]), particle["color"])

        # ボールの描画
        for body, shape in objects:
            if isinstance(shape, pymunk.Circle):
                x, y = body.position
                pyxel.circ(x, y, shape.radius, pyxel.frame_count % 16 + 1)

        # プラットフォームの描画
        x, y = self.platform.position
        pyxel.rect(x - 50, y - 5, 100, 5, 10)

        pyxel.text(5, 5, "Click to spawn balls!", 7)

# アプリの実行
App()
```
pyxelの動画出力はなぜかできなかったので静止画だけ
![test10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3927925/6beff331-eb26-ca8d-b50a-ba09dc9bda7a.png)

マウス左クリックを連打すると玉を発生させ、発生時にはじけるアニメーションをします。

抽象的な質問でも基本は抑えているようです。
ただ、出力されたpyxelのソースコードのバージョンは古い場合があるのでそこは指摘してあげれば改善してくれます。
もっと細かく指示してあげればそれなりのソースコードを得ることができます。
それなり・・・です。