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.
Devblog for Assimilation, a game that features modular construction of space craft, Newtonian physics, and some other interesting things.
Showing posts with label Physics. Show all posts
Showing posts with label Physics. Show all posts
Sunday, May 24, 2015
Saturday, October 11, 2014
Flight Controller Logic
Over the summer, I worked on the flight controller. The purpose of the flight controller is to make it easy for any ordinary human or AI to fly an unbalanced spaceship in a game with simulated physics. In space, the laws of inertia become very significant, as anything put in motion will tend to stay in motion. The flight controller would do two things: compensate for inertia so that the craft is easier to control, and allow an unbalanced spaceship to fly straight.
The first step I took, was to try and create an algorithm that would take take a direction/torque as an input, and would accelerate the assembly in said direction/rotation. I figured once I had this, the rest would be relatively easy.
The current way the algorithm works is as follows:
The first step I took, was to try and create an algorithm that would take take a direction/torque as an input, and would accelerate the assembly in said direction/rotation. I figured once I had this, the rest would be relatively easy.
The current way the algorithm works is as follows:
- The force and torque vectors each engine will exert on the assembly are calculated and stored.
- These force/torque vectors are then grouped together to form 6 dimensional vectors, one for each engine.
- These vectors are then transferred into a matrix class as column vectors.
- An additional target column vector is added to the far right of the matrix, this is the "target acceleration" input vector.
- An algorithm puts the matrix into reduced row form using Gaussian elimination. (if you think of the matrix as a system of equations, it essentially solves for the unknowns)
- The last column vector in the matrix now has a list of values. Essentially these are the ratios of the engines to each other required to accelerate in the input vector's direction.
- These values are then scaled to create the maximum thrust possible and the enignes are turned on.
While the algorithm technically works, there are some flaws:
- It does not take into account the fact that engines cannot fire in reverse, so some of the output values can be negative depending on the input and the engines available. This results in engines firing backwards.
- This solution works for only 6 engines exactly, and usually only if their force/torque vectors are linearly independent (ie only one engine for each direction).
So far I have found a partial workaround for the second flaw. If the number of engines is fewer then 6, multiplying the target vector and the original matrix of force/torque values by the transpose of the original matrix creates a matrix with as many solutions as you have engines. This can then be solved to get ratio values that will fire the engines with a resultant force/torque as close as possible to the input target force/torque vector.
Friday, February 28, 2014
Physics Multiplayer
Its been a while since I posted anything here, been very busy, both in college and working on this project. While I have been working on the project quite a bit, I haven't updated this blog much. Much has been changed, its practically a playable demo at this point.
This being a space ship game though, there should be few enough collisions that this should not be a problem.
Multiplayer, has been the most recent feature I have been trying to implement. Adding multiplayer to a game like this is very challenging for several reasons:
- This game is physics based.
- It has to be as lag free as possible for direct user feedback
That's it.
Only problem is, those two things generally don't go together, especially when using unitys physics, here is why:
In most multiplayer games, you have a server and a client, the server runs the official version of the game, and the client runs a similar version that the server updates to be in sync with the server. Even with a very good internet connection, the delay between sending information to a server and receiving the resulting update of the simulation can range from .2-.4 seconds. Say if you press the space key to jump, the signal is sent from your computer to the server in .1-.2 seconds. The server receives the signal, tells your player to jump, then sends the updated position back to the client. So it takes .2-.4 seconds for your command to appear on the clients display.
To fix this delay, client side prediction can be used, how this works, is your player moves immediately after receiving a command, and sends the command to the server. The server then sends its results back to the player. However, this data from the server cannot be used to update the player, its .2-.4 seconds old. The server is constantly sending out its idea of where the player should be. So if this old data is used to correct the players position, then client side prediction will be pretty much invalidated.
To Compensate for this, the data the server sends can be "checked" with what the players position was in the past. If the two don't match closely enough, then an extrapolation is made of where the player would be assuming the two did match. The player is then moved there.
To Compensate for this, the data the server sends can be "checked" with what the players position was in the past. If the two don't match closely enough, then an extrapolation is made of where the player would be assuming the two did match. The player is then moved there.
The server also has to update the other players, since each of them also has a simulation of the world. The flowchart above shows roughly how this would work.
One of the problems with client side prediction though, is you need to predict something based off of old information. With unitys physics, you cannot do this. Unitys physics cannot "rewind" or "resimulate" nor "predict" any part of the physics system. That why making a physics multiplayer is very challenging, especially when using unity.
To get around this problem, you could simulate some data yourself, you would have to have your own simple physics engine essentially. What my project will do, is use a custom rigidbody system that supports "predicting" where it will be in the future. Unfortunately, it will not be possible to check collisions, so those will have to be handled server side, which will likely result in lag glitches during a collision.
This being a space ship game though, there should be few enough collisions that this should not be a problem.
Subscribe to:
Posts (Atom)
.png)