Add flaps: flappable tag, flap lever on the control node, flap physics (0.4.0)

Shift-right-click a block in improved_aerodynamics:flappable to make it a flap.
G/H step the node's flap lever UP/TAKEOFF/LANDING; flaps slew to the configured
angle, add lift and drag and raise the stall angle, and retract above a max speed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YVREx3uo7nz1FEhzveWTUh
This commit is contained in:
Claude committed 2026-11-11 18:36:28 +01:00
1 parent 70eb237d70
commit 1be7e90ec2
18 files changed
+525 -13

No files matched your search

@@ -27,6 +27,12 @@ final class ImprovedAero {
private static final double MAX_DEFLECTION = Math.toRadians(20.0);
// Share of the deflection that acts as angle of attack, gives Warium's control authority at the design speed
private static final double FLAP_EFFECTIVENESS = 0.75;
// How much of the lift a flap adds raises the stall angle, and the parasitic drag coefficient per radian² of flap
// Share of the flap's deflection that acts as angle of attack: 35 degrees of landing flap adds about 1.1 to the
// lift coefficient, like a real plain or slotted flap
private static final double FLAP_ALPHA_FACTOR = 0.4;
private static final double FLAP_STALL_GAIN = 0.7;
private static final double FLAP_DRAG = 0.35;
// Angle of attack of a level cambered wing, where K is calibrated
private static final double REFERENCE_ANGLE = Math.toRadians(4.0);
private static final double REFERENCE_SPEED = 40.0;
@@ -62,10 +68,11 @@ final class ImprovedAero {
* @param w ship angular velocity, ship axes
* @param r block center relative to the center of mass, ship axes
* @param input control input of the surface, -1 to 1
* @param flap flap deflection in radians, 0 for surfaces that are not flaps
* @param stalled whether the surface was stalled in the previous substep
* @return whether the surface is stalled now
*/
static boolean evaluate(AeroSurface s, double[] v, double[] w, double[] r, double input, double weight,
static boolean evaluate(AeroSurface s, double[] v, double[] w, double[] r, double input, double flap, double weight,
Tuning tuning, boolean stalled, Wrench out) {
// Airflow at the block: ship velocity plus w x r
double vx = v[0] + w[1] * r[2] - w[2] * r[1];
@@ -114,6 +121,10 @@ final class ImprovedAero {
// Same sign convention as Warium: positive input pushes along n while moving against the facing
alpha += FLAP_EFFECTIVENESS * MAX_DEFLECTION * input * (u <= 0.0 ? 1.0 : -1.0);
}
// A flap bends the airfoil's camber whichever way the air comes, so it always adds lift, and it moves the stall
// up with it: a flap raises the highest lift a wing can make
double flapShift = FLAP_ALPHA_FACTOR * flap;
alpha += flapShift;
alpha = Math.max(-Math.PI / 2.0, Math.min(Math.PI / 2.0, alpha));
// Low aspect ratio wings keep their flow attached longer thanks to leading-edge vortices. Control surfaces
@@ -124,6 +135,9 @@ final class ImprovedAero {
: s.wingGroup() && s.type().controllable ? SurfaceType.WING.stallAngle : s.type().stallAngle;
double critical = Math.toRadians(baseStall) * (1.0 + tuning.vortexStallBonus() * vortexFactor) * tuning.stallAngleScale();
double absAlpha = Math.abs(alpha);
if (alpha >= 0.0) {
critical += FLAP_STALL_GAIN * flapShift;
}
// Flips only where both blends agree, so the hysteresis never makes the force jump
if (!stalled && absAlpha > critical + STALL_BLEND) {
stalled = true;
@@ -156,7 +170,7 @@ final class ImprovedAero {
double dy = -(vn * ny) / planeSpeed;
double dz = -(u * cz + vn * nz) / planeSpeed;
double liftForce = q * lift * tuning.liftScale();
double dragForce = q * drag / m;
double dragForce = q * (drag + FLAP_DRAG * flap * flap) / m;
out.addForce(r, lx * liftForce + dx * dragForce, ly * liftForce + dy * dragForce, lz * liftForce + dz * dragForce);
return stalled;
}