CCCPaste

# tk_text2physics.py

# tk_text2physics.py

import tkinter as tk
import random
import math

root = tk.Tk()
root.title("# tk_text2physics")
canvas = tk.Canvas(root, width=600, height=600, bg='#333333')
canvas.pack()

letters_x = []
letters_y = []
letters_vx = []
letters_vy = []
letters_angle = []
letters_av = []
letters_char = []
letter_chars = list("QWERTYUIOPASDFGHJKLZXCVBNM1234567890")

def apply_force(i, fx, fy):
    letters_vx[i] += fx
    letters_vy[i] += fy

def update_letter(i):
    letters_vy[i] += 0.5
    letters_x[i] += letters_vx[i]
    letters_y[i] += letters_vy[i]
    letters_angle[i] += letters_av[i]
    letters_vx[i] *= 0.98
    letters_vy[i] *= 0.98
    letters_av[i] *= 0.92
    
    if abs(letters_vx[i]) < 0.01:
        letters_vx[i] = 0
    if abs(letters_vy[i]) < 0.01:
        letters_vy[i] = 0
    if abs(letters_av[i]) < 0.001:
        letters_av[i] = 0
    
    if letters_y[i] > 570:
        letters_y[i] = 570
        if abs(letters_vy[i]) < 0.5:
            letters_vy[i] = 0
        else:
            letters_vy[i] *= -0.4
        letters_av[i] = letters_av[i] * 0.4 + letters_vx[i] * 0.05
        
    if letters_x[i] < 30:
        letters_x[i] = 30
        letters_vx[i] *= -0.4
        letters_av[i] *= 0.6
    if letters_x[i] > 570:
        letters_x[i] = 570
        letters_vx[i] *= -0.4
        letters_av[i] *= 0.6

def check_collision(i, j):
    dx = letters_x[j] - letters_x[i]
    dy = letters_y[j] - letters_y[i]
    dist = math.sqrt(dx*dx + dy*dy)
    
    if dist < 40 and dist > 0:
        nx = dx / dist
        ny = dy / dist
        
        dvx = letters_vx[j] - letters_vx[i]
        dvy = letters_vy[j] - letters_vy[i]
        
        dot = dvx * nx + dvy * ny
        
        if dot < 0:
            impulse = -1.2 * dot / 2
            
            letters_vx[i] -= impulse * nx
            letters_vy[i] -= impulse * ny
            letters_vx[j] += impulse * nx
            letters_vy[j] += impulse * ny
            
            tangent_vel_i = -ny * letters_vx[i] + nx * letters_vy[i]
            tangent_vel_j = -ny * letters_vx[j] + nx * letters_vy[j]
            
            torque_i = tangent_vel_j * 0.015
            torque_j = tangent_vel_i * 0.015
            
            letters_av[i] += torque_i
            letters_av[j] += torque_j
            
            letters_av[i] *= 0.7
            letters_av[j] *= 0.7
            
            overlap = 40 - dist
            
            if letters_y[i] < letters_y[j]:
                letters_y[i] -= 3
            else:
                letters_y[j] -= 3
            
            letters_x[i] -= nx * overlap * 0.5
            letters_y[i] -= ny * overlap * 0.5
            letters_x[j] += nx * overlap * 0.5
            letters_y[j] += ny * overlap * 0.5

def attract_letters():
    for i in range(len(letters_x)):
        for j in range(i+1, len(letters_x)):
            dx = letters_x[j] - letters_x[i]
            dy = letters_y[j] - letters_y[i]
            dist = math.sqrt(dx*dx + dy*dy)
            
            if dist > 0 and dist < 150:
                force = 0.02 / (dist * dist + 1)
                fx = (dx / dist) * force
                fy = (dy / dist) * force
                
                apply_force(i, fx, fy)
                apply_force(j, -fx, -fy)

def update():
    canvas.delete('all')
    
    attract_letters()
    
    for i in range(len(letters_x)):
        update_letter(i)
        
    for i in range(len(letters_x)):
        for j in range(i+1, len(letters_x)):
            check_collision(i, j)
    
    for i in range(len(letters_x)):
        canvas.create_text(letters_x[i], letters_y[i], text=letters_char[i], 
                          font=('Arial', 50, 'bold'),
                          fill='white', angle=math.degrees(letters_angle[i]))
    
    root.after(16, update)

def spawn_letter():
    if len(letters_x) < len(letter_chars):
        letters_x.append(random.randint(50, 550))
        letters_y.append(-20)
        letters_vx.append(0)
        letters_vy.append(0)
        letters_angle.append(0)
        letters_av.append(0)
        letters_char.append(letter_chars[len(letters_x) - 1])
        root.after(500, spawn_letter)

def reset(event):
    letters_x.clear()
    letters_y.clear()
    letters_vx.clear()
    letters_vy.clear()
    letters_angle.clear()
    letters_av.clear()
    letters_char.clear()

root.bind('', reset)

spawn_letter()
update()
root.mainloop()