Flying in 3d space with Newtonian physics is tricky. With modular space craft, the center of mass can shift at any time, but even worse, if the object is not symmetrical, then forces generate hard to predict rotational accelerations. On top of this, any force applied will cause the ship to move....and
keep moving, until another force slows it down. These are all things the user would have to take into account when building a ship, and set each engines output and keybinding accordingly, or else the ship would be completely uncontrollable,
The goal of the flight controller is to handle all this in background. It does this through several methods and techniques that together work to make the controls easy to use and user friendly, no matter the ship configuration (Though some designs work better then others).
The flight controller consists of two main parts.
The first part: Give it a target force and torque, and have it fire the engines accordingly.
You may have many engines, but you can only go in one direction at a time. Its follows then, that it would be useful to find how much power to give each engine, to go in a particular direction. This sounds simple, but turns out to be extraordinarily difficult to program. However, this can be modeled as a linear program, and there are linear program solvers that have already done the hard part for you. For those interested, the solver I used is
lp_solve, and the linear program used is on
math_exchange.
To format the problem as a linear program, you need to set each engine throttle as a variable. You also need to calculate the force and torque each individual engine would exert on the spacecraft. You then simply plug these into the solver, along with a target force and torque,
and the linear program solver returns the throttles each engine needs to be set too.
This gets further complicated by one thing: When rotating, torque is
not equal to angular acceleration*mass. In 3d space, if you apply a torque on something, the resulting angular acceleration depends on the
distribution of that mass, that's why if your spinning on a chair, and you pull your arms in, you spin faster, its also why if you rotate something, its better if its symetrical. The distribution of mass of a 3d object relative to a pivot point, is commonly represented as something called an
Inertia Tensor. An inertia tensor is a 3x3 matrix, and by doing some math operations involving it and target angular acceleration, we can get the torque required to produce the given angular acceleration.
Using the above, we can feed the flight controller a target angular acceleration, and target force, and the flight controller will fire the engines to produce it as closely as it can. The problem now is to figure out which angular acceleration and force we want to produce.
The second part: finding a target angular acceleration and force.
Before this part can be solved, we need to consider how the player expects the controls to work. In most cases, you aim with the mouse, and use the arrow keys to move. So, given a direction (from the user aiming the mouse), the ships current direction (ie: which way it is looking), we need to find a force/torque to rotate the ship to point in the desired direction. For moving around, we need to, given a target movement direction, move in that direction, by producing a force in that direction.
Finding the target force is the easiest part. Simply map each arrow key to a vector which points in the expected direction. So "w" would be mapped to a forward vector, pressing it would call the flight controller with this vector*maximum_force as the force vector. The flight controller would then accelerate in the given direction.
Finding the target angular acceleration, to rotate from one direction to another is a bit more complex. I used a
PD controller to solve this part. Essentially, the pd controller takes the angle between the desired direction and the current direction, and the current angular velocity, and returns an angular acceleration to try and minimize the errors. It takes into account the maximum angular acceleration and two tuning constants as well. The constants are for tweaking how much the controller responds to the error in angular velocity and the angle error.
That's the flight controller for the most part. It sounds simple enough explaining it like this, but the flight controller has been the toughest part of this project out of the 4 years since I came up with idea. Now that its working quite well, I can work on the things that wouldn't be possible without it. Specifically: gameplay elements, AI etc.