Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import math
- import tkinter as tk
- import time
- class Ball:
- def __init__(self, x, y, vx, vy, radius, color, number, angular_velocity):
- self.x = x
- self.y = y
- self.vx = vx
- self.vy = vy
- self.radius = radius
- self.color = color
- self.number = number
- self.angular_velocity = angular_velocity
- self.theta = 0.0
- def closest_point_on_segment(px, py, x1, y1, x2, y2):
- vx = x2 - x1
- vy = y2 - y1
- wx = px - x1
- wy = py - y1
- dot = vx * wx + vy * wy
- len2 = vx * vx + vy * vy
- if len2 == 0:
- return (x1, y1), math.sqrt(wx * wx + wy * wy)
- t = max(0.0, min(1.0, dot / len2))
- cx = x1 + t * vx
- cy = y1 + t * vy
- dx = px - cx
- dy = py - cy
- d = math.sqrt(dx * dx + dy * dy)
- return (cx, cy), d
- def main():
- R = 300
- num_sides = 7
- vertices = []
- for i in range(num_sides):
- angle = i * 2 * math.pi / num_sides
- x = R * math.cos(angle)
- y = R * math.sin(angle)
- vertices.append((x, y))
- midpoints = []
- for i in range(num_sides):
- mid_x = (vertices[i][0] + vertices[(i + 1) % num_sides][0]) / 2
- mid_y = (vertices[i][1] + vertices[(i + 1) % num_sides][1]) / 2
- midpoints.append((mid_x, mid_y))
- normals = []
- for mid in midpoints:
- mag = math.sqrt(mid[0] * mid[0] + mid[1] * mid[1])
- nx = mid[0] / mag
- ny = mid[1] / mag
- normals.append((nx, ny))
- colors = [
- "#f8b862", "#f6ad49", "#f39800", "#f08300", "#ec6d51", "#ee7948", "#ed6d3d",
- "#ec6800", "#ec6800", "#ee7800", "#eb6238", "#ea5506", "#ea5506", "#eb6101",
- "#e49e61", "#e45e32", "#e17b34", "#dd7a56", "#db8449", "#d66a35"
- ]
- balls = []
- ball_radius = 15
- # Slightly offset initial positions in a small circle
- for i in range(20):
- angle = i * 2 * math.pi / 20
- offset_x = 0.5 * math.cos(angle)
- offset_y = 0.5 * math.sin(angle)
- angular_velocity = 0.1
- balls.append(Ball(offset_x, offset_y, 0.0, -0.1, ball_radius, colors[i], i + 1, angular_velocity))
- root = tk.Tk()
- root.title("Bouncing Balls in Rotating Heptagon")
- canvas = tk.Canvas(root, width=800, height=800, bg='white')
- canvas.pack()
- dt = 0.01
- angular_velocity_heptagon = 2 * math.pi / 5.0
- start_time = time.time()
- def draw_heptagon():
- current_time = time.time()
- elapsed = current_time - start_time
- angle = (angular_velocity_heptagon * elapsed) % (2 * math.pi)
- rotated_vertices = []
- for (x, y) in vertices:
- new_x = x * math.cos(angle) - y * math.sin(angle)
- new_y = x * math.sin(angle) + y * math.cos(angle)
- rotated_vertices.append((new_x, new_y))
- points = []
- for (x, y) in rotated_vertices:
- points.append(x + 400)
- points.append(y + 400)
- canvas.create_polygon(points, outline='black', fill='', width=2)
- def draw_ball(ball):
- x = ball.x + 400
- y = ball.y + 400
- canvas.create_oval(x - ball.radius, y - ball.radius, x + ball.radius, y + ball.radius, fill=ball.color, outline='black')
- canvas.create_text(x, y, text=str(ball.number), font=('Arial', 12, 'bold'), fill='black')
- while True:
- current_time = time.time()
- elapsed = current_time - start_time
- angle = (angular_velocity_heptagon * elapsed) % (2 * math.pi)
- for ball in balls:
- ball.vy += 100.0 * dt
- ball.x += ball.vx * dt
- ball.y += ball.vy * dt
- ball.angular_velocity *= (1.0 - 0.01 * dt)
- ball.theta += ball.angular_velocity * dt
- for ball in balls:
- for edge_index in range(num_sides):
- v1 = vertices[edge_index]
- v2 = vertices[(edge_index + 1) % num_sides]
- closest, d = closest_point_on_segment(ball.x, ball.y, v1[0], v1[1], v2[0], v2[1])
- if d < ball.radius:
- nx, ny = normals[edge_index]
- normal = (-nx, -ny)
- relative_vel = ball.vx * normal[0] + ball.vy * normal[1]
- if relative_vel > 0:
- continue
- restitution = 0.1
- j = -(1 + restitution) * relative_vel
- ball.vx += j * normal[0]
- ball.vy += j * normal[1]
- penetration = ball.radius - d
- ball.x += penetration * normal[0]
- ball.y += penetration * normal[1]
- for i in range(len(balls)):
- for j in range(i + 1, len(balls)):
- ball1 = balls[i]
- ball2 = balls[j]
- dx = ball2.x - ball1.x
- dy = ball2.y - ball1.y
- dist = math.sqrt(dx * dx + dy * dy)
- if dist < ball1.radius + ball2.radius:
- if dist < 1e-5: # Prevent division by zero
- dist = 1e-5
- nx = dx / dist
- ny = dy / dist
- dvx = ball2.vx - ball1.vx
- dvy = ball2.vy - ball1.vy
- dv_normal = dvx * nx + dvy * ny
- if dv_normal < 0:
- restitution = 0.2
- j = -(1 + restitution) * dv_normal
- ball1.vx -= j * nx
- ball1.vy -= j * ny
- ball2.vx += j * nx
- ball2.vy += j * ny
- overlap = ball1.radius + ball2.radius - dist
- ball1.x -= overlap * nx * 0.5
- ball1.y -= overlap * ny * 0.5
- ball2.x += overlap * nx * 0.5
- ball2.y += overlap * ny * 0.5
- canvas.delete("all")
- draw_heptagon()
- for ball in balls:
- draw_ball(ball)
- root.update()
- time.sleep(0.001)
- if __name__ == "__main__":
- main()
Advertisement
Add Comment
Please, Sign In to add comment