I am doing some basic physics stuff with a sprite, this one being gravity with some extra drag so that the sprite in theory should come to rest on the top edge of the screen. The issue is however that as it gets closer to the ground the sprite vibrates faster and faster and ends up 'squeezing' over the boundary.
Whats a good way to stop this? I could pst code if required but there is nothing unusual about it, I just think it needs a workaround to reduce the velocity as it gets closer to be stationary.
import pygame, math, random
pygame.init()
class Circle(pygame.sprite.Sprite):
def __init__(self, screen):
pygame.sprite.Sprite.__init__(self)
self.screen = screen
self.dx = 0
self.dy = 0
self.ddx = 0
self.ddx = 0
self.forceX = 0
self.forceY = 0
self.x = random.randrange(20,self.screen.get_width())
self.y = self.screen.get_height()/2
self.radius = random.randrange(5,30)
self.image = pygame.Surface((self.radius*2,self.radius*2))
self.image.set_colorkey((0,0,0))
self.image.set_alpha(120)
self.mass = self.radius/15.0
pygame.draw.circle(self.image, (175,255,0), (self.radius,self.radius), self.radius)
self.image = self.image.convert_alpha()
self.rect = self.image.get_rect()
self.rect.center = (self.x, self.y)
def update(self):
self.calcPos()
self.checkBounds()
self.rect.centerx = self.x
self.rect.centery = self.y
self.forceX = 0
self.forceY = 0
def calcPos(self):
self.ddx = self.forceX
self.ddy = self.forceY
self.dy += self.ddy
self.dx += self.ddx
self.x += self.dx
self.y += self.dy
def applyForce(self, force):
self.forceX += force[0]/self.mass
self.forceY += force[1]/self.mass
def checkBounds(self):
if self.y > self.screen.get_height():
self.dy *= -1.05
if self.x > self.screen.get_width():
self.dx *= -1.05
if self.y < 0:
self.dy *= -1.05
if self.x < 0:
self.dx *= -1.05
def main():
screen = pygame.display.set_mode((600,400))
background = pygame.Surface((screen.get_size()))
background.fill((150,150,150))
background = background.convert()
circleGRP = pygame.sprite.Group() #Add balls
for x in range(10):
circleGRP.add(Circle(screen))
wind = (1, 0)
gravity = (0, 1.0)
clock = pygame.time.Clock()
mainLoop = True
while mainLoop:
clock.tick(30) #Clock
for event in pygame.event.get(): #Key events
if event.type == pygame.QUIT:
mainLoop = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
mainLoop = False
elif event.type == pygame.MOUSEBUTTONDOWN: #Add wind
if pygame.mouse.get_pressed()[0]:
for circle in circleGRP:
circle.applyForce(wind)
#----------------------------------------------------------------------------
for circle in circleGRP: #Add gravity
gravity = (0, 1.0)
gravity = tuple([each * circle.mass for each in gravity])
circle.applyForce(gravity)
circleX = circle.dx * -1 #Add friction
circleY = circle.dy * -1
friction = (circleX/80* circle.mass* (circle.radius/5), circleY/80* circle.mass* (circle.radius/5))
circle.applyForce(friction)
#----------------------------------------------------------------------------
circleGRP.update()
screen.blit(background, (0,0))
circleGRP.draw(screen)
pygame.display.flip()
pygame.quit()
if __name__ == "__main__":
main()