RE: [pygame] Bouncing ball - separating the physics from the frame rate
ok, I had this problem once, a while ago, simulating bouncing rigid balls. lost the code... The best I think you can do, is, in pseudo code: mainloop: -get the current time in ms -calculate the new position of the ball -take speed of ball, take direction of ball, calculate the imaginary end position of the ball -keep checking (with calculus), if the line ball-beginpos to ball-endpos crosses a line, if so, say where and at what angle that line is, and calculate the new imaginary endpos, mirrored about the line closest to the beginpos. (so, the position of the ball is correct, even if it bounces a couple of times inside one time-frame) (http://hyperphysics.phy-astr.gsu.edu/hbase/hframe.html for a good physics reference, also, choose radians, steer away from degrees http://en.wikipedia.org/wiki/Sine) -blit ball/line -handle input -get the current time in ms, (decide to sleep some milliseconds till next planned frame, or just continue without sleeping, if in a state of lag) If you want to simulate a 'real' bouncing ball, reduce the 'energy' of the ball (mass times speed) each time the ball bounces, by reducing speed with a percentage (simulating impression-depression, converting energy to the line and ball in the form of 'heat') and slightly reduce speed each 'meter' traveled (to simulate air friction). if you want, you can make this all just like in the real world: include size and weight of the ball in the air friction part, make the balls bounce against each other, or go to the 'non rigid' balls (oeh!), etc. For good results, simulate reality. So give your ball a mass. Then, applying 'force' to it (by mouse input, or whatever), you can just slam in Newton's laws, and balls of different weight all behave nicely to the laws of physics. dont calculate the position of the ball from the top left of a sprite or rect. Use the MIDDLE. And keep in mind the size of the ball, when calculating the bounces, I dont want to see big balls sink halfway through the line, before they bounce (heheheh.. happened to me :) ) A ball at least has a size, a mass, a position, a speed, and a direction of speed. hope you are writing a 2d environment :) _ Share life as it happens with the new Windows Live.Download today it's FREE! http://www.windowslive.com/share.html?ocid=TXT_TAGLM_Wave2_sharelife_112007
RE: [pygame] Why does my ball vibrate?
#ok, I think I have it broken down into pieces now... check out this code: # import sys, pygame, mathpygame.init()pixelspercm=10.0gravity=9.80 * 10.0 # meter per second per second (juiced up a little :) )framerate=50.0 # per secondlossperbounce=0.33 # lose energy per bounceframestosilence=3#if a bounce occurs AGAIN within the next 3 frames, consider the ball dead class Ball(object):def __init__(self, id,pos=(0,0)):self.speed=0.0 # meter per secondself.diameter=0.025 # meterself.pos=pos self.previous=0#count how many frames ago we had the previous bounce self.name=id#just some name to show for feedback image=pygame.Surface((int(self.diameter*2*pixelspercm*100),int(self.diameter*2*pixelspercm*100))) image.set_colorkey((0,0,0))image.fill((0,0,0)) pygame.draw.circle(image, (255,255,255), (int(self.diameter*pixelspercm*100),int(self.diameter*pixelspercm*100)), int(self.diameter*pixelspercm*100))self.image=imagedef updatepos(self,ms):if not (self.speed==0 and self.pos[1]==300): distance=self.DeltaX2(self.speed, gravity,ms/1000.0)if distance+self.pos[1]300: self.speed=self.FinalVelocity1(self.speed,gravity,ms/1000.0) self.pos=(self.pos[0],distance+self.pos[1])if self.previous0: self.previous=self.previous-1print self.name, 'normal cycle',self.previouselse:print self.namedis2=300-self.pos[1]# distance to ground print 'distance to ground=',dis2 ms2=self.MsTillGround(dis2,self.speed,self.FinalVelocity1(self.speed,gravity,ms/1000.0)) #ms till groundprint 'ms till ground=',ms2 endvel=self.FinalVelocity1(self.speed, gravity, (ms-ms2)/1000.0)#speed at groundspeedatground=-endvel*(1-lossperbounce)#lose energy print 'speed at ground=',speedatground dis3=self.DeltaX2(speedatground, gravity,(ms-ms2)/1000.0)#deltaX after all ms print 'deltaX after all ms=',dis3 endvel2=self.FinalVelocity1(speedatground, gravity, (ms-ms2)/1000.0)#speed after timeprint 'speed after time=',endvel2if self.previous1:self.pos=(self.pos[0],300) self.speed=0.0print 'self.speed=',self.speed print 'self.pos=',self.posprint 'SILENCE!' else:self.speed=endvel2 self.pos=(self.pos[0],300+dis3)print 'self.speed=',self.speedprint 'self.pos=',self.pos self.previous=framestosilence def MsTillGround(self, Dx, Vi, Vf):#Dx=1/2*(Vi+Vf)*t #t=Dx/(1/2*(Vi+Vf))t=Dx/(0.5*(Vi+Vf))return t*1000.0 # t is in seconds, but we want the amount of millisecondsdef FinalVelocity1(self,Vi,A,t):# ### 1# Vf=Vi+A*t # Final Velocity = Initial Velocity + Acceleration * time# meter/second = meter/second + meter/second/second * secondreturn Vi+A*t def AverageVelocity(self,Vi,Vf):# ### 2# Va=(Vi+Vf)/2# Average Velocity = ( Initial Velocity + Final Velocity )/2# meter/second = ( meter/second + meter/second )/2return (Vi+Vf)/2def DeltaX1(self,Vi,Vf,t):# ### 3# Dx=1/2*(Vi+Vf)*t# DeltaX = 1/2 * ( Initial Velocity + Final Velocity ) * time# meter = 1/2 * ( meter/second + meter/second )* second return 0.5*(Vi+Vf)*tdef DeltaX2(self,Vi,A,t):# ### 4 # Dx=Vi*t+ 1/2*a* t^2 # notice: t^2 in python is: t**2# DeltaX = Initial Velocity * time+1/2*Acceleration* time*time# meter = meter/second * second+1/2*meter/second/second * second*secondreturn Vi*t+0.5*A*t**2def FinalVelocity2(self,Vi,A,Dx):# ### 5 # Vf^2=Vi^2+2*a*Dx# Final Velocity^2=Initial Velocity^2+2*Acceleration*DeltaX# meter/second*meter/second= meter/second*meter/second+2*meter/second/second*meterVf2=Vi**2+2*A*Dx return math.sqrt(Vf2) screen = pygame.display.set_mode((200, 400), 0, 32)balls = []balls.append(Ball('Ball 1',(78,15)))balls.append(Ball('Ball 2',(12,158)))balls.append(Ball('Ball 3',(122,56)))newtime=oldtime=0 while True:newtime=pygame.time.get_ticks() # milliseconds since start of programif newtime-oldtime(1000.0/framerate)*2:print 'LAGGING!' if newtime-oldtime1000.0/framerate:for event in pygame.event.get(): if event.type == pygame.QUIT:exit() screen.fill((0, 0, 0))for ball in balls: ball.updatepos(newtime-oldtime)for ball in balls:
RE: [pygame] This is why your ball vibrates
The solution: :) see my previous post for some code. the problem was twofold: check somehow, if the ball moves SOO slightly, it is to be considered dead. BUT! there also was a major flaw in the way the ball bounced back up: the speed was assumed to INCREASE all the way, even AFTER the direction is flipped. this causes the ball to raise higher as normal, and gather some extra speed while falling the extra height, then get ejected back up again. Hence: a nervously bouncing ball! the solution is to calculate the moment of hitting the ground, calculate the speed at that moment, THEN turn the direction, and handle the rest, so, in the last part, the speed is not INcreased, but, as should be, DEcreased by gravity. this reduces the bouncing to ZERO! I then also choose to cut the moving if the ball bounces within 3 frames, but you could also calculate the amount of milliseconds it will take the ball to bounce again, and silence the ball if it is back that same frame. you could also NOT declare a ball 'dead', and just keep calculating the minute chances, getting ever smaller each iteration, and waste all that cpu power :) the vibrating ball problem was in the gravity error in the second part after bouncing. It does not vibrate any more if you fix that, look at my code to see a working example in my previous message :) _ Share life as it happens with the new Windows Live.Download today it's FREE! http://www.windowslive.com/share.html?ocid=TXT_TAGLM_Wave2_sharelife_112007
[pygame] centered screen position using SDL_VIDEO_CENTERED
#!/usr/bin/env python import pygame from pygame.locals import * #center screen import os #os.environ[SDL_VIDEO_CENTERED] = 1 ## (UN)COMMENT TO SEE EFFECT # WITH os.environ[SDL_VIDEO_CENTERED] = 1 : #when maximized: window does not make it to the top - half of the taskbars height?? #when resizing: need new screen (with new size), which pops the window back to the middle # WHAT! oh NO! (and writing os.environ[SDL_VIDEO_CENTERED] = 0 there does NOT work, #the window is already initialised WITH those paramaters I guess) # withOUT os.environ[SDL_VIDEO_CENTERED] = 1 : #resizing goes as planned, maximizing works normally, BUT! the screen starts in the top left corner # (or closelyby) WHAT! oh NO! #my goal? to have a window at least under W32 (but preferably crossplatform!), behave well, # like a normal window? #I want my user to have a fresh window put in the middle, he places it somewhere, resize it #somewhat, and then, when the user closes the window: i save the settings, so I start up at the #same place, same size, next time! now, THATS service! #any ideas??? #init pygame pygame.init() #load bmp as icon, black as transparancy key try: rawicon=pygame.image.load('icon.bmp') except: #no icon found rawicon=pygame.Surface((32,32)) rawicon.fill((0,0,0)) icon=pygame.Surface(rawicon.get_size()) icon.set_colorkey((0,0,0)) for i in range(0,rawicon.get_height()): for j in range(0,rawicon.get_width()): icon.set_at((i,j), rawicon.get_at((i,j))) pygame.display.set_icon(icon) #init screen screen=pygame.display.set_mode((250,250), RESIZABLE) pygame.display.set_caption(test) mousecount=0 #to filter some mouse events while 1:#loop till death: #handle user input: for event in pygame.event.get():#loop all events pygame detected: #pgs.checkinput(event) if event.type == QUIT: # detect user break/closewindowevent print close raise SystemExit elif event.type == KEYDOWN and event.key == K_ESCAPE: #detect escape print escape raise SystemExit elif event.type == VIDEORESIZE:#user changed screensize print resize from + str(screen.get_size()) + to + str(event.size) screen=pygame.display.set_mode(event.size, RESIZABLE) elif event.type == MOUSEMOTION: if mousecount%250==0:#only show if mousecount/250 has no left overs print str(event) mousecount+=1 else: print str(event) pygame.display.flip() # show screen _ Help yourself to FREE treats served up daily at the Messenger Café. Stop by today! http://www.cafemessenger.com/info/info_sweetstuff2.html?ocid=TXT_TAGHM_OctHMtagline