Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Basic Physics

Credits go to gillius and Paul Pridham for helping out!
This thread is locked; no one can reply to it. rss feed Print
Basic Physics
edfredcoder
Member #7,985
November 2006
avatar

Hello. I am trying to get a basic physics system working, but something doesn't work.

The first thing I tried was to get a falling object, of a small mass, to fall on top of a heavy object and bounce up. The heavy object has its velocity set to 0 each frame to keep it from falling downward too. What should happen is the falling block should bounce up and down on the stationary block, eventually coming to rest. What actually happens is the falling block bounces up and down, then rests on the stationary block for a moment, then slowly sinks through it. My code is as follows:

1typedef struct
2{
3 //Physics info
4 float x,y,dx,dy,mass;
5}Entity;
6 
7void updateEntity(Entity *e)
8{
9 e->x+=e->dx;
10 e->y+=e->dy;
11}
12 
13//Copied from some web site. *Should* conserve momentum, make them bounce, etc.
14void collide(Entity *a,Entity *b)
15{
16 float adx=a->dx,bdx=b->dx,ady=a->dy,bdy=b->dy;
17 a->dx=(2*b->mass*bdx+adx*(a->mass-b->mass))/(a->mass+b->mass);
18 a->dy=(2*b->mass*bdy+ady*(a->mass-b->mass))/(a->mass+b->mass);
19
20 b->dx=(2*a->mass*adx-bdx*(a->mass-b->mass))/(a->mass+b->mass);
21 b->dy=(2*a->mass*ady-bdy*(a->mass-b->mass))/(a->mass+b->mass);
22}
23 
24//This calculates if there's a collision between the circle at (x1,y1) of radius r1 and the circle at (x2,y2) of radius r2
25int circleCollision(int x1,int y1,int r1,int x2,int y2,int r2)
26{
27 float dx=x1-x2;
28 float dy=y1-y2;
29 float distanceSquared=dx*dx+dy*dy;
30 float radius=r1+r2;
31 if(distanceSquared<radius*radius)
32 return 1;
33 return 0;
34}
35 
36//Global entity variables
37Entity e1,e2;
38 
39//This code is run to set up e1 and e2. Obviously, its actually differently written in my real program, but basically the same.
40e1.mass=200;
41e2.mass=1000;
42e1.x=32;
43e2.x=32;
44e1.y=0;
45e2.y=70;
46e1.dx=e2.dx=e1.dy=e2.dy=0;
47 
48//This is the main loop. Again, the actual main loop in my program looks different and has other things in it, but this is the relevant part
49for(;;)
50{
51 if(circleCollision(e1.x,e1.y,16,e2.x,e2.y,16)) //The blocks are 32x32, hence a radius of 16
52 collide(&e1,&e2);
53 
54 //The first entity falls, so we add to it's velocity each frame
55 e1.dy+=.1;
56 //The second entity can't fall, as it is stationary.
57 e2.dy=0;
58 
59 //Update the positions of the entities.
60 updateEntity(&e1);
61 updateEntity(&e2);
62 
63 draw_everything();
64}

This is not literally what my code is; for example, the entities also have information about what bitmap represents them, but this is the general gist of it.

Could someone help me? I think the order of physics events might be the problem, but I'm very new to physics programming.

gillius
Member #119
April 2000

I didn't examine the code, but I have a general advice that might apply here. The most common problems in physics simulations is that the math (particularly the integration) is not precise because of breaking the simulation into frames. This problem typically destroys all "stable-states" and therefore you need to code specifically for rest states. For example if you write a routine for sliding friction and objects, after getting to where they should finally stop, just studder instead, usually is an example of this case. So you need to put in checks to make sure that friction doesn't reverse the direction, and/or add things to clamp to certain values, such as 0, if the value is close enough (or you can get values like 1e-20 just from floating point error).

Probably if you have an object that's supposed to rest but starts to sink, you are checking for collision but then not reversing the "bad" calculation you just made, so the gravity pulls it down for 1 frame, then you set velo to 0 because it collided, but in the next frame it starts "falling" again. Changing your order of operations and/or checking explicitly for rest states can help. An example: if bounce speed is less than 1 frame's worth of acceleration, set "resting" flag to true then stop calculating gravity until something changes.

Gillius
Gillius's Programming -- https://gillius.org/

edfredcoder
Member #7,985
November 2006
avatar

I tried what you suggested, adding a lower threshold to the velocity. I also changed the order of events; velocities are modified, then collision detection occurs. This has solved my problem, mostly, except that, for the frame when the block is bouncing up, the two blocks overlap. Does anyone know of how to fix this, or maybe another (open source) physics engine I could look at to see how everything works?

Paul Pridham
Member #250
April 2000
avatar

Johan Peitz adapted the "Box2D" physics example for Allegro. Perhaps it could be some help: http://www.allegro.cc/forums/thread/590241

edfredcoder
Member #7,985
November 2006
avatar

Thank you!

Johan Halmén
Member #1,550
September 2001

For the frame where the objects overlap, recalculate the position. Either zero the overlap by adjusting the y position, like if the falling object slows down a bit when collision, then continue. Or mirror the overlap: if in frame n the y position is 0.7 and in frame n+1 the y position is -0.4 and collision is when y position is 0.0, set the y position in frame n+1 to +0.4. This would be a perfect simulation, if we had no friction, no energy loss at collision and no gravity.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Years of thorough research have revealed that the red "x" that closes a window, really isn't red, but white on red background.

Years of thorough research have revealed that what people find beautiful about the Mandelbrot set is not the set itself, but all the rest.

Go to: