無題

Pasted Oct 30, 2026, 2:43 AM1 file169 lines

Scan to open on your phone

Point a camera at the QR code - it opens this exact paste, no app needed.

https://codepastes.com/zzgsgxm3471b13jk
無題
import pygame
import sys
import random
import math

# --- 設定 ---
SCREEN_WIDTH = 500
SCREEN_HEIGHT = 700
FPS = 60

# カラー定義 (数字が大きくなるほど色が変化)
COLORS = {
    2: (240, 128, 128),    # 薄赤
    4: (255, 165, 0),      # オレンジ
    8: (238, 232, 170),    # 黄
    16: (152, 251, 152),   # 緑
    32: (135, 206, 250),   # 青
    64: (186, 85, 211),    # 紫
    128: (255, 105, 180),  # ピンク
    256: (255, 0, 0)       # 赤
}

# 出現する基本の数字リスト
SPAWN_VALUES = [2, 4, 8]

# --- クラス定義 ---
class Blob:
    def __init__(self, x, y, value):
        self.x = x
        self.y = y
        self.value = value
        self.radius = int(math.log2(value)) * 8 + 12  # 値が大きいほどサイズアップ
        self.vy = 0  # 自由落下の速度
        self.is_dropped = False
        self.color = COLORS.get(value, (255, 255, 255))

    def update(self):
        if self.is_dropped:
            self.vy += 0.5  # 重力
            self.y += self.vy
            
            # 地面との衝突
            if self.y + self.radius > SCREEN_HEIGHT - 20:
                self.y = SCREEN_HEIGHT - 20 - self.radius
                self.vy = 0

    def draw(self, screen, font):
        # 本体を描画
        pygame.draw.circle(screen, self.color, (int(self.x), int(self.y)), self.radius)
        pygame.draw.circle(screen, (255, 255, 255), (int(self.x), int(self.y)), self.radius, 2)
        
        # 数字を描画
        text = font.render(str(self.value), True, (0, 0, 0))
        text_rect = text.get_rect(center=(int(self.x), int(self.y)))
        screen.blit(text, text_rect)

# --- メイン処理 ---
def main():
    pygame.init()
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    pygame.display.set_caption("sobosuba Like Merge Game")
    clock = pygame.time.Clock()
    font = pygame.font.SysFont(None, 24)

    score = 0
    blobs = []
    
    # 次に落とすBlobを生成(修正:SPAWN_VALUESを追加)
    current_blob = Blob(SCREEN_WIDTH // 2, 80, random.choice(SPAWN_VALUES))

    running = True
    while running:
        screen.fill((30, 30, 30))  # 背景(ダークグレー)

        # 上部の待機ライン・地面の描画
        pygame.draw.line(screen, (100, 100, 100), (0, 120), (SCREEN_WIDTH, 120), 2)
        pygame.draw.rect(screen, (50, 50, 50), (0, SCREEN_HEIGHT - 20, SCREEN_WIDTH, 20))

        # イベント処理
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            
            # マウス移動で投下位置を変更(落とす前のみ)
            if event.type == pygame.MOUSEMOTION and not current_blob.is_dropped:
                current_blob.x = max(current_blob.radius, min(event.pos[0], SCREEN_WIDTH - current_blob.radius))
            
            # クリックで落下開始
            if event.type == pygame.MOUSEBUTTONDOWN and not current_blob.is_dropped:
                current_blob.is_dropped = True
                blobs.append(current_blob)
                # 次のBlobをセット(修正:SPAWN_VALUESを追加)
                current_blob = Blob(event.pos[0], 80, random.choice(SPAWN_VALUES))

        # 移動制限(次のBlobが端に行き過ぎないように)
        if not current_blob.is_dropped:
            mx, _ = pygame.mouse.get_pos()
            current_blob.x = max(current_blob.radius, min(mx, SCREEN_WIDTH - current_blob.radius))
            current_blob.draw(screen, font)

        # 既存のBlobの更新と描画
        for blob in blobs:
            blob.update()
            
        # 衝突・マージ判定
        merged_blobs = []
        to_remove = set()

        for i in range(len(blobs)):
            if i in to_remove: continue
            for j in range(i + 1, len(blobs)):
                if j in to_remove: continue
                
                b1 = blobs[i]
                b2 = blobs[j]
                
                # 2つの円の距離を計算
                dist = math.hypot(b1.x - b2.x, b1.y - b2.y)
                min_dist = b1.radius + b2.radius
                
                if dist < min_dist:
                    # 同じ数字ならマージ
                    if b1.value == b2.value:
                        to_remove.add(i)
                        to_remove.add(j)
                        # 中間地点に新しいBlobを生成
                        new_x = (b1.x + b2.x) / 2
                        new_y = (b1.y + b2.y) / 2
                        new_value = b1.value * 2
                        score += new_value
                        
                        new_blob = Blob(new_x, new_y, new_value)
                        new_blob.is_dropped = True
                        merged_blobs.append(new_blob)
                        break
                    else:
                        # 違う数字なら、めり込まないように位置を押し返す(超簡易擬似物理)
                        overlap = min_dist - dist
                        angle = math.atan2(b2.y - b1.y, b2.x - b1.x)
                        if b2.is_dropped and b2.vy == 0:  # 下が固定されているなら上を押し上げる
                            b1.x -= math.cos(angle) * overlap
                            b1.y -= math.sin(angle) * overlap
                        else:
                            b2.x += math.cos(angle) * overlap / 2
                            b2.y += math.sin(angle) * overlap / 2
                            b1.x -= math.cos(angle) * overlap / 2
                            b1.y -= math.sin(angle) * overlap / 2

        # 削除と新規マージ分の適用
        blobs = [b for idx, b in enumerate(blobs) if idx not in to_remove]
        blobs.extend(merged_blobs)

        # 全て描画
        for blob in blobs:
            blob.draw(screen, font)

        # スコア表示
        score_text = font.render(f"SCORE: {score}", True, (255, 255, 255))
        screen.blit(score_text, (20, 20))

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

    pygame.quit()
    sys.exit()

if __name__ == "__main__":
    main()

5,561 chars · codepastes.com