Advertisement
Guest User

Untitled

a guest
Jan 24th, 2025
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.88 KB | Source Code | 0 0
  1. import pygame
  2. import math
  3.  
  4. # Initialize pygame
  5. pygame.init()
  6.  
  7. # Screen dimensions
  8. width, height = 800, 600
  9. screen = pygame.display.set_mode((width, height))
  10. pygame.display.set_caption("Spinning Triangle with Bouncing Ball")
  11.  
  12. # Colors
  13. black = (0, 0, 0)
  14. white = (255, 255, 255)
  15. red = (255, 0, 0)
  16.  
  17. # Triangle vertices (initial, equilateral triangle centered)
  18. triangle_size = 150
  19. triangle_points = [
  20. [0, -triangle_size],
  21. [triangle_size * math.sqrt(3) / 2, triangle_size / 2],
  22. [-triangle_size * math.sqrt(3) / 2, triangle_size / 2]
  23. ]
  24.  
  25. # Calculate centroid of the triangle
  26. centroid_x = sum(p[0] for p in triangle_points) / 3
  27. centroid_y = sum(p[1] for p in triangle_points) / 3
  28. centroid = [centroid_x, centroid_y]
  29.  
  30. # Function to rotate a point around the centroid
  31. def rotate_point(point, angle, center):
  32. """Rotates a point around a center by a given angle in radians."""
  33. px, py = point
  34. cx, cy = center
  35. angle_rad = math.radians(angle)
  36. rotated_x = math.cos(angle_rad) * (px - cx) - math.sin(angle_rad) * (py - cy) + cx
  37. rotated_y = math.sin(angle_rad) * (px - cx) + math.cos(angle_rad) * (py - cy) + cy
  38. return [rotated_x, rotated_y]
  39.  
  40. # Ball properties
  41. ball_radius = 15
  42. ball_color = red
  43. ball_pos = [0, 0] # Start at centroid initially
  44. ball_speed = 3
  45. ball_velocity = [ball_speed, ball_speed] # Initial velocity
  46.  
  47. # Rotation speed of the triangle
  48. rotation_speed = 0.5 # degrees per frame
  49. rotation_angle = 0
  50.  
  51. def is_point_in_triangle(point, triangle_vertices):
  52. """Checks if a point is inside a triangle using barycentric coordinates."""
  53. x, y = point
  54. x1, y1 = triangle_vertices[0]
  55. x2, y2 = triangle_vertices[1]
  56. x3, y3 = triangle_vertices[2]
  57.  
  58. denominator = (y2 - y3) * (x1 - x3) + (x3 - x2) * (y1 - y3)
  59. if denominator == 0: return False # Triangle is degenerate
  60.  
  61. a = ((y2 - y3) * (x - x3) + (x3 - x2) * (y - y3)) / denominator
  62. b = ((y3 - y1) * (x - x3) + (x1 - x3) * (y - y3)) / denominator
  63. c = 1 - a - b
  64.  
  65. return 0 <= a <= 1 and 0 <= b <= 1 and 0 <= c <= 1
  66.  
  67. def distance_point_to_segment(point, segment_p1, segment_p2):
  68. """Calculates the shortest distance from a point to a line segment."""
  69. px, py = point
  70. x1, y1 = segment_p1
  71. x2, y2 = segment_p2
  72.  
  73. l2 = (x1 - x2)**2 + (y1 - y2)**2
  74. if l2 == 0: return math.sqrt((px - x1)**2 + (py - y1)**2) # p1 == p2 case
  75.  
  76. t = ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / l2
  77. t = max(0, min(1, t)) # Clamp t to be within the segment [0, 1]
  78.  
  79. closest_x = x1 + t * (x2 - x1)
  80. closest_y = y1 + t * (y2 - y1)
  81.  
  82. return math.sqrt((px - closest_x)**2 + (py - closest_y)**2), [closest_x, closest_y]
  83.  
  84.  
  85. def reflect_velocity(ball_pos, ball_velocity, segment_p1, segment_p2):
  86. """Reflects the ball's velocity off a line segment."""
  87. x1, y1 = segment_p1
  88. x2, y2 = segment_p2
  89.  
  90. # Vector representing the segment
  91. segment_vector_x = x2 - x1
  92. segment_vector_y = y2 - y1
  93.  
  94. # Normal vector to the segment (normalized)
  95. normal_x = -segment_vector_y
  96. normal_y = segment_vector_x
  97. norm = math.sqrt(normal_x**2 + normal_y**2)
  98. normal_x /= norm
  99. normal_y /= norm
  100.  
  101. # Dot product of velocity and normal
  102. dot_product = ball_velocity[0] * normal_x + ball_velocity[1] * normal_y
  103.  
  104. # Reflection formula: v_reflected = v - 2 * (v . n) * n
  105. reflected_velocity_x = ball_velocity[0] - 2 * dot_product * normal_x
  106. reflected_velocity_y = ball_velocity[1] - 2 * dot_product * normal_y
  107.  
  108. return [reflected_velocity_x, reflected_velocity_y]
  109.  
  110.  
  111. # Game loop
  112. running = True
  113. clock = pygame.time.Clock()
  114.  
  115. while running:
  116. for event in pygame.event.get():
  117. if event.type == pygame.QUIT:
  118. running = False
  119.  
  120. # Rotate the triangle
  121. rotated_triangle_points = [rotate_point(p, rotation_angle, centroid) for p in triangle_points]
  122. rotation_angle += rotation_speed
  123.  
  124. # Move the ball
  125. ball_pos[0] += ball_velocity[0]
  126. ball_pos[1] += ball_velocity[1]
  127.  
  128. # Collision detection with triangle edges
  129. collided = False
  130. for i in range(3):
  131. p1 = rotated_triangle_points[i]
  132. p2 = rotated_triangle_points[(i + 1) % 3]
  133. distance, closest_point = distance_point_to_segment(ball_pos, p1, p2)
  134.  
  135. if distance <= ball_radius:
  136. ball_velocity = reflect_velocity(ball_pos, ball_velocity, p1, p2)
  137. collided = True
  138. # Slightly move ball out of collision to prevent sticking
  139. push_out_vector_x = ball_pos[0] - closest_point[0]
  140. push_out_vector_y = ball_pos[1] - closest_point[1]
  141. push_out_norm = max(distance, 1e-9) # Avoid division by zero if distance is zero
  142. ball_pos[0] += push_out_vector_x * (ball_radius - distance + 0.1) / push_out_norm
  143. ball_pos[1] += push_out_vector_y * (ball_radius - distance + 0.1) / push_out_norm
  144. break # Only reflect off one edge at a time per frame for simplicity
  145.  
  146.  
  147. # Keep ball inside triangle (as a fallback, although collision should handle this)
  148. if not is_point_in_triangle(ball_pos, rotated_triangle_points):
  149. # If somehow ball gets outside, reposition it to centroid and reverse velocity (basic fix)
  150. ball_pos = [0, 0] # Reset to centroid - you could do something smarter
  151. ball_velocity[0] *= -1
  152. ball_velocity[1] *= -1
  153.  
  154.  
  155. # Clear the screen
  156. screen.fill(black)
  157.  
  158. # Draw the spinning triangle
  159. triangle_screen_points = [
  160. (int(p[0] + width / 2), int(p[1] + height / 2)) for p in rotated_triangle_points
  161. ]
  162. pygame.draw.polygon(screen, white, triangle_screen_points, 2) # Draw triangle outline
  163.  
  164. # Draw the bouncing ball
  165. pygame.draw.circle(screen, ball_color, (int(ball_pos[0] + width / 2), int(ball_pos[1] + height / 2)), ball_radius)
  166.  
  167. # Update the display
  168. pygame.display.flip()
  169.  
  170. # Control frame rate
  171. clock.tick(60)
  172.  
  173. pygame.quit()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement