Thursday, August 29, 2013

Let's Do Math! - Guidance Control

Down below you'll find some discussion of doing some "physics-based guidance control," but first the daily update:

Particle Event Components

I basically have two separate particle systems:

One is a pretty typical particle system, it just emits and renders mostly ballistic sprite particles, for explosions or smoke, that sort of thing.

The other is really more of a batch model-rendering system - it takes a single model and spawns multiple rigid bodies, so it has a physical presence in the physics simulation - good for bullets, swarms, that sort of thing.

So, what if you have a bullet, and you want a small explosion when it hits something?

I put together a sort of mediation component that waits for notifications from the physics particle system that a particle is being destroyed, and then it emits a particle on a an explosion particle system.

Which is fine, except now I have a cSpawnParticleOnPhysicsCollideComponent class, which is getting a bit wordy.  There's also a cSpawnParticleOnPhysicsTimeoutComponent class.  It also doesn't trigger any audio yet.  This is going to grow out of control quickly, seems like it needs a rethink.

Now, Let's Do Math!

I wanted to work out the math required to solve this problem:

  • Under a maximum acceleration, how do we turn to face a particular direction as quickly as possible without overshooting the target?

So, you want to start turning in a particular direction, then slow down and come to a stop directly facing your target.  I'm assuming that your target is stationary, otherwise this gets complicated.

First, your velocity under maximum deceleration will look something like this:

where the y-axis is your current speed, x-axis is the amount of time it will take you to stop, and the area under the curve is the distance you will travel.

  • If you are on the line, you just need to decelerate at the maximum rate, and when you hit zero angular velocity, you should be facing the right direction.
  • If you are below the line, you basically want to get to the line as quickly as possible.
  • If you are above the line, you can't slow down fast enough to avoid overshooting the target, but let's do our best...

So what do we need to calculate?

Converting between angular acceleration and torque is pretty easy:
Then you just need to compute the optimal acceleration, and make sure you don't exceed it:

Which looks a bit more sensible in code:

VECTOR4 axis, angle; //Desired rotation
turn_axis_angle(from, to, &axis, &angle);

VECTOR4 w_opt = axis * VECTOR4::sqrt2() * sqrt(angle * max_ang_accel); //How fast we should be turning right now (w0) to decelerate to w=0 after turning angle radians
VECTOR4 w_delta = w_opt - w0; //Difference between optimal and current angular velocities
VECTOR4 w_delta_accel = length3(w_delta) / VECTOR4(GameLib::physics_dt); //Acceleration required to get to optimal by next frame
VECTOR4 w_cmp = w_delta_accel > max_ang_accel; //Choose lesser of optimal and maximum acceleration
VECTOR4 w_accel = sel(w_cmp, safe_normalize3(w_delta) * max_ang_accel, axis * w_delta_accel);
VECTOR4 torque = I * w_accel; //Compute torque from acceleration

OK, I'm not 100% certain that is all correct, but it seems to work, which is a good sign.  :)

All of the math looks very similar for doing the same thing with linear acceleration.

No comments:

Post a Comment