Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import tkinter as tk
- import math
- import random
- import colorsys
- BALL_COUNT = 1000
- SPEED_RANGE = (1, 4)
- RADIUS_RANGE = (5, 15)
- root = tk.Tk()
- root.title("Мячики")
- root.geometry("800x600")
- root.resizable(False, False)
- canvas = tk.Canvas(root, bg="white", width=800, height=600)
- canvas.pack()
- target_x, target_y = 400, 300
- storage = []
- balls = []
- is_sucking = False
- is_blowing = False
- is_repelling = False
- canvas.bind("<Motion>", lambda e: update_target(e))
- canvas.bind("<ButtonPress-1>", lambda e: set_flag("blow", True))
- canvas.bind("<ButtonRelease-1>", lambda e: set_flag("blow", False))
- canvas.bind("<ButtonPress-2>", lambda e: set_flag("repel", True))
- canvas.bind("<ButtonRelease-2>", lambda e: set_flag("repel", False))
- canvas.bind("<ButtonPress-3>", lambda e: set_flag("suck", True))
- canvas.bind("<ButtonRelease-3>", lambda e: set_flag("suck", False))
- def set_flag(action, value):
- global is_sucking, is_blowing, is_repelling
- if action == "suck":
- is_sucking = value
- elif action == "blow":
- is_blowing = value
- elif action == "repel":
- is_repelling = value
- 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
- def update_storage_text():
- canvas.itemconfig(storage_text, text=f"Storage: {len(storage)}")
- def suck_nearby(cx, cy):
- global storage
- for ball in balls[:]:
- dx = ball["x"] - cx
- dy = ball["y"] - cy
- dist = math.hypot(dx, dy)
- if dist < 20 and len(storage) < BALL_COUNT:
- canvas.delete(ball["id"])
- balls.remove(ball)
- storage.append(ball)
- update_storage_text()
- def blow_from_storage(cx, cy):
- global storage
- for _ in range(min(len(storage), 5)):
- ball = storage.pop()
- r = ball["r"]
- x = cx + random.randint(-30, 30)
- y = cy + random.randint(-30, 30)
- color = pastel_color()
- ball_id = canvas.create_oval(x - r, y - r, x + r, y + r, fill=color, outline="")
- ball.update({
- "x": x,
- "y": y,
- "vx": random.uniform(-3, 3),
- "vy": random.uniform(-3, 3),
- "id": ball_id,
- "color": color,
- "repel_timer": 20,
- })
- balls.append(ball)
- update_storage_text()
- 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
- 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,
- })
- storage_text = canvas.create_text(790, 20, text="Storage: 0", anchor="ne", font=("Arial", 12), fill="black")
- def move_balls():
- if is_sucking:
- suck_nearby(target_x, target_y)
- if is_blowing:
- blow_from_storage(target_x, target_y)
- if is_repelling:
- repel_balls(target_x, target_y)
- 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()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement