Advertisement
Guest User

Untitled

a guest
Jan 27th, 2025
18
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.46 KB | None | 0 0
  1. # fixed issues ball running out of the square after 30s, added collision detection (Collision Print Statements), comment line 112 with '#' to disable
  2. import pygame
  3. import math
  4.  
  5. # Initialize Pygame
  6. pygame.init()
  7.  
  8. # Screen dimensions
  9. screen_width = 800
  10. screen_height = 600
  11. screen = pygame.display.set_mode((screen_width, screen_height))
  12. pygame.display.set_caption("Bouncing Yellow Ball in Rotating Square")
  13.  
  14. # Colors
  15. black = (0, 0, 0)
  16. white = (255, 255, 255)
  17. yellow = (255, 255, 0)
  18. light_gray = (200, 200, 200)
  19.  
  20. # Ball properties
  21. ball_radius = 20
  22. ball_x = screen_width // 2
  23. ball_y = screen_height // 2
  24. ball_speed_x = 5
  25. ball_speed_y = 3
  26.  
  27. # Square properties
  28. square_size = 300
  29. square_center_x = screen_width // 2
  30. square_center_y = screen_height // 2
  31. square_rotation_angle = 0
  32. #square_rotation_speed = 0.0 # Degrees per frame - Rotation Disabled
  33. square_rotation_speed = 0.5 # Degrees per frame
  34.  
  35. # Function to rotate a point around a center
  36. def rotate_point(point, center, angle_degrees):
  37. angle_radians = math.radians(angle_degrees)
  38. cos_theta = math.cos(angle_radians)
  39. sin_theta = math.sin(angle_radians)
  40. x = point[0] - center[0]
  41. y = point[1] - center[1]
  42. rotated_x = x * cos_theta - y * sin_theta
  43. rotated_y = x * sin_theta + y * cos_theta
  44. return [rotated_x + center[0], rotated_y + center[1]]
  45.  
  46. # Function to get square vertices based on rotation
  47. def get_square_vertices(center_x, center_y, size, angle):
  48. half_size = size / 2
  49. vertices = [
  50. [-half_size, -half_size],
  51. [half_size, -half_size],
  52. [half_size, half_size],
  53. [-half_size, half_size]
  54. ]
  55. rotated_vertices = []
  56. for vertex in vertices:
  57. rotated_vertices.append(rotate_point([vertex[0] + center_x, vertex[1] + center_y], [center_x, center_y], angle))
  58. return rotated_vertices
  59.  
  60. # Function to check collision with a square edge and bounce (more robust and no sticking)
  61. def check_square_collision_and_bounce(ball_x, ball_y, ball_radius, ball_speed_x, ball_speed_y, vertices):
  62. next_ball_x = ball_x + ball_speed_x
  63. next_ball_y = ball_y + ball_speed_y
  64. new_ball_speed_x = ball_speed_x
  65. new_ball_speed_y = ball_speed_y
  66.  
  67. for i in range(4):
  68. p1 = vertices[i]
  69. p2 = vertices[(i + 1) % 4]
  70.  
  71. dx = p2[0] - p1[0]
  72. dy = p2[1] - p1[1]
  73.  
  74. # Vector from p1 to ball center
  75. ball_vec_x = next_ball_x - p1[0]
  76. ball_vec_y = next_ball_y - p1[1]
  77.  
  78. # Project ball vector onto edge normal (normalized perpendicular vector)
  79. edge_length_sq = dx*dx + dy*dy
  80. if edge_length_sq == 0: # Handle degenerate edge
  81. continue
  82.  
  83. normal_x = dy # Swapped sign with dy patch #3: Corrected Normal Calculation - Swapping signs)
  84. normal_y = -dx # Swapped sign with -dx patch #3: Corrected Normal Calculation - Swapping signs)
  85. normal_length = math.sqrt(normal_x * normal_x + normal_y * normal_y)
  86. normal_x /= normal_length
  87. normal_y /= normal_length
  88.  
  89. projection = (ball_vec_x * normal_x + ball_vec_y * normal_y)
  90.  
  91. # Closest point on the edge to the ball center
  92. closest_x = next_ball_x - projection * normal_x
  93. closest_y = next_ball_y - projection * normal_y
  94.  
  95. # Check if closest point is on the segment (Corrected logic)
  96. edge_vec_dot_ball_vec = (closest_x - p1[0]) * dx + (closest_y - p1[1]) * dy
  97. edge_vec_sq_length = dx * dx + dy * dy
  98. if edge_vec_sq_length == 0:
  99. on_segment = False # Degenerate edge , patch #1: on_segment check precision (Adding Tolerance):
  100. else:
  101. t = edge_vec_dot_ball_vec / edge_vec_sq_length
  102. tolerance = 0.001 # Small tolerance value
  103. on_segment = (-tolerance <= t <= 1 + tolerance)
  104.  
  105.  
  106.  
  107.  
  108. if on_segment:
  109. distance_sq = (next_ball_x - closest_x)**2 + (next_ball_y - closest_y)**2
  110. if distance_sq <= ball_radius**2: # Collision!
  111. # enable/disable Collision Print Statements
  112. print(f"Collision with edge {i}, projection: {projection:.2f}, ball_speed_x: {ball_speed_x:.2f}, ball_speed_y: {ball_speed_y:.2f}, normal_x: {normal_x:.2f}, normal_y: {normal_y:.2f}")
  113. if projection < 0: # Ball moving towards the edge
  114. dot_product_vel = ball_speed_x * normal_x + ball_speed_y * normal_y
  115. new_ball_speed_x -= 2 * dot_product_vel * normal_x
  116. new_ball_speed_y -= 2 * dot_product_vel * normal_y
  117. # Slightly push ball away to prevent sticking , patch #2: Insufficient "push away" (Increasing Push Value)
  118. next_ball_x += normal_x * 1 # 0.1
  119. next_ball_y += normal_y * 1 # 0.1
  120. return next_ball_x - ball_speed_x, next_ball_y - ball_speed_y, new_ball_speed_x, new_ball_speed_y
  121.  
  122. return next_ball_x - ball_speed_x, next_ball_y - ball_speed_y, new_ball_speed_x, new_ball_speed_y
  123.  
  124.  
  125. # Game loop
  126. running = True
  127. clock = pygame.time.Clock()
  128.  
  129. while running:
  130. for event in pygame.event.get():
  131. if event.type == pygame.QUIT:
  132. running = False
  133.  
  134. # Update square rotation
  135. square_rotation_angle += square_rotation_speed
  136.  
  137. # Get rotated square vertices
  138. square_vertices = get_square_vertices(square_center_x, square_center_y, square_size, square_rotation_angle)
  139.  
  140. # Ball movement and collision detection
  141. ball_x, ball_y, ball_speed_x, ball_speed_y = check_square_collision_and_bounce(ball_x, ball_y, ball_radius, ball_speed_x, ball_speed_y, square_vertices)
  142.  
  143. ball_x += ball_speed_x
  144. ball_y += ball_speed_y
  145.  
  146.  
  147. # Keep ball within screen bounds (fallback, but square collision is primary)
  148. if ball_x - ball_radius < 0:
  149. ball_x = ball_radius
  150. ball_speed_x *= -1
  151. if ball_x + ball_radius > screen_width:
  152. ball_x = screen_width - ball_radius
  153. ball_speed_x *= -1
  154. if ball_y - ball_radius < 0:
  155. ball_y = ball_radius
  156. ball_speed_y *= -1
  157. if ball_y + ball_radius > screen_height:
  158. ball_y = screen_height - ball_radius
  159. ball_speed_y *= -1
  160.  
  161.  
  162. # Drawing
  163. screen.fill(black)
  164.  
  165. # Draw rotating square
  166. pygame.draw.polygon(screen, light_gray, square_vertices, 2) # 2 is line thickness
  167.  
  168. # Draw ball
  169. pygame.draw.circle(screen, yellow, (int(ball_x), int(ball_y)), ball_radius)
  170.  
  171. pygame.display.flip()
  172.  
  173. clock.tick(60) # Limit frame rate to 60 FPS
  174.  
  175. pygame.quit()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement