#!python # -*- mode: python; Encoding: utf-8; coding: utf-8 -*- # Last updated: <2026/07/03 15:03:28 +0900> """ スプライトで球を表示するサンプル。 Google Gemini に作ってもらった。 Windows11 x64 25H2 + Python 3.10.10 64bit """ import pygame import sys import math import asyncio # 1. asyncioのインポート # 初期設定 pygame.init() WIDTH, HEIGHT = 800, 600 screen = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("3D Point Cloud Sphere with Sprites (Pygbag)") clock = pygame.time.Clock() # --- 球体上の点群(3D座標)を生成 --- NUM_POINTS = 100 SPHERE_RADIUS = 250 base_points = [] phi = math.pi * (math.sqrt(5.0) - 1.0) for i in range(NUM_POINTS): y = 1.0 - (i / float(NUM_POINTS - 1)) * 2.0 radius_at_y = math.sqrt(1.0 - y * y) theta = phi * i x = math.cos(theta) * radius_at_y z = math.sin(theta) * radius_at_y base_points.append([x * SPHERE_RADIUS, y * SPHERE_RADIUS, z * SPHERE_RADIUS]) # 2. メインの処理を async 定義の関数にする async def main(): # 画像の読み込み (関数内で実行) try: sprite_image = pygame.image.load("image.png").convert_alpha() except pygame.error: print("image.png が見つからないため、仮のスプライトを作成します。") sprite_image = pygame.Surface((64, 64), pygame.SRCALPHA) pygame.draw.circle(sprite_image, (0, 255, 200), (32, 32), 24) pygame.draw.circle(sprite_image, (255, 255, 255), (32, 32), 16) SPRITE_W, SPRITE_H = sprite_image.get_size() angle_y = 0 angle_x = 0 running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False elif event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: running = False # 画面のクリア screen.fill((15, 15, 15)) # アニメーション速度 angle_y += 0.020 angle_x += 0.008 # 3次元回転と座標変換 transformed_points = [] for pt in base_points: x, y, z = pt # Y軸周りの回転 cos_y, sin_y = math.cos(angle_y), math.sin(angle_y) x1 = x * cos_y - z * sin_y z1 = x * sin_y + z * cos_y # X軸周りの回転 cos_x, sin_x = math.cos(angle_x), math.sin(angle_x) y2 = y * cos_x - z1 * sin_x z2 = y * sin_x + z1 * cos_x transformed_points.append((x1, y2, z2)) # Z値(奥行き)でソート transformed_points.sort(key=lambda p: p[2]) # 描画処理 for pt in transformed_points: tx, ty, tz = pt screen_x = int(tx + (WIDTH // 2) - (SPRITE_W // 2)) screen_y = int(ty + (HEIGHT // 2) - (SPRITE_H // 2)) screen.blit(sprite_image, (screen_x, screen_y)) # 画面更新 pygame.display.flip() # 3. clock.tick() の直後に「await asyncio.sleep(0)」を入れる # これがブラウザのハングアップ(フリーズ)を防ぐために必須です clock.tick(60) await asyncio.sleep(0) pygame.quit() sys.exit() # 4. スクリプトの実行部 if __name__ == "__main__": asyncio.run(main())