123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
import tkinter as tk
import math
import random
from dataclasses import dataclass
from typing import List, Tuple
@dataclass
class Fragment:
x: float
y: float
vx: float
vy: float
radius: float
color: str
rotation: float = 0.0
angular_velocity: float = 0.0
is_seed: bool = False
class WatermelonSplash:
def __init__(self, root):
self.root = root
self.root.title("Watermelon Splash Simulation Tk")
self.width = 800
self.height = 800
self.ground_y = 700
self.canvas = tk.Canvas(root, width=self.width, height=self.height, bg="sky blue")
self.canvas.pack()
self.gravity = 0.5
self.friction = 0.02
self.air_resistance = 0.01
self.watermelon = {
"x": self.width // 2,
"y": 100,
"radius": 40,
"vx": 0,
"vy": 0,
"color": "green",
"splat": False
}
self.fragments: List[Fragment] = []
self.particles: List[Fragment] = []
self.draw_ground()
self.draw_watermelon()
self.running = True
self.root.after(10, self.update)
self.canvas.bind("<Button-1>", self.reset_simulation)
def draw_ground(self):
self.canvas.create_rectangle(0, self.ground_y, self.width, self.height,
fill="sandy brown", outline="")
# Add some texture to the ground
for _ in range(50):
x = random.randint(0, self.width)
y = random.randint(self.ground_y, self.height)
size = random.randint(1, 3)
self.canvas.create_oval(x, y, x+size, y+size, fill="peru", outline="")
def draw_watermelon(self):
if self.watermelon["splat"]:
return
x, y = self.watermelon["x"], self.watermelon["y"]
r = self.watermelon["radius"]
# Draw watermelon (ellipse with stripes)
self.canvas.create_oval(x-r, y-r, x+r, y+r,
fill=self.watermelon["color"], outline="black")
# Add watermelon stripes
for i in range(-r, r, 5):
self.canvas.create_line(x+i, y-r, x+i, y+r, fill="dark green", width=2)
# Draw inner red part (smaller ellipse)
inner_r = r * 0.7
self.canvas.create_oval(x-inner_r, y-inner_r, x+inner_r, y+inner_r,
fill="red", outline="")
# Draw some seeds
for _ in range(8):
seed_x = x + random.randint(-int(inner_r*0.8), int(inner_r*0.8))
seed_y = y + random.randint(-int(inner_r*0.8), int(inner_r*0.8))
if math.sqrt((seed_x-x)**2 + (seed_y-y)**2) < inner_r:
self.canvas.create_oval(seed_x-2, seed_y-1, seed_x+2, seed_y+1,
fill="black", outline="")
def draw_fragments(self):
for frag in self.fragments + self.particles:
if frag.is_seed:
# Draw seed (black oval)
self.canvas.create_oval(
frag.x-2, frag.y-1, frag.x+2, frag.y+1,
fill="black", outline=""
)
else:
# Draw watermelon fragment
points = []
for i in range(6): # Create a hexagon shape
angle = frag.rotation + i * (2 * math.pi / 6)
px = frag.x + frag.radius * math.cos(angle)
py = frag.y + frag.radius * math.sin(angle)
points.extend([px, py])
self.canvas.create_polygon(
*points,
fill="red" if frag.color == "green" else frag.color,
outline="black" if frag.color == "green" else ""
)
def update(self):
if not self.running:
return
self.canvas.delete("all")
self.draw_ground()
# Update watermelon physics
if not self.watermelon["splat"]:
self.watermelon["vy"] += self.gravity
self.watermelon["y"] += self.watermelon["vy"]
# Check for ground collision
if self.watermelon["y"] + self.watermelon["radius"] >= self.ground_y:
self.watermelon["splat"] = True
self.create_splash()
# Update fragments
new_fragments = []
for frag in self.fragments:
# Apply gravity
frag.vy += self.gravity
# Apply air resistance
frag.vx *= (1 - self.air_resistance)
frag.vy *= (1 - self.air_resistance)
# Update position
frag.x += frag.vx
frag.y += frag.vy
# Update rotation
frag.rotation += frag.angular_velocity
# Check for ground collision
if frag.y + frag.radius >= self.ground_y:
frag.y = self.ground_y - frag.radius
frag.vy = -frag.vy * 0.4 # Bounce with energy loss
frag.vx *= 0.8 # Friction
# Keep fragment if it's still moving significantly
if (abs(frag.vx) > 0.1 or abs(frag.vy) > 0.1 or
frag.y + frag.radius < self.ground_y - 5):
new_fragments.append(frag)
else:
# Create some particles when fragment comes to rest
if not frag.is_seed:
self.create_rest_particles(frag.x, frag.y)
self.fragments = new_fragments
# Update particles
new_particles = []
for p in self.particles:
p.vy += self.gravity * 0.2 # Particles are lighter
p.vx *= (1 - self.air_resistance * 2)
p.vy *= (1 - self.air_resistance * 2)
p.x += p.vx
p.y += p.vy
# Particles disappear when they hit the ground or after some time
if p.y + p.radius < self.ground_y and p.radius > 0.2:
p.radius *= 0.95 # Shrink over time
new_particles.append(p)
self.particles = new_particles
# Draw everything
if not self.watermelon["splat"]:
self.draw_watermelon()
self.draw_fragments()
# Continue animation
self.root.after(16, self.update)
def create_splash(self):
x, y = self.watermelon["x"], self.watermelon["y"]
r = self.watermelon["radius"]
# Create fragments from the watermelon
num_fragments = 15
for _ in range(num_fragments):
angle = random.uniform(0, 2 * math.pi)
speed = random.uniform(2, 8)
fragment_r = random.uniform(r*0.2, r*0.4)
self.fragments.append(Fragment(
x=x + random.uniform(-r*0.5, r*0.5),
y=y + random.uniform(-r*0.5, r*0.5),
vx=math.cos(angle) * speed,
vy=math.sin(angle) * speed - 2, # Slight upward force
radius=fragment_r,
color="green" if random.random() < 0.3 else "red",
angular_velocity=random.uniform(-0.2, 0.2)
))
# Create seeds
num_seeds = 10
for _ in range(num_seeds):
angle = random.uniform(0, 2 * math.pi)
speed = random.uniform(4, 10)
self.fragments.append(Fragment(
x=x + random.uniform(-r*0.7, r*0.7),
y=y + random.uniform(-r*0.7, r*0.7),
vx=math.cos(angle) * speed,
vy=math.sin(angle) * speed - 1,
radius=2,
color="black",
angular_velocity=random.uniform(-0.5, 0.5),
is_seed=True
))
# Create splash particles
for _ in range(30):
angle = random.uniform(0, 2 * math.pi)
speed = random.uniform(1, 5)
self.particles.append(Fragment(
x=x,
y=y,
vx=math.cos(angle) * speed,
vy=math.sin(angle) * speed,
radius=random.uniform(2, 5),
color=random.choice(["red", "pink", "light green"])
))
def create_rest_particles(self, x, y):
for _ in range(5):
angle = random.uniform(0, 2 * math.pi)
speed = random.uniform(0.5, 2)
self.particles.append(Fragment(
x=x,
y=y,
vx=math.cos(angle) * speed,
vy=math.sin(angle) * speed,
radius=random.uniform(1, 3),
color=random.choice(["red", "pink"])
))
def reset_simulation(self, event):
self.watermelon = {
"x": self.width // 2,
"y": 100,
"radius": 40,
"vx": 0,
"vy": 0,
"color": "green",
"splat": False
}
self.fragments = []
self.particles = []
if not self.running:
self.running = True
self.update()
if __name__ == "__main__":
root = tk.Tk()
app = WatermelonSplash(root)
root.mainloop()