Below is a complete Python code implementation that simulates a ball bouncing inside a spinning hexagon. The simulation is built using Pygame and factors in gravity and friction. The code is structured to first set up the simulation environment, then define the classes for both the ball and the hexagon, and finally put everything together in a main loop that handles updating positions, processing collisions, and drawing the graphics on the screen.
The program initializes Pygame and sets up the display window. Constants such as screen width, height, gravity, and friction are established. The hexagon’s vertices are computed based on its radius and center coordinates to form the boundary.
Two main classes are defined:
Collision detection involves checking the distance from the ball’s center to each edge of the hexagon and determining if the ball is penetrating an edge. Upon collision, the velocity is reflected relative to the surface normal, and an energy loss factor simulates inelastic bounce while friction slows the ball.
The main loop updates the ball’s position, updates the hexagon’s rotation, checks for collisions, and renders both objects on the screen. The loop runs at a fixed frame rate to maintain smooth animation.
Below is the complete Python code. You can run this script in an environment with Pygame installed.
# Importing necessary libraries
import pygame
import math
# Initialize Pygame and create display window
pygame.init()
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Bouncing Ball in Spinning Hexagon")
clock = pygame.time.Clock()
# Define colors and physics constants
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GRAVITY = 0.2 # Gravity acceleration per frame
FRICTION = 0.99 # Friction coefficient for ball's velocity reduction
# Class representing the bouncing ball with physics updates and collision handling
class Ball:
def __init__(self, x, y, radius):
self.x = x
self.y = y
self.radius = radius
self.vx = 5 # Initial horizontal velocity
self.vy = -5 # Initial vertical velocity
self.gravity = GRAVITY
self.friction = FRICTION
def update(self):
# Apply gravity to vertical velocity
self.vy += self.gravity
# Update position based on the current velocity
self.x += self.vx
self.y += self.vy
# Apply friction to both velocity components
self.vx *= self.friction
self.vy *= self.friction
def draw(self, surface):
pygame.draw.circle(surface, RED, (int(self.x), int(self.y)), self.radius)
def bounce_off_edge(self, p1, p2):
# Calculate the edge vector from p1 to p2
edge_dx = p2[0] - p1[0]
edge_dy = p2[1] - p1[1]
edge_length = math.sqrt(edge_dx <b> 2 + edge_dy </b> 2)
# Calculate the unit normal vector for the edge (-dy, dx) normalized
normal_x = -(edge_dy) / edge_length
normal_y = (edge_dx) / edge_length
# Compute vector from one vertex to the ball center
vx = self.x - p1[0]
vy = self.y - p1[1]
# Dot product between velocity vector and the normal vector
dot = self.vx * normal_x + self.vy * normal_y
# Reflect the ball's velocity across the collision normal with energy loss
self.vx -= 2 * dot * normal_x
self.vy -= 2 * dot * normal_y
self.vx *= 0.9
self.vy *= 0.9
def handle_collision(self, hex_vertices):
# Check collision with each edge of the hexagon
for i in range(6):
p1 = hex_vertices[i]
p2 = hex_vertices[(i + 1) % 6] # Wrap around
# Compute line equation parameters for edge p1 to p2
edge_dx = p2[0] - p1[0]
edge_dy = p2[1] - p1[1]
edge_length = math.sqrt(edge_dx <b> 2 + edge_dy </b> 2)
if edge_length == 0:
continue # Prevent division by zero
# Find the distance from the ball's center to the edge
distance = abs(edge_dy * self.x - edge_dx * self.y + p2[0]*p1[1] - p2[1]*p1[0]) / edge_length
# Simple collision check: if the ball is very close to the edge
if distance <= self.radius:
# Adjust position to overcome penetration (optional)
self.bounce_off_edge(p1, p2)
# Class representing the rotating hexagon container
class SpinningHexagon:
def __init__(self, center, radius, rotation_speed):
self.center = center
self.radius = radius
self.rotation_speed = rotation_speed
self.angle = 0 # Initial rotation angle
def update(self):
# Increase rotation angle over time
self.angle += self.rotation_speed
def get_vertices(self):
vertices = []
cx, cy = self.center
for i in range(6):
# Calculate each vertex angle; add current rotation angle for spinning effect
theta = self.angle + i * math.pi / 3
x = cx + self.radius * math.cos(theta)
y = cy + self.radius * math.sin(theta)
vertices.append((x, y))
return vertices
def draw(self, surface):
vertices = self.get_vertices()
pygame.draw.polygon(surface, WHITE, vertices, 2)
# Main simulation loop combining hexagon rotation, ball movement, and collision handling
def main():
hexagon = SpinningHexagon(center=(WIDTH // 2, HEIGHT // 2), radius=200, rotation_speed=0.02)
ball = Ball(WIDTH // 2, HEIGHT // 2 - 150, radius=20)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Update simulation physics
ball.update()
hexagon.update()
# Get current hexagon vertices after rotation
vertices = hexagon.get_vertices()
ball.handle_collision(vertices)
# Drawing section
screen.fill(BLACK)
hexagon.draw(screen)
ball.draw(screen)
pygame.display.flip()
clock.tick(60) # Limit the frame rate to 60 FPS
pygame.quit()
if __name__ == "__main__":
main()
The code above is organized to provide readability and ease of future enhancements. Here is an overview of its structure and key parameters:
Component | Description |
---|---|
Ball Physics | Applies gravity, friction, and uses vector reflection for wall collisions. |
Hexagon Rotation | The hexagon’s vertices are computed dynamically based on a continuously updating rotation angle. |
Collision Detection | Checks proximity of the ball to each hexagon edge and reflects the velocity vector upon contact. |
This implementation has been designed with clarity in mind. The performance of the simulation depends on the chosen physics parameters, such as the gravity constant, friction coefficient, and energy loss during collisions. You can adjust these values to achieve the desired simulation effect.