😉

回転する六角形の中でボールが跳ね返るデモアプリの作ってみる

に公開

はじめに

@denwaya34です。😉

タイトルの通り、よくみるこのデモアプリがちゃんとできるか確認してみます。
cursorエディタとopenai o4-miniで作ってみます。
https://x.com/flavioAd/status/1885449107436679394

プロンプト

write a Python program that shows a ball bouncing inside a spinning hexagon.
The ball should be affected by gravity and friction, and it must bounce off the rotating walls realistically.

日本語訳

回転する六角形の中でボールが弾む様子を示すPythonプログラムを書きなさい。
ボールは重力と摩擦の影響を受け、回転する壁をリアルに跳ね返らなければならない。

結果

ちゃんとできた😉
https://www.youtube.com/watch?v=3DywJjkpxAA

コードはこんな感じ

# main.py
# ボールが重力と摩擦を受けながら回転する六角形内で跳ね返るプログラム
# 必要パッケージ: pygame(pip install pygame)

import pygame
import sys
import math
import random

WIDTH, HEIGHT = 800, 600
CENTER = pygame.math.Vector2(WIDTH/2, HEIGHT/2)
HEX_RADIUS = 250
BALL_RADIUS = 15
GRAVITY = 500  # px/s^2
FRICTION = 0.999
BOUNCE = 0.9
FPS = 60
ROT_SPEED = math.radians(30)  # 回転速度 (rad/s)

def main():
    pygame.init()
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
    pygame.display.set_caption("Ball in Spinning Hexagon")
    clock = pygame.time.Clock()

    ball_pos = pygame.math.Vector2(CENTER)
    ball_vel = pygame.math.Vector2(random.uniform(-200, 200), random.uniform(-200, 200))

    angle = 0.0

    running = True
    while running:
        dt = clock.tick(FPS) / 1000.0

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

        # 物理演算
        ball_vel.y += GRAVITY * dt
        ball_vel *= FRICTION
        ball_pos += ball_vel * dt

        # 回転更新
        angle += ROT_SPEED * dt

        # 六角形頂点計算
        hex_points = []
        for i in range(6):
            theta = angle + i * 2 * math.pi / 6
            x = CENTER.x + HEX_RADIUS * math.cos(theta)
            y = CENTER.y + HEX_RADIUS * math.sin(theta)
            hex_points.append(pygame.math.Vector2(x, y))

        # 衝突判定
        for i in range(len(hex_points)):
            A = hex_points[i]
            B = hex_points[(i + 1) % len(hex_points)]
            edge = B - A
            mid = (A + B) * 0.5
            to_center = CENTER - mid
            normal = pygame.math.Vector2(edge.y, -edge.x).normalize()
            if normal.dot(to_center) < 0:
                normal = -normal
            dist = (ball_pos - A).dot(normal)
            proj = (ball_pos - A).dot(edge.normalize())
            if dist < BALL_RADIUS and proj > 0 and proj < edge.length():
                # 壁速度
                r = ball_pos - CENTER
                v_wall = pygame.math.Vector2(-ROT_SPEED * r.y, ROT_SPEED * r.x)
                v_rel = ball_vel - v_wall
                v_rel_reflected = v_rel - 2 * v_rel.dot(normal) * normal
                ball_vel = (v_rel_reflected + v_wall) * BOUNCE
                ball_pos += normal * (BALL_RADIUS - dist)

        # 描画
        screen.fill((30, 30, 30))
        pygame.draw.polygon(screen, (200, 200, 200), [(p.x, p.y) for p in hex_points], 2)
        pygame.draw.circle(screen, (255, 100, 100), (int(ball_pos.x), int(ball_pos.y)), BALL_RADIUS)
        pygame.display.flip()

    pygame.quit()
    sys.exit()

if __name__ == "__main__":
    main()

その他

録画をしたい場合

プログラム作成後、下記のプロンプトを入力して録画を作成するように指示します。

このプログラムが起動したら、pygameの画面を起動時点から30秒録画するようにしてください

Discussion