[Python] Pymunk Energy Conservation: Simulating a Bouncing Ball with Perfect Elasticity

Discussão em 'Python' iniciado por Stack, Fevereiro 1, 2025.

  1. Stack

    Stack Membro Participativo

    Issue with Mechanical Energy Conservation in a Bouncing Ball Simulation (Pymunk)

    I'm trying to simulate a simple bouncing ball in Pymunk with perfect elasticity (coefficient of restitution = 1). The ball should conserve mechanical energy, meaning the sum of kinetic and potential energy remains constant over time. However, when I track the total energy of the system, I notice variations instead of a constant value.

    The ball has elasticity set to 1. Gravity is applied in the downward direction. No external forces are acting after the initial release.

    Despite these conditions, the total energy fluctuates over time. Is there something I'm missing in how Pymunk handles collisions or numerical integration that could explain this issue? How can I ensure better energy conservation in the simulation?

    Kinetic Energy: 1551.06, Potential Energy: 405.32, Total Energy: 1956.38 Kinetic Energy: 1569.31, Potential Energy: 395.76, Total Energy: 1965.07

    Thank you in advance for your time and help

    '''

    import pygame
    import pymunk
    import numpy as np

    # Constants
    SCREEN_WIDTH = 600
    SCREEN_HEIGHT = 400
    G = 9.8 # Gravity acceleration

    # Initialize Pygame and Pymunk
    pygame.init()
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    clock = pygame.time.Clock()

    # Pymunk Space setup
    space = pymunk.Space()
    space.gravity = (0, G)

    # Ball properties
    radius = 30
    mass = 1
    moment = pymunk.moment_for_circle(mass, 0, radius)

    # Create the ball
    ball_body = pymunk.Body(mass, moment)
    ball_body.position = (SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2)
    ball_shape = pymunk.Circle(ball_body, radius)
    ball_shape.elasticity = 1.0 # Perfect elasticity
    space.add(ball_body, ball_shape)

    # Create the floor (static)
    floor = pymunk.Segment(space.static_body, (0, SCREEN_HEIGHT - 10), (SCREEN_WIDTH, SCREEN_HEIGHT - 10), 0)
    floor.elasticity = 1.0 # Perfect elasticity
    space.add(floor)


    # Function to calculate energy
    def calculate_energy():
    # Kinetic energy: 1/2 * m * v^2
    velocity = ball_body.velocity
    velocity_mag = (velocity[0] ** 2 + velocity[1] ** 2) ** 0.5
    kinetic_energy = 0.5 * mass * (velocity_mag ** 2)

    # Potential energy: m * g * h
    potential_energy = mass * G * (SCREEN_HEIGHT - ball_body.position.y)

    # Total energy
    total_energy = kinetic_energy + potential_energy
    return kinetic_energy, potential_energy, total_energy


    # Function to render the ball
    def render_ball():
    pygame.draw.circle(screen, (255, 0, 0), (int(ball_body.position.x), int(ball_body.position.y)), radius)


    # Main loop
    running = True
    while running:
    for event in pygame.event.get():
    if event.type == pygame.QUIT:
    running = False

    # Update the world
    space.step(1 / 60)

    # Calculate and display energy
    kinetic, potential, total = calculate_energy()
    print(f"Kinetic Energy: {kinetic:.2f}, Potential Energy: {potential:.2f}, Total Energy: {total:.2f}")

    # Clear the screen
    screen.fill((255, 255, 255))

    # Render the ball
    render_ball()

    # Update the display
    pygame.display.flip()

    # Limit FPS
    clock.tick(60)

    # Quit Pygame
    pygame.quit()


    '''

    Continue reading...

Compartilhe esta Página