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("", 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()