# 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()