[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [pygame] Why does my ball vibrate?



On Wed, Nov 28, 2007 at 08:26:19PM +0000, Matt Smith wrote:
> Hi,
> 
> I am beginning to learn Pygame and I have written a short program to 
> simulate a bouncing ball. The motion of the ball is pretty realistic 
> until it has almost come to rest. The ball continues to vibrate long 
> after you would have expected it to come to a complete rest (or be 
> moving less than 1 pile each time as it will never stop moving 100%). 
> Also, the ball can start to bounce higher again if I click somewhere 
> else on the desktop. I can't work out why this happens so can anyone 
> shed some light on it and suggest how I can prevent it.Here's my code:

I have two suggestions, see below:

> #! /usr/bin/python
> 
> import sys, pygame
> pygame.init()
> 
> xpos = 92
> ypos = 0
> gravity = 9.8
> velocity = 0
> # How much of the velocity of the ball is retained on a bounce
> bounce = 0.8
> 
> screen = pygame.display.set_mode((200, 400), 0, 32)
> # The ball is a 16px sprite
> ball = pygame.image.load('ball.png')
> clock = pygame.time.Clock()
> 
> # The main loop
> while True:
> 
>     # Test for exit
>     for event in pygame.event.get():
>         if event.type == pygame.QUIT:
>             exit()
> 
>     # The physics
>     # Reverse velocity taking into account bounciness if we hit the ground
>     if ypos == 384 and velocity > 0:

Here you probably want "if ypos >= 384 ..." rather than checking the 
precise pixel position, since your ball could be falling fast enough to 
skip over pixel 384. I notice you have a check for that later, but why 
not put it here?

>         velocity = -velocity * bounce
>     time_passed = clock.tick(60) / 1000.0
>     newvelocity = velocity + (gravity * time_passed)
>     # Use the average velocity over the period of the frame to change 
> position
>     ypos = ypos + (((velocity + newvelocity) / 2) * time_passed * 160)

Your velocity is a floating point number, and floating point math has 
limited precision. Because your ball sprite is being displayed only at 
integer pixel coordinates, you ought not to let your xpos and ypos have 
decmals. I suggest you change the above line to this:

  ypos = ypos + int(((velocity + newvelocity) / 2) * time_passed * 160)

This throws away the decmal on the ypos, but preserves it for your 
velocity. This fix alone, even without the ypos == 384 thing I mentioned 
above, is enough to solve your bouncing problem.

>     # Prevent the ball from sinking into the ground
>     if ypos >= 384:
>         ypos = 384
>     velocity = newvelocity
> 
>     # Update the screen
>     screen.fill((0, 0, 0))
>     screen.blit(ball, (xpos, ypos))
>     pygame.display.update()
> 
> Thanks for looking.
> 
> Matt

You are welcome :)

---
James Paige