import tkinter as tk import math import random import colorsys BALL_COUNT = 500 SPEED_RANGE = (1, 4) RADIUS_RANGE = (5, 15) root = tk.Tk() root.geometry("800x600") root.title("Пастельные мячики") canvas = tk.Canvas(root, bg="white") canvas.pack(fill=tk.BOTH, expand=True) target_x, target_y = 300, 200 canvas.bind("", lambda e: update_target(e)) canvas.bind("", lambda e: repel_balls(e.x, e.y)) balls = [] def pastel_color(): h = random.random() s = 0.4 # низкая насыщенность v = 0.95 # высокая яркость r, g, b = colorsys.hsv_to_rgb(h, s, v) return f"#{int(r*255):02x}{int(g*255):02x}{int(b*255):02x}" def update_target(event): global target_x, target_y target_x = event.x target_y = event.y for _ in range(BALL_COUNT): r = random.randint(*RADIUS_RANGE) x = random.randint(r, 800 - r) y = random.randint(r, 600 - r) color = pastel_color() speed = random.uniform(*SPEED_RANGE) ball_id = canvas.create_oval(x - r, y - r, x + r, y + r, fill=color, outline="") balls.append({ "x": x, "y": y, "vx": 0, "vy": 0, "r": r, "speed": speed, "id": ball_id, "color": color, "repel_timer": 0, }) def repel_balls(cx, cy): for ball in balls: dx = ball["x"] - cx dy = ball["y"] - cy dist = math.hypot(dx, dy) + 0.01 if dist < 200: force = 12 / dist ball["vx"] += force * dx ball["vy"] += force * dy ball["repel_timer"] = 20 def move_balls(): for ball in balls: if ball["repel_timer"] > 0: ball["x"] += ball["vx"] ball["y"] += ball["vy"] ball["vx"] *= 0.9 ball["vy"] *= 0.9 ball["repel_timer"] -= 1 else: dx = target_x - ball["x"] dy = target_y - ball["y"] dist = math.hypot(dx, dy) if dist > 1: step_x = ball["speed"] * dx / dist step_y = ball["speed"] * dy / dist ball["x"] += step_x ball["y"] += step_y r = ball["r"] canvas.coords(ball["id"], ball["x"] - r, ball["y"] - r, ball["x"] + r, ball["y"] + r) root.after(16, move_balls) move_balls() root.mainloop()