Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # tk_gravity_repel.py
- from tkinter import *
- import math
- import random
- # Define constants
- NUM_POINTS = 50
- RADIUS = 5
- WIDTH = 500
- HEIGHT = 500
- GRAVITY_CONSTANT = 100 # Define the repelling gravity constant, enough to keep every circle from ever colliding
- MAX_SPEED = 4 # Define the maximum velocity change allowed
- DELAY = 50 # Define the delay between updates
- MIN_DISTANCE = 25 # Minimum distance between two circles
- STEER = 80
- # Initialize tkinter window
- root = Tk()
- root.title("Gravity Repel")
- canvas = Canvas(root, width=WIDTH, height=HEIGHT)
- canvas.pack()
- # Define function for calculating distance between two points
- def distance(x1, y1, x2, y2):
- return math.sqrt((x1 - x2)**2 + (y1 - y2)**2)
- # Define function for calculating the repelling force between nearest two points
- def repel_force(x1, y1, x2, y2, d):
- force = GRAVITY_CONSTANT / (d ** 2) + 3 # Calculate force using inverse square law
- angle = math.atan2(y2 - y1, x2 - x1) # Calculate angle between points
- return force * math.cos(angle) * -1, force * math.sin(angle) * -1 # Calculate x and y components of force
- # Create list of points with random locations and velocities
- points = []
- for i in range(NUM_POINTS):
- x = random.randint(RADIUS, WIDTH-RADIUS)
- y = random.randint(RADIUS, HEIGHT-RADIUS)
- angle = 2 * math.pi * random.random()
- speed = MAX_SPEED
- vx = speed * math.cos(angle)
- vy = speed * math.sin(angle)
- points.append({'x': x, 'y': y, 'vx': vx, 'vy': vy, 'speed': speed, 'lines': []})
- # Define function for updating the positions of the points
- def update_points():
- # Find nearest neighbors using sorted points list
- canvas.delete('line')
- did = set()
- sorted_x = sorted(points, key=lambda p: p['x'])
- sorted_y = sorted(points, key=lambda p: p['y'])
- for i, point in enumerate(points):
- min_dist = 9999999999
- others = []
- for ppp in (sorted_x, sorted_y):
- iii = ppp.index(point)
- for j in (iii-1, iii+1):
- try:
- others.append(ppp[j])
- except:
- 0
- for other in others:
- d = distance(point['x'], point['y'], other['x'], other['y']) # Calculate the distance between the two circles
- if d < min_dist:
- min_dist = d
- nearest = other
- # Move point
- point['x'] += point['vx']
- point['y'] += point['vy']
- # Apply repelling force from walls
- if not (RADIUS < point['x'] < WIDTH - RADIUS and RADIUS < point['y'] < HEIGHT - RADIUS):
- # Apply attracting force towards dead center
- cx = WIDTH / 2
- cy = HEIGHT / 2
- dx = cx - point['x']
- dy = cy - point['y']
- dist = distance(point['x'], point['y'], cx, cy)
- angle = math.atan2(-dy, -dx) # Calculate angle between point and center
- point['vx'] += MAX_SPEED * math.cos(angle) * -1 # Apply force in x direction
- point['vy'] += MAX_SPEED * math.sin(angle) * -1 # Apply force in y direction
- else:
- try:
- # Update velocities based on repelling force and steering force
- repel_x, repel_y = repel_force(point['x'], point['y'], nearest['x'], nearest['y'], min_dist)
- point['vx'] += repel_x
- point['vy'] += repel_y
- point['vx'] = (point['vx'] + (nearest['x'] - point['x']) / STEER) / 2
- point['vy'] = (point['vy'] + (nearest['y'] - point['y']) / STEER) / 2
- except:
- 0
- # Keep velocity changes within maximum limit
- speed = MAX_SPEED / math.sqrt(point['vx']**2 + point['vy']**2)
- point['vx'] *= speed
- point['vy'] *= speed
- # Redraw point on canvas
- canvas.coords(point['circle'], point['x']-RADIUS, point['y']-RADIUS, point['x']+RADIUS, point['y']+RADIUS)
- if min_dist < MIN_DISTANCE * 2 + RADIUS:
- if not any(t in did for t in (id(point), id(nearest))):
- did.update([id(point), id(nearest)])
- # Update lines between points
- line = canvas.create_line(point['x'], point['y'], nearest['x'], nearest['y'], width=5, fill='lightgreen', tags='line')
- canvas.lower(line)
- # Call this function again after a delay
- root.after(DELAY, update_points)
- # Create circles on canvas for each point
- for point in points:
- point['circle'] = canvas.create_oval(point['x']-RADIUS, point['y']-RADIUS, point['x']+RADIUS, point['y']+RADIUS, fill='yellow')
- # Start animation loop
- update_points()
- root.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement