Using the below key bindings, my AR_Aircraft class has the following code:
Note, to implement the aircraft 'properly' as UDK does, I have three classes: AR_Aircraft (extends UTAirVehicle), AR_AircraftContent (extends AR_Aircraft), and AR_AircraftFactory (extends UTVehicleFactory). For more information, look at the Cicada. The code for the AR_Aircraft class above should help anyone implement (very) rough aircraft physics.
class AR_Aircraft extends UTAirVehicle;
/* etc */
var float AR_MaxLift, AR_TurnSpeed, AR_Speed, AR_CurrentForward, AR_AddedLiftSpeed, AR_Acceleration;
/* etc */
simulated function AirRaidKinematics(float DeltaTime)
local Vector AR_ForceApplication, AR_ForceRotation, AR_ForwardsNormal, AR_UpwardsNormal, AR_SidewardsNormal;
local Vector AR_ForceRotationVectX, AR_ForceRotationVectY, AR_ForceRotationVectZ;
local float AR_Lift, AR_ForwardSpeed, AR_NewRise;
// While there is a player in the biplane:
if (PlayerController(Controller) != None)
GetAxes(Rotation, AR_ForwardsNormal, AR_SidewardsNormal, AR_UpwardsNormal);
// It's probably unnecessary to normalise these:
AR_ForceRotationVectX = Normal(AR_ForwardsNormal);
AR_ForceRotationVectY = Normal(AR_SidewardsNormal);
AR_ForceRotationVectZ = Normal(AR_UpwardsNormal);
// Rise is NOT between -1 and 1, like it said it was
AR_NewRise = 0;
if (Rise != 0) AR_NewRise = Rise / Abs(Rise); // Avoid divide by 0
// Calculate the XYZ components of the relative steering:
// Generic controls Steering, Throttle and Rise are set by the controller
AR_ForceRotationVectX.X *= 35 * -AR_NewRise; // Steering is between -1 and 1
AR_ForceRotationVectX.Y *= 35 * -AR_NewRise; // Steering is between -1 and 1
AR_ForceRotationVectX.Z *= 35 * -AR_NewRise; // Steering is between -1 and 1
AR_ForceRotationVectY.X *= 30 * Throttle; // Throttle is between -1 and 1
AR_ForceRotationVectY.Y *= 30 * Throttle; // Throttle is between -1 and 1
AR_ForceRotationVectY.Z *= 30 * Throttle; // Throttle is between -1 and 1
AR_ForceRotationVectZ.X *= 25 * -Steering; // AR_NewRise is between -1 and 1
AR_ForceRotationVectZ.Y *= 25 * -Steering; // AR_NewRise is between -1 and 1
AR_ForceRotationVectZ.Z *= 25 * -Steering; // AR_NewRise is between -1 and 1
// Add them together to get final global rotation vector:
AR_ForceRotation.X = AR_ForceRotationVectX.X + AR_ForceRotationVectY.X + AR_ForceRotationVectZ.X;
AR_ForceRotation.Y = AR_ForceRotationVectX.Y + AR_ForceRotationVectY.Y + AR_ForceRotationVectZ.Y;
AR_ForceRotation.Z = AR_ForceRotationVectX.Z + AR_ForceRotationVectY.Z + AR_ForceRotationVectZ.Z;
AR_CurrentForward += AR_Acceleration * Throttle;
AR_ForwardSpeed = AR_CurrentForward * 2.2;
// AR_ForwardSpeed is not necessarily true - I'd optimally need to use some
// calculation based off Velocity and current forwards direction Vector...
// Calculate lift for the biplane:
AR_Lift = (AR_ForwardSpeed + AR_AddedLiftSpeed) * Abs(Cos(Rotation.Pitch));
if (AR_Lift > AR_MaxLift) AR_Lift = AR_MaxLift;
// This gives lift upwards relative to its up-axis and push forwards relative to its forward-axis:
AR_ForceApplication.X = AR_UpwardsNormal.X * AR_Lift + AR_CurrentForward * AR_ForwardsNormal.X;
AR_ForceApplication.Y = AR_UpwardsNormal.Y * AR_Lift + AR_CurrentForward * AR_ForwardsNormal.Y;
AR_ForceApplication.Z = AR_UpwardsNormal.Z * AR_Lift + AR_CurrentForward * AR_ForwardsNormal.Z;
// Add forces and rotations
AR_CurrentForward = AR_Speed; // Biplane propellor thrust sets to default
simulated function Tick(float DeltaTime)
/* etc */
As mentioned, I changed the key bindings for my specific game inside UTInput.ini:
Q, E to roll.
A, D to yaw.
W, S to pitch (also gains speed).
LeftControl to hop in or out (replaces E).
(Without changing bindings, the normal controls would be C, Spacebar to roll)
By all means, take the code, extend it, and reply to me with what you've done with it.