glCombat - Week 2 - Projectiles & Explosions
Another week has passed. But this time, things have slowed down as real life took its toll. Focus was on the projectiles and their explosions.
A projectile primer
Moving with Gravity and Drag
Animating a projectile is rather simple. You set its initial position and velocity.
Then each frame, you move the projectile by the traveled distance. This is computed as the velocity multiplied by the time.
It is not totally accurate, but given than the frames are short enough and it is a game not a simulator, it is fine.
Each frame you also have to modify the velocity to take gravity into account, along with drag. Again this is done with the same technique. Gravity and drag vectors are added to the velocity vector, with a factor that depends on the time.
This is known as integration, and is a fundamental mathematical construct. It is used to convert acceleration into speed into distance. Note that we only approximate the real value with that technique.
Gravity is a constant vector, aimed down. Drag is depending on the velocity, and directly opposed. So instead of complex computation, we’ll apply gravitation first, and drag is done via a simple constant multiplication that is smaller than 1.
Note that the drag is usually quadratic to the speed. Which means a factor of the speed squared. But as a first step we’ll pretend it is linear only.
Collision
At the end of the projectile course there is usually a collision. For now only the collision with the map is handled.
The algorithm is very simple :
- move the projectile
- if the projectile is below the height of the map, it does explode.
- loop
Computing the height of the map at a (x,y) point is tricky, as the quad is not a plane. We cut it in 4 triangles last week. For a first approximation, we simply take the highest vertex of the quad and use that for the whole quad. It works well enough, except for high slopes.
Explosions
Explosions are very simple: a translucent expanding sphere.
It works rather well, as it enables to modulate
- the blast radius, with the final size of the explosion
- the damage, with the alpha transparency. More powerful, more opaque.
That provides an immediate visual clue of both. Testing will tell if it my idea is accurate.
Small Performance Improvement
The biggest time consumer is the map drawing. I managed to improve by 30% moving from glVertex3f(x, y, z);
to glVertex3fv(v);
.
As struct v3f
was already similar in memory than the required float v[3]
a simple cast did the trick to hide the magic from the outside.
static inline float* v3f_to_f3v(struct v3f *v) {
return (float *) v; // Raw cast
}
and the usage becomes
float *n = v3f_to_f3v(& o->vertices_normal[vertice_normal_idx]);
glNormal3fv(n);