Here is some code that I was proud of when I was building my senior game project, Boxland, while studying at DigiPen.
/*
This is the Update loop for a very basic Impulse Physics engine.
Quicklist is just a linked list that I made which has some additional functionality that I wanted. Here, it is a container for all game objects that are active in the game currently.
The main goal of the first loop pass is to update the positions of all game objects.
Then the second loop will make sure that none of the objects are inside each other after moving by Depenetrating them.
*/
void UpdatePhysics(QuickList<GameObj*>& ObjsAll)
{
// gravity/integration pass
MaxIterator it = ObjsAll.Front();
for(int i=0;i<ObjsAll.Size();++i)
{
// reset collision flags
for(int i=0;i<6;++i)
it->Data->cflags[i] = false;
// add gravity
if(it->Data->dynamic)
it->Data->vel += vec3(0,GravityValue,0);
// positional integration
it->Data->pos += it->Data->vel;
// rotational integration
it->Data->rot += it->Data->rotvel;
it = it->Next;
}
// collision/resolution pass
it = ObjsAll.Front();
for(int i=0;i<ObjsAll.Size();++i)
{
if(!it->Data->ischild && it->Data->dynamic)
CollideWithAll(it->Data);
it = it->Next;
}
}
/*
This will perhaps look very un-optimized and slow, because every game object appears to check for collision with every other in the game world.
Dynamic objects are those that move around freely and are affected by Gravity such as the player, monsters, and boulders.
*/
void CollideWithAll(GameObj* o)
{
if(o->dynamic)
{
MaxIterator it2 = ObjsAll.Front();
for(int j=0;j<ObjsAll.Size();++j)
{
if(it2->Data != o)
{
CollideWithOne(o,it2->Data);
}
it2 = it2->Next;
}
}
}
/*
Here is where the collision detection is done between two Box bodies.
*/
void CollideWithOne(GameObj* o, GameObj* o2)
{
vec3 pen = o->pos - o2->pos;
vec3 dist = o->pos - o2->pos;
vec3 dist2 = o->pos - o2->pos;
vec3 diff = o2->scale + o->scale;
int dir = 1;
pen.abs();
dist.abs();
pen -= diff; // penetration depth needed
if((dist.x < diff.x) &&
(dist.y < diff.y) &&
(dist.z < diff.z)) // then we're colliding
{
o->collisions.PushBack(o2);
if(o2->collidable)
Depenetrate(pen, dist2, diff, dir, o, o2);
}
}
/*
Now the two objects have been found to need Depenetration because they are overlapping after moving.
*/
void Depenetrate(vec3 pen, vec3 dist2, vec3 diff, int dir, GameObj* o, GameObj* o2)//, bool ischild, GameObj* parent)
{
for(int k=0;k<3;++k) // check all 3 axes x,y,z
{
// resolve along axis with smallest penetration
if(pen[k] > pen[(k+1)%3] &&
pen[k] > pen[(k+2)%3])
{
if(dist2[k] < 0)
dir = -1;
if(!o2->dynamic) // a collision with a static object
{
if(o->ischild)
{
o->parent->pos[k] = o2->pos[k] + dir*diff[k];
o->parent->vel[k] *= -0.3f;
}
else
{
o->pos[k] = o2->pos[k] + dir*diff[k];
o->vel[k] *= -0.3f;
}
}
else // a collision with a dynamic (movable) object
{
// depenetrate
o->pos[k] -= pen[k]/2.0f*dir;
o2->pos[k] += pen[k]/2.0f*dir;
// swap velocities (if same mass)
vec3 tempvel = o->vel;
o->vel = o2->vel;
o2->vel = tempvel;
}
if(k==1) // y-axis
{
// set bottom collision flag
o->cflags[0] = true;
// apply friction with ground
o->vel = o->vel*0.80f;
}
}
}
}
In this picture you can see this basic physics in action. The player (turquoise with sphere head), is standing on a small stack of blocks that can be pushed around.