Body/LinearVelocity for Airplanes (Aerodynamics)

Hello,
I’ve been wondering with how aviation games like Neo Warfare, Aircraft Carrier, etc. make semi-aerodynamic physics for their airplanes. This is bumping my previous topic which was left on read.

When making vehicles in Roblox, they require a mover. There are many movers used for vehicles, the most common being the BodyVelocity, if not, the LinearVelocity. They are known for its versatility, showing its capability for many including projectiles.

They have 2 essential properties, which are the .Velocity and .MaxForce. I’ve tried making a basic flight physics for my airplanes, which work similarly to most performance games, Naval Warfare for example.

Naval Warfare’s airplanes relies on just 2 movers: a BodyVelocity, for thrust, and BodyGyro for maneuvering. By default, it stays unpowered, in which both movers have zero torque. When entering flight mode, they are given a high amount of torque, allowing it to fly “like an airplane”. However, they are unrealistic for having no de/acceleration influenced by gravity/weight and tight maneuvers.

In Neo Warfare, their aerodynamic physics are sufficient for an aviation game. They have proper de/acceleration, stalling, and roll.

  1. Acceleration. Any objects that move have acceleration. For airplanes, they are powered by thrusters. In Neo, it relies on the amount of throttle% that is put, and a maximum acceleration rate, which I believe.

  2. Stalling. The most intriguing one, and what I’m trying to achieve currently. When an aircraft could not generate enough lift, influenced by speed and angle of attack, it will start to stall. With the use of BodyVelocity, I am really confused with how this is done in said games.
    BodyVelocity has the .MaxForce property. The higher it is, the faster it will reach the speed of its inputted .Velocity, or, just instant if high enough. And if it is, it would completely ignore gravity and try to stay on its last position.
    This is what I am experiencing on my aircrafts. I tried solving this by checking its speed. If it is higher than a constant value of stallSpeed, it will remain high on torque. If it is equal or under, it will lose its torque, which allows it to “stall”. But the twist, during the freefall, it starts to speed up, relying on gravity, exceeding the stallSpeed, in which it receives a high torque that stops gravity from interfering, going speed of under stallSpeed again, thus creating a cycle. This is something that should not be a thing. On a second thought, do they really use BodyVelocity? I have no idea.

  3. Roll. This is about BodyGyro, and not BodyVelocity. If an aircraft banks/tilts sideways (longitudinal axis), it will steer by its vertical axis to the direction it is banking. This is what was done in both said games, and others as well.

I find it unpleasant with how little to aviation-related topics in this forum are paid with attention. Some are answered with what I find is like me as a 5 year old being taught the Pythagoras theorem, and some are left unanswered. I don’t understand math well.

I’ve tried watching this video with no outcome from my bland mind as it was too realistic compared to Neo and what I’m trying to achieve, or just that again I don’t understand with what’s being explained. Realistic Aerodynamics for Games


Overall, if I really use BodyVelocity, how could I achieve the said desire? If not, let me know with what I should do.

Other than that, thank you for reading.

1 Like

Its possible to do all the physics in a script and essentially translate the result to forces on the center of gravity. That is you could still have just one linear velocity and gyro. You can also just set the position and rotation manually, as long as you do it every physics step.
There are many models for lifting surfaces with different trade offs, the ones used for fluid simulation are not suitable for games. You should make the following assumptions right off the bat:

  • The aircraft is one rigid body, the components can’t move relative to each other, e.g. through bending.
  • Lifting surfaces behave as if they are the only surface, they do not cause changes in the behavior of any other surface. You may have to make exceptions in specific cases, the effect of propeller slipstream on a small aircraft is not negligible, for example.

You can simulate lifting surfaces with varying degrees of realism. The important thing is that any force it produces conserves momentum, otherwise you have an unstable simulation which can “freak out” under hard to identify conditions.

The simplest lifting surface (with no drag) is a infinitely thin plate that produces force because of the momentum change necessary to push air out of the way. Drag is produced in two ways, the drag from air slipping along the surface of the plate, and the pressure required to move the air in the aforementioned way to produce lift. That last part is hard and has its own range of approximations.

1 Like

I don’t know how to simulate it since I don’t know what to do. If all the 4 laws of aerodynamics are possible in the BodyVelocity alone, do I combine it all into the single mover? How do I achieve lift? How do I achieve drag? How do I achieve weight? Do I multiply stuff with stuff? Which stuff should I do with exactly? If I have achieved one equation, what is the next step? I don’t know.

My weighted shackles is with all the complex mathematical operations that I don’t know how to start with.

To mention that I’ve tried to learn all the formulas of each law from articles like NASA’s… well, I tried.

why do you want to use gyros and BodyVelocity? just use forces and moments like a normal person, apply those every frame to the center of mass of your plane.

you just need to calculate every force and moment acting upon the craft and add all individual forces and moments together, then apply them with :ApplyImpulse() & :ApplyAngularImpulse()

drag is just a force along the opposite direction of the velocity
lift and side force directions are slightly more complicated, for that you need to know the angle of attack and sideslip

the aerodynamic equation is C * Q * S
where
C is the coefficient (either lift, drag or side force)
Q is the dynamic pressure (true_airspeed^2 * .5 * air_density)
S is the reference area (most commonly wing area)
the aerodynamic coefficients are the annoying part, you cant calulcate them you can only measure them and then use those numbers as predefined values, flight simulators use lookup tables at all kinds of different conditions to figure out the coefficient of lift, drag and side force at that particular frame in time, theres also a linearized way to get a coefficient at a certain state called stability derivatives, which is just a single number multiplied by the state in question (such as angle of attack) to get the coefficient at that dynamic configuration of the aircraft, but its only good for less important characteristics of the plane, a stability derivative will work for lift vs aoa, but only for small angles, and it is unable to model stalling on its own

if you want to i can give you a more in-depth explanation

My knowledge is capped within the use of said BodyMovers.

I have barely learnt about :ApplyImpulse, hence not knowing a potential use for this.

I’ve read somewhere that the coefficients are presented as a constant value, and you tell me that all of the force’s coefficient is combined into one. The thing is, what do I do exactly with this aerodynamic equation? Is it the final value to be put using :ApplyImpulse? Wait, how does that even work? Did we miss .LookVector of the aircraft? I’m confused…

I’ve just heard of this stability derivative thing. I don’t quite understand by what you mean with being a multiplication result of various ‘state’. How is this implemented? I might need an explanation via example.

Stall model is the very secured gemstone here. If I’m not aiming for this much of aerodynamics behavior, stalling is at the very least I need. However, I am not looking for that much of realism, so sideslip can go.

My idea is having these pre-defined values: maxSpeed, stallSpeed, maxAltitude, etc. Is that what you mean by ‘lookup tables’?


I am focusing on performance. I want to have as little as possible memory usage from the script.

If you can’t figure out how to simulate a plane yet, simulate a parachute. That’s a lifting surface where the air always hits it from the same direction.

Well in that case let me explain anything and everything about flight dynamics to you in a way you won’t understand!

A dynamic configuration is the exact state the aircraft is in at that moment in time; its airspeed, pitch angle, bank angle, yaw, angle of attack, angle of sideslip, pitch rate, aoa rate etc. all these factors combined determine the aircrafts forces and moments, some of those factors are negligible, others aren’t. The most important and prominent one is the angle of attack or AoA, also denoted as α.

The angle of attack of an airfoil is the angle between its chord line and the airflow relative to it:


This is THE primary component of lift, as the angle increases, lift increases, if the angle of attack reaches a critical angle, the airflow will separate and the wing will stop producing lift.
Here’s an example graph of the F-16:

As you can see, at a little over 35 degrees AoA the lift coefficient starts going down again, this is what a stall looks like. Basically all Cl vs α curves look like this, it goes up almost linearly and then drops off. And here’s where stability derivatives lie in. If you sample 2 coefficients at 2 angles of attack, you can get a slope/derivative, a derivative is the rate of change of a thing in regards of another thing, velocity for example is the rate of change in position. A stability derivative can be calculated like this:
change in force (or coef) / change in dynamic configuration
Here’s an example on a lift coefficient curve:

Here the resulting stability derivative is 0.13 units of lift coefficient per degree of angle of attack, if you multiply any number by this number, you will get the coefficient of lift at that angle of attack, assuming the AoA is in degrees. This linearization generally works for smaller things that actually are linear, as you can see the Clα curve is not linear, it curves downwards eventually, so the stability derivative method will work for the main lift, up until the critical angle, at which point it will just keep increasing and therefore not model stalls, you can come up with a quadratic equation that closely matches the actual numbers, or you can just use a look-up table, which is what Microsoft Flight Simulator does, they also use stability derivatives for less significant factors that can be linearized, unlike the Clα curve.
A stability derivative also doesn’t take into account any offset that may be present at α = 0, cambered airfoils for example generate lift at 0 angle of attack, but there’s a simple solution: just add the difference after calculating the coefficient.

Look-up tables

A look-up table is exactly what is sounds like, it’s a table full of numbers which specify how much lift a given angle of attack gives.
Here’s an example of how a lookup table might look:


Here the left column is the angles of attack and the right column are the coefficients of lift. According to this table at 15 degrees of AoA the lift coefficient is 1.6.
You’re probably asking yourself now “but what if the plane is at an AoA that has no table entry? Like 4.5 for example? what if it’s some ridiculously specific number like 4.543534765474234234534534?? You can’t have infinite precision, it’s just not possible, so how do account for that?”
Simple, get the closest number below 4.5 and the closest number above 4.5 and interpolate the two coefficients at those angles. Now you can get the coefficient of lift at any angle of attack as long as the input aoa is within the minimum and maximum specified range. Here’s what the graphed out table looks like:

And this is also what the entire 360° spectrum of lift vs aoa looks like for the NACA 2412 airfoil, generally you won’t find this information anywhere as no one cares about numbers below -5 and above 15 degrees, but if you plane is tumbling or something where the aoa keeps changing rapidly and goes in all sorts of different areas, you need to get some number for your calculations to avoid errors or unwanted behavior.
So, Either make up numbers or try to find them on the internet, there’s a site called airfoiltools.com where you can get aerodynamic data of various NACA airfoils. Apply this method for the other forces/moments, drag, side force, pitch, yaw, roll and you got your coefficients!

Now we can finally move on to getting the forces and moments, and making the plane actually move.

There’s 5 total forces acting upon an aircraft. No, not 4. 5.
Lift, Drag, Weight, Thrust and the Side force. The side force is basically lateral lift created by the fuselage and the tail of the plane if it flies with a yaw angle, which is not negligible. We won’t talk about weight and thrust because I don’t know how to model engines and weight is already done by Roblox. Just add a forward force * a throttle setting or something.

Drag acts in the direction opposite the airflow:
dir_drag = -aircraft.Velocity.Unit That’s it.

Lift and side forces act perpendicular to the direction of the airflow.
A common misconception is that lift acts upward of the actual airfoil/aircraft, THIS IS NOT TRUE, THAT IS THE NORMAL FORCE! You can use either lift & drag, or normal & axial forces, you don’t need both. if you know one pair of forces, you can figure out the other.


So now we need the angle of attack (again), to get the direction of lift:
Assuming -Z is the forward direction, you can calculate the angle of attack as such:
AoA = atan2(-v.Y, -v.Z)
and while we’re at it, sideslip:
AoS = asin(v.X / v.Magnitude)
Note the v is the velocity in the local body frame of reference, which can be calculated as:
aircraft.CFrame:VectorToObjectSpace(aircraft.Velocity) (i think you may have to normalize it so put a .Unit at the end just in case, idk tho)
Now you can rotate the body frame into what’s called the wind axis:
windex = aircraft.CFrame * CFrame.Angles(-AoA, 0, 0) * CFrame.Angles(0, -AoS, 0)
(idk why theres so many minus signs, im just copy pasting my code which works)
Using this CFrame you can— no. no you don’t use that CFrame to set the plane’s position no. This CFrame will act as the wind frame of reference, if you remove the sideslip term you’ll get the stability frame (which is stupidest reference frame seriously who uses this)
Now you can get the lift and side direction:
dir_lift = windex.UpVector
dir_side = windex.RightVector
dir_drag = -windex.LookVector - or just the negative velocity unit, both works

Ok now let’s start with calculating the lift force.
We will use a very simple model with only one parameter for lift:
Cl_α - Cl vs angle of attack
First you get the lift coefficient from the angle of attack, whether it be from a lookup table, quadratic function or a stability derivative.
Then you get the density of the air at the aircrafts position, which varies with altitude, you can use either the international standard atmosphere table or just google the equation for air density vs altitude it’s a really simple equation.
The air density unit will be in slugs/ft^3 and the velocity in feet/sec and with it you calculate the dynamic pressure:
Q = air_density * .5 * aircraft_velocity.Magnitude^2
The reference area S can be any number you want, in square feet
And here’s your final lift force:
F_lift = Cl_a(AoA) * Q * S
(forces are in pounds)

Now on to drag:
Drag is both created by the air pushing against the plane, called parasitic drag and the compressibility of the air as the plane approaches the sound barrier, called wave drag. But is also induced via lift, that’s why we calculated the lift first, we don’t need the lift force, just the coefficient. And the parasite drag… can be neglected for some reason?? Because Microsoft Flight Simulator actually neglects parasitic drag vs angle of attack, and only uses lift-induced drag + parasitic drag at AoA = 0, so if this is good enough I guess we can simplify this and just use 1 constant for drag at 0° AoA.
We can ignore wave drag.

Hence, the drag coefficient is calculated as:
Cd0 = any number you want, generally between .01 - .025 – drag at 0-aoa

Cdi = (Cl_a(AoA)^2) / (pi * AR * oswald) - lift induced drag
Where
pi is 3

AR is the aspect ratio of the wings, calculated as: (wing_span^2) / wing_area

oswald is the oswald efficiency factor, generally less than 1

(MSFS calculates induced drag slightly differently and I can give you their equation if you want, but this is good enough)

And the total drag force is:
F_drag = (Cd0 + Cdi) * Q * S

Side force:
ughhh let’s move on

Moments
The general moment equation is similar to the lift & drag equation but with 1 extra parameter: wing span (b) for yaw and roll, or mean geometric chord (c_) for pitch

Let’s start with the pitch moment
As the angle of attack increases, the plane will either want to pitch down if it’s stable, not do anything if it’s neutral, or pitch up even more if it’s unstable. You can use a simple stability derivative for the pitching moment even though a lookup table would be better as the pitching behavior changes post-stall.

So the pitching moment is calculated quite easily:
M_pth = (CM_a * AoA) * Q * S * c_
except, you can’t ignore dynamic effects and you need to include at least one extra factor:
The pitching moment due to pitch rate (CM_q), there’s also the pitching moment due to AoA rate (CM_adot), so we might as well just include that as well.
These are generally linearized so 1 single number for both will be enough, no need for tables. You want CM_q to be negative and this derivative can get quite large.
These are also called damping coefficients, these are required so that your plane doesn’t pitch up and down like crazy, like a spring without a damper.
Since these are dynamic coefficients you can’t just add them onto the main pitching moment coefficient, you need to add them onto the total pitching moment like this:
M_pth = M_pth + (((CM_q * q) + (CM_adot * adot)) * ((c_)/(2*airspeed)) * Q * S * c_)
Where q and adot are the pitch rate and aoa rate respectively

Do the same thing with the yawing moment:
M_yaw = (CN_b * AoS) * Q * S * b
M_yaw += (((CN_r * r)) * ((b)/(2*airspeed)) * Q * S * b)
Once again, CN_b is the yawing moment vs sideslip, AoS is sideslip, CN_r is the yawing moment due to yaw rate and r is the yaw rate itself

And of course roll just damping:
M_roll += (((CL_p * p)) * ((b)/(2*airspeed)) * Q * S * b)

Of course, if you want to add controls, all you need to do is add another extra coefficient and multiply it by the deflection of the flight stick.
for example:
M_roll += (CL_da * ail) * Q * S
where CL_da is the roll moment due to aileron deflection and ail is the aileron deflection. Do the same for pitch and yaw and you got working controls.

Now to make the aircraft move:
Since you asked, :ApplyImpulse() and :ApplyAngularImpulse() just simply apply a force and a moment (or torque) to a part, that’s it. Imagine pushing something, yeah that’s it.

So you add up all forces:
F_lift3d = dir_lift * F_lift
F_drag3d = dir_drag * F_drag
F_thrust3d = aircraft.CFrame.LookVector * F_thrust

And you apply the forces:
aircraft:ApplyImpulse(F_lift3d + F_drag3d + F_thrust3d)

And the moments are in the local object space, so it’s slightly different:

aircraft:ApplyAngularImpulse(
    (-aircraft.CFrame.LookVector * M_roll) +
    (aircraft.CFrame.RightVector * M_pth) +
    (aircraft.CFrame.UpVector * M_yaw)
)

There you go, do that every frame and you got a very basic simple plane

you can also just use the built-in roblox aerodynamics if you dont want any realism