RE: [pygame] Bouncing ball - separating the physics from the frame rate

2007-12-03 Thread Boer Kees

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?

2007-12-03 Thread Boer Kees

#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

2007-12-03 Thread Boer Kees

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

2007-11-01 Thread Boer Kees

#!/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