Untitled

 avatar
unknown
plain_text
2 months ago
3.8 kB
2
Indexable
import pygame
import math
from pygame.math import Vector2

# Initialize pygame
pygame.init()

# Screen dimensions
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Bouncing Ball in Spinning Hexagon")
clock = pygame.time.Clock()
FPS = 60

# Colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED   = (255, 0, 0)

# Hexagon parameters
hex_center = Vector2(WIDTH/2, HEIGHT/2)
hex_radius = 250         # Distance from center to vertex
hex_rotation = 0         # Initial rotation angle in radians
angular_velocity = 0.01  # Rotation speed (radians per frame)

# Ball parameters
ball_radius = 15
ball_pos = Vector2(WIDTH/2, HEIGHT/2 - 100)
ball_vel = Vector2(3, 0)
gravity = Vector2(0, 0.2)    # Constant acceleration downward
ball_color = RED

# Physics parameters
restitution = 0.9       # Bounce damping factor (energy loss on impact)
global_friction = 0.999 # Damping applied every frame

def compute_hexagon_vertices(center, radius, rotation):
    """Compute the vertices of a regular hexagon given a center, radius, and rotation."""
    vertices = []
    for i in range(6):
        angle = rotation + i * (2 * math.pi / 6)
        x = center.x + radius * math.cos(angle)
        y = center.y + radius * math.sin(angle)
        vertices.append(Vector2(x, y))
    return vertices

def point_line_distance(p, a, b):
    """
    Returns the distance from point p to the line segment defined by points a and b,
    along with the closest point on the segment.
    """
    ap = p - a
    ab = b - a
    t = ap.dot(ab) / ab.length_squared()
    t = max(0, min(1, t))
    closest = a + ab * t
    return (p - closest).length(), closest

running = True
while running:
    dt = clock.tick(FPS) / 1000.0  # dt in seconds (not used extensively)
    
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    
    # Update hexagon rotation
    hex_rotation += angular_velocity

    # Update ball physics: gravity and friction
    ball_vel += gravity
    ball_vel *= global_friction
    ball_pos += ball_vel

    # Get current hexagon vertices (rotating each frame)
    vertices = compute_hexagon_vertices(hex_center, hex_radius, hex_rotation)
    
    # Check collision with each hexagon edge
    for i in range(len(vertices)):
        a = vertices[i]
        b = vertices[(i+1) % len(vertices)]
        dist, closest = point_line_distance(ball_pos, a, b)
        if dist < ball_radius:
            # Collision detected: compute collision normal (from wall toward ball)
            normal = (ball_pos - closest).normalize()
            
            # Compute the wall's velocity at the collision point due to rotation.
            # For a rotating body, v = ω × r. Here r = (collision point - hex_center)
            r = closest - hex_center
            wall_vel = angular_velocity * Vector2(-r.y, r.x)
            
            # Compute ball velocity relative to the moving wall
            rel_vel = ball_vel - wall_vel
            # Reflect the relative velocity along the collision normal
            rel_vel_reflected = rel_vel - 2 * rel_vel.dot(normal) * normal
            # New ball velocity is the reflected relative velocity plus wall velocity,
            # scaled by the restitution coefficient to simulate energy loss.
            ball_vel = wall_vel + rel_vel_reflected * restitution
            
            # Reposition ball just outside the wall to prevent sticking.
            overlap = ball_radius - dist
            ball_pos += normal * overlap

    # Drawing
    screen.fill(BLACK)
    # Draw hexagon (outline)
    pygame.draw.polygon(screen, WHITE, [(v.x, v.y) for v in vertices], 2)
    # Draw ball
    pygame.draw.circle(screen, ball_color, (int(ball_pos.x), int(ball_pos.y)), ball_radius)
    pygame.display.flip()

pygame.quit()
Editor is loading...
Leave a Comment