Re: [pygame] Bouncing ball - separating the physics from the frame rate
Matt Smith wrote: I can see how it could fall down when I introduce non-horizontal or vertical surfaces. although I imagine that I could keep using the vectors but convert them into angular vectors on collision. There's no need to calculate angles even then. Take a unit vector perpendicular to the surface, and find the dot product of that with the velocity. This is the magnitude of the component of the velocity perpendicular to the surface. Multiply the unit vector by that and add it to the original velocity (assuming your unit vector points "away" from the surface). As a general rule, it's almost never necessary to deal with angles when doing this sort of thing. There's usually some combination of vector operations that will give you what you want much more easily and efficiently. This is even more true in 3D, where angular coordinate systems (so-called Euler angles) have various nasty problems due to singularities. It's better to stay with cartesian coordinates if at all possible. -- Greg
Re: [pygame] Bouncing ball - separating the physics from the frame rate
Opps, that second ex. should have been math.acos()
Re: [pygame] Bouncing ball - separating the physics from the frame rate
On Dec 3, 2007, at 12:30 PM, Ian Mallett wrote: On 12/3/07, Matt Smith <[EMAIL PROTECTED]> wrote: 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) Yep, and if you want to do trig functions in Python with the 'Math' module with degrees, you must convert to radians. math.cos(math.radians(blah)) math.degrees(math.cos(blah)) Except that the output of sine/cos is not an angle, thus calling math.degrees() on it makes little sense. Honestly I find it easier to just use radians all the time rather than convert back and forth, except for a few pygame methods that take degrees... -Casey
Re: [pygame] Bouncing ball - separating the physics from the frame rate
On 12/3/07, Matt Smith <[EMAIL PROTECTED]> wrote: > > 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) Yep, and if you want to do trig functions in Python with the 'Math' module with degrees, you must convert to radians. math.cos(math.radians(blah)) math.degrees(math.cos(blah)) Ian
Re: [pygame] Bouncing ball - separating the physics from the frame rate
Boer Kees wrote: 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) Hi, Rather than use the angle of the ball, I have used the vertical and horizontal components of the velocity of the ball. If the ball hits a vertical wall then reverse the horizontal component of the velocity taking into account the 'bounce factor'. This seems to work for horizontal and vertical surfaces but I can see how it could fall down when I introduce non-horizontal or vertical surfaces. although I imagine that I could keep using the vectors but convert them into angular vectors on collision. I am still wrestling with what to do when the ball hits a surface and wants to pass through it, currently I am truncating the movement - this will become less accurate as the frame rate gets slower. Anyway, here is my latest code, not taking into account all of the fantastic responses my post has had over the last day or so. I will have a look at all of them and I'll modify the code accordingly over the next few days. Please not, I'm only just getting to grips with OOP! Thanks for looking, Matt #! /usr/bin/python import sys, pygame pygame.init() xsize = 800 ysize = 600 startx = 192 starty = 0 floor = ysize - 16 ceiling = 0 lwall = 0 rwall = xsize - 16 class world: gravity = 1000 bounce = 0.8 class ball(world): def __init__(self): self.velocity = [0, 0] self.position = [0, 0] self.sprite = pygame.image.load('ball.png') def put(self, x, y): self.position[0] = x self.position[1] = y def push(self, x, y): self.velocity[0] = x self.velocity[1] = y def update(self, timepassed): newvelocity = self.velocity[1] + (world.gravity * timepassed) self.position[1] = self.position[1] + int(((self.velocity[1] + newvelocity) / 2) * timepassed) self.velocity[1] = newvelocity self.position[0] = self.position[0] + int(self.velocity[0] * timepassed) def checkcollision(self): # Check for collisions and rebound if necessary if self.position[1] >= floor and self.velocity[1] > 0: self.position[1] = floor self.velocity[1] = -self.velocity[1] * world.bounce self.velocity[0] = self.velocity[0] * world.bounce if self.position[1] <= ceiling and self.velocity[1] < 0: self.position[1] = ceiling self.velocity[1] = -self.velocity[1] * world.bounce self.velocity[0] = self.velocity[0] * world.bounce if self.position[0] >= rwall and self.velocity[0] > 0: self.position[0] = rwall self.velocity[0] = -self.velocity[0] * world.bounce self.velocity[1] = self.velocity[1] * world.bounce if self.position[0] <= lwall and self.velocity[0] < 0: self.position[0] = lwall self.velocity[0] = -self.velocity[0] * world.bounce self.velocity[1] = self.velocity[1] * world.bounce screen = pygame.display.set_mode((xsize, ysize), 0, 32) clock = pygame.time.Clock() ball1 = ball() ball1.put(startx, starty) ball1.push(-8000, 4000) # The main loop while True: # Test for exit for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit() # Update the screen screen.fill((0, 0, 0)) screen.blit(ball1.sprite, ball1.position) pygame.display.update() # Apply physics to the ball timepassed = clock.tick(50) / 1000.0 ball1.checkcollision() ball1.update(timepassed)
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] Bouncing ball - separating the physics from the frame rate
Patrick Mullen wrote: > The only downside to this > method, is if the framerate goes down, the physics will slow down > along with it - but this may be preferable to jerkiness anyway. Right. You don't want the physics to run too far ahead of what's displayed on the screen. If rendering gets slowed down for any reason, I find it's better to just let the physics get slowed down as well. Otherwise the game starts taking big jumps and becomes difficult to play. The way I'm doing this in my games at the moment is to set up a timer which sends events at regular intervals, let's call it dt. Whenever one of these events occurs, I set a physics_update_needed flag. Then my main loop does something like Get all the events that have occurred since last time round the loop Process all of these events If physics_update_needed is set: Advance physics by dt Clear physics_update_needed Render The result of this is that as long as an update/render cycle can be done in less than dt, everything proceeds smoothly with frames dt apart. If not, the frame rate and game speed slow down together to whatever can be supported. I prefer to use timer events rather than clock.tick(), because I don't like the idea of busy waiting. It's a really bad thing to do on a multitasking system. -- Greg
Re: [pygame] Bouncing ball - separating the physics from the frame rate
> 1. Have the physics and graphics running in separate threads. I don't have a > clue how to implement this! This is a very experimental technique. I think there may be a few games that do this, but the majority do not. > > 2. Call a function from the main loop every time it passes which does the > physics calculations based on a clock independent of the frame rate but which > pauses when the simulation is paused (window not in focus?) Is there a > function > in the sys module that I can use to test for a pause? If your framerate is fairly constant, i.e. it doesn't ever go slower than what you place inside the clock.tick() call, than you should be able to get away with simply calling the physics once per frame without using time_passed as part of the calculation. (Substituting some fixed time, like 0.02 as needed). The only downside to this method, is if the framerate goes down, the physics will slow down along with it - but this may be preferable to jerkiness anyway. What you won't have is a bad framerate that causes the physics to go out of sync or go haywire. And the pausing problem won't matter. To handle slower framerates, you could detect if time_passed is above some threshold, and call the physics function twice if the time is too large. But it's better to keep the framerate up, no? clock.tick(60) should guarantee that the framerate is a steady 60 fps unless things slow down. So here's my untested example, factoring out time_passed, and making physics a function: #physics def run_physics(ob): time_passed = 0.02 #.02 is a decent time interval for 60 fps, adjust as needed. (1/60.0 is more accurate) # The physics # Reverse velocity taking into account bounciness if we hit the ground if ob.ypos >= 384 and ob.velocity > 0: # Avoid the ball sinking into the ground ob.ypos = 384 ob.velocity = -ob.velocity * ob.bounce newvelocity = ob.velocity + (ob.gravity * time_passed) # Use the average velocity over the period of the frame to change position ob.ypos = ob.ypos + int(((ob.velocity + newvelocity) / 2) * time_passed * 160) ob.velocity = newvelocity # The main loop while True: # Test for exit for event in pygame.event.get(): if event.type == pygame.QUIT: exit() clock.tick(60) / 1000.0 run_physics(ball) #Make global variables attributes of ball # Update the screen screen.fill((0, 0, 0)) screen.blit(ball, (xpos, ypos)) pygame.display.update()
[pygame] Bouncing ball - separating the physics from the frame rate
Hi, I know have the following code for my bouncing ball program: #! /usr/bin/python import sys, pygame, math 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: # Avoid the ball sinking into the ground ypos = 384 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 + int(((velocity + newvelocity) / 2) * time_passed * 160) velocity = newvelocity # Update the screen screen.fill((0, 0, 0)) screen.blit(ball, (xpos, ypos)) pygame.display.update() The bounce is pretty realistic and I can live with the slight error caused by returning the ball to the floor exactly each time it bounces. Next I am going to have a look at adding in some sideways movement and bouncing off walls as well. Before I do that I would like to separate the physics calculations from the frame rate calculations and drawing loop. I really don't have a clue how to do this. I have never programmed anything in real time before. Having had a think about this I can see two possible ways of doing it. 1. Have the physics and graphics running in separate threads. I don't have a clue how to implement this! 2. Call a function from the main loop every time it passes which does the physics calculations based on a clock independent of the frame rate but which pauses when the simulation is paused (window not in focus?) Is there a function in the sys module that I can use to test for a pause? Can anyone give me some more pointers on the best and most pythonic way of doing this. Thanks. Matt