Very simple physics problem - Printable Version +- iDevGames Forums (http://www.idevgames.com/forums) +-- Forum: Development Zone (/forum-3.html) +--- Forum: Game Programming Fundamentals (/forum-7.html) +--- Thread: Very simple physics problem (/thread-7193.html) Pages: 1 2 Very simple physics problem - Fenris - Mar 27, 2003 11:22 AM I'm going nuts! My world is turning upside down! What I though was the simplest physics code in the known world, proves to be not. It's simple. I want to implement gravity. So, I declare a class which has position, velocity and acceleration. I set the acceleration to be constant, right? Then, for each frame, I add the acceleration * (time step), right? This gives me correct velocity: double ts = myClock->GetTimeStep(); vel += acc*ts; Right? Now, I figured, to add this to my model's position, I just add the velocity, times the time step, right? pos += vel*ts; Now, this proves to be ridicoulously incorrect. What the heck am I doing wrong? It looks OK, but when I move this code to a slower computer, everything moves hellishly wrong. It seems that as the time-step grows larger, (lower frame-rate), gravity seems to fade. Now, the way I figure it, this iterative formula would translate quite nicely into pos = v*t; v = a * t -> pos = (a*t)*t = at^2, which I think looks pretty familiar... What the heck am I doing wrong? :sorry: Very simple physics problem - Hog - Mar 27, 2003 11:49 AM how about Code: ```pos += vel*ts - acc*ts*ts*.5; vel += acc*ts;``` Very simple physics problem - OneSadCookie - Mar 27, 2003 01:27 PM I'm guessing your GetTimeStep() method is wrong... Very simple physics problem - Fenris - Mar 27, 2003 01:33 PM I briefly looked at c_dev's solution, and it seems to work... but I haven't tough-tested this yet. Thanks, though! OSC, I' afraid it isn't - it works for everything else, and this error emerges even on paper and in an Excel spreadsheet... But yeah, I went down that road. Very simple physics problem - Hog - Mar 27, 2003 02:19 PM i double checked on that, and i think it shoud be Code: ```pos += vel*ts + acc*ts*ts*.5; vel += acc*ts;``` since D[pos(0) + vel(0)*ts - acc*ts*ts*.5] would be vel(0) - acc*ts the difference is probably small enough not to be seen (though actually it would seem to make a grave difference) Very simple physics problem - Fenris - Mar 27, 2003 03:58 PM Nope... That didn't do it either. It's funny, I've always held this as a tried and true solution, and finding it fail isn't fun at all. I hacked up a quick app that tried different algos at different delta intervals, but I haven't found anything that has been consistent over the tests. For instance, c_dev's last attempt (thanks, man!) gives a position of 75 after 2 seconds at a 0.5 second delta, but 25 after two seconds with a 1 second delta. I'm confused beyond everything! :?: Very simple physics problem - OneSadCookie - Mar 27, 2003 04:12 PM I use precisely your original method in Smiley Tag, and that seems to produce reasonable acceleration. Obviously it will be less accurate as the time step increases (you are approximating a curve by a straight line after all). One possible solution is to run your physics at a fixed (high) rate. For each variable timestep, just run the physics the appropriate number of times: Code: ```void step_system(physics_system *ps, float raw_dt) {     float dt = raw_dt + ps->overflow_dt;     for (; FIXED_TIME_STEP <= dt; dt -= FIXED_TIME_STEP)     {         do_physics(ps);     }          ps->overflow_dt = dt; }``` Very simple physics problem - Fenris - Mar 27, 2003 04:24 PM Quote:(you are approximating a curve by a straight line after all) Why, this could be it... But what the hey, is that what every game that implements gravity does? Or any other kind of acceleration - this doesn't seem right to me... > (But of course you are, OSC.) I just get the feeling that there has to be a better way to do this, and get consistent jump heights on different computers - right now, my 733 G4 makes the little guy jump about three times higher than he does on my 233 PowerBook... Very simple physics problem - skyhawk - Mar 27, 2003 05:09 PM thanks to this thread, I fixed a long overdue bug in the post udevgames BOB2. Yeah, apparently over time you would slow down horribly. quite a horrendous bug. I fixed it now! and GOD my particles look awesome at high framerates (the higher the framerates, the more particles are created to balance out your super computer) Very simple physics problem - Fenris - Mar 27, 2003 05:12 PM OSC, I just now realized how convinient your way is. Thanks, I'll do it right away! Skyhawk, sounds amazing! Very simple physics problem - DoG - Mar 27, 2003 05:43 PM You cannot expect approximative physics like the above code to return the same results with different time steps. I suggest you find a time step which small enough for the simulation to work, but still works on the slowest target platform, and artificially limit the timestep to that value. Or, if simple gravity is all you have, you can derive a formula for the relative error generated as a function of the timestep size, and use that factor to correct your physics. I suggest the 1st way, as it will give you consistent physics easily, and it works not only for simple gravity. Very simple physics problem - Skorche - Mar 27, 2003 08:00 PM Yeah, what doog said. You have to use a consistent step size. Most games run their simulation 30 times per second or more, and then the rest of the processor time goes to graphics. You *must* keep the step size the same though, otherwise you have to do some calculus to correct for errors. Simple gravity wouldn't be so hard to do it for, but anything more complicated would get messy really fast. Very simple physics problem - Hog - Mar 28, 2003 01:15 AM Quote:Originally posted by Fenris ...For instance, c_dev's last attempt (thanks, man!) gives a position of 75 after 2 seconds at a 0.5 second delta, but 25 after two seconds with a 1 second delta. I'm confused beyond everything!... that is strange, if you calculate: Code: ```pos(1) = pos(0) + vel(0)*ts(0) + acc*ts(0)*ts(0)*.5 pos(2) = pos(1) + vel(1)*ts(1) + acc*ts(1)*ts(1)*.5        = pos(0) + vel(0)*ts(0) + acc*ts(0)*ts(0)*.5 + (vel(0)+acc*ts(1))*ts(2) + acc*ts(1)*ts(1)*.5        = pos(0) + vel(0)*ts(0) + vel(0)*ts(2) + acc*.5*( ts(0)*ts(0) + 2*ts(0)*ts(1) + ts(1)*ts(1) )        = pos(0) + vel(0)*( ts(1)+ts(2) ) + acc*.5*( ts(0)+ts(1) )*( ts(0)+ts(1) )``` so theoretically is should be the same Very simple physics problem - codemattic - Mar 28, 2003 04:21 AM Quote:Originally posted by Fenris Nope... That didn't do it either. It's funny, I've always held this as a tried and true solution, and finding it fail isn't fun at all. well either you are wrong or Newton and Leibnitz are wrong. I know where Im placing my money... c_dev used calculus to figure out the formula for the position by integrating the acceleration fomula once to get a velocity formula - and then again to get the position formula. This produces the *exact* correct answer regardless how many timesteps you use. However there is a problem with this. Its only really useful for the simplest of simulations. Add friction or collision and exact integration becomes undoable. So for most games we are back to using OSC's suggestion to using a fixed timestep for your physics/movement/collision calculations. There are other benefits of using a fixed timestep. However, I did want to test to make sure that my calc books havent lied to me all these years, so...: Enter length of simulation in seconds (or 0 to quit): 2.0 Break that time into how many steps?: 8 step # = 0 / 8 step amount = 0.25 time passed = 0 acceleration = -10 position = 0 velocity = 0 step # = 1 / 8 step amount = 0.25 time passed = 0.25 acceleration = -10 position = -0.3125 velocity = -2.5 step # = 2 / 8 step amount = 0.25 time passed = 0.5 acceleration = -10 position = -1.25 velocity = -5 step # = 3 / 8 step amount = 0.25 time passed = 0.75 acceleration = -10 position = -2.8125 velocity = -7.5 step # = 4 / 8 step amount = 0.25 time passed = 1 acceleration = -10 position = -5 velocity = -10 step # = 5 / 8 step amount = 0.25 time passed = 1.25 acceleration = -10 position = -7.8125 velocity = -12.5 step # = 6 / 8 step amount = 0.25 time passed = 1.5 acceleration = -10 position = -11.25 velocity = -15 step # = 7 / 8 step amount = 0.25 time passed = 1.75 acceleration = -10 position = -15.3125 velocity = -17.5 step # = 8 / 8 step amount = 0.25 time passed = 2 acceleration = -10 position = -20 velocity = -20 Enter length of simulation in seconds (or 0 to quit): 2.0 Break that time into how many steps?: 2 step # = 0 / 2 step amount = 1 time passed = 0 acceleration = -10 position = 0 velocity = 0 step # = 1 / 2 step amount = 1 time passed = 1 acceleration = -10 position = -5 velocity = -10 step # = 2 / 2 step amount = 1 time passed = 2 acceleration = -10 position = -20 velocity = -20 Enter length of simulation in seconds (or 0 to quit): 2.0 Break that time into how many steps?: 1 step # = 0 / 1 step amount = 2 time passed = 0 acceleration = -10 position = 0 velocity = 0 step # = 1 / 1 step amount = 2 time passed = 2 acceleration = -10 position = -20 velocity = -20 Enter length of simulation in seconds (or 0 to quit): 0.0 calc_test has exited with status 0. here is the code: [SOURCECODE]#include int main (int argc, const char * argv[]) { while (true) { double position, velocity, acceleration, timeStep, timeLength; int numberOfSteps; position = velocity = timeStep = timeLength = 0.0; acceleration = -10.0; //effect of force of gravity numberOfSteps = 0; std::cout << "Enter length of simulation in seconds (or 0 to quit): "; std::cin >> timeLength; if (0.0==timeLength) return 0; //normally dont use == w/ a float - but w 0.0 its ok std::cout << "Break that time into how many steps?: "; std::cin >> numberOfSteps; timeStep = timeLength / double(numberOfSteps); for (int count = 0; count <= numberOfSteps; ++count ) { std::cout << std::endl; std::cout << "step # = " << count << " / " << numberOfSteps << std::endl; std::cout << "step amount = " << timeStep << std::endl; std::cout << "time passed = " << timeStep * double(count) << std::endl; std::cout << "acceleration = " << acceleration << std::endl; std::cout << "position = " << position << std::endl; std::cout << "velocity = " << velocity << std::endl; // from c_dev's post // pos += vel*ts + acc*ts*ts*.5; // vel += acc*ts; position += velocity*timeStep + acceleration*timeStep*timeStep*0.5; velocity += acceleration*timeStep; } std::cout << std::endl; } return 0; //shouldnt get here }[/SOURCECODE] cheers, Codemattic Very simple physics problem - IBethune - Mar 28, 2003 05:37 AM Quote:Originally posted by Fenris double ts = myClock->GetTimeStep(); vel += acc*ts; Right? Now, I figured, to add this to my model's position, I just add the velocity, times the time step, right? pos += vel*ts; Another possible way to do this (maybe simpler?) is: double deltaT = myClock->GetTimeStep(); double oldVel = vel; vel += acc*deltaT; pos += (vel+ oldVel)/2*deltaT; This way you are actually adding on the average velocity over the previous time interval. it is OK to use this simple average as velocity increases linearly with time. Here are some pen & paper examples: acc = -10; deltaT = 0.5; 0.5: vel = -5 pos = -1.25 1.0: vel = -10 pos = -5 1.5: vel = -15 pos = -11.25 2.0: vel = -20 pos = -20 Another example: acc = -10 deltaT = 1.0 1.0: vel = -10 pos = -5 2.0: vel = -20 pos = -20 I am 100% sure that this works. if it doesn't I'm going to look a bit silly, and I wonder what I actually learnt in the last 6 years of studying Physics - Iain