Monday, December 13, 2010

Vector Math

I ran into a fun  problem while working on The Bridge today:

In my process of refactoring the ship engine, I added a rotational thruster to turn the ship. When the player issues a Turn Clockwise command, the Navigator AI will apply the rotational thruster to the ship until it reaches the desired velocity.

Here are the properties I worked with:
  • A target yaw, pitch, and roll to rotate to, in terms of angular velocity
  • Current angular velocity of the ship
  • Angular acceleration of the ship's engines

Each of these I represented as a Vector3 in XNA
  • Vector3 targetAngularVelocity;
  • Vector3 currentAngularVelocity;
  • ship.engines.angularThrust

I figured that the most logical way to approach this was to adjust angularThrust every frame in an Update loop. The challenge was figuring out what acceleration was appropriate, when only given currentAngularVelocity and targetAngularVelocity.

My first attempt involved finding a midpoint vector with a simple LERP:
ship.engines.angularThrust = Vector3.Lerp(currentAngularVelocity, targetAngularVelocity, strength) * time;
This works when going from not rotating at all, to rotating in some direction. However, it fails miserably if the ship is already moving in some capacity. I ended up spinning the player's ship phenomenally fast.

Clearly, a midpoint isn't good enough, I need something a bit more relative.

Thankfully, a simple Vector Math trick works nicely:
ship.engines.angularThrust = (targetAngularVelocity - currentAngularVelocity) * strength * time;
Subtracting targetAngularVelocity from currentAngularVelocity will give me a new Vector that points from currentAngularVelocity  to targetAngularVelocity . Then all I need to do is shrink the strength of the vector down to a reasonable acceleration, and I'm done.

And thanks to the miracles of Vector Math, this will work in any direction, under any circumstance.