Skip to content

Instantly share code, notes, and snippets.

@brihernandez
Last active August 11, 2023 03:51
Show Gist options
  • Save brihernandez/f92f666d0103e67392b0d88eb29db4f9 to your computer and use it in GitHub Desktop.
Save brihernandez/f92f666d0103e67392b0d88eb29db4f9 to your computer and use it in GitHub Desktop.
Freelancer ship physics for Unity. Includes engine kill and thruster.
// ====================================================================================================
// In my codebase, all ships have their own instance of this that they use to apply physics with.
// I'm using a struct mostly because I want to maintain copy semantics.
// ====================================================================================================
public struct FlightInput
{
public float Pitch;
public float Yaw;
public float Roll;
public float Throttle;
public float StrafeHorizontal;
public float StrafeVertical;
public bool IsEngineKill;
public bool IsThrusterActive;
public bool IsReversing;
}
// ====================================================================================================
// These are the member variables used for physics. The values here are taken from 88 Flak's Defender.
// In the actual Unity C# class, these are all properties that are exposed to the Inspector.
// ====================================================================================================
// Physics
public float Mass = 150f;
public float LinearDrag = 155f;
public Vector3 AngularDrag = new Vector3(50000f, 50000f, 50000f);
public Vector3 AngularInertia = new Vector3(12500f, 12500f, 12500f);
public Vector3 SteeringTorque = new Vector3(120000f, 120000f, 120000f);
public float BankLimit = 80f;
// Engine
public float ThrustForce = 24000f;
public float BoosterForce = 12000f;
public float ReverseFraction = .5f;
public float StrafeForce = 18000f;
// ====================================================================================================
// These functions are the core of Freelancer's physics. It's pretty straightforward since it uses
// linear drag for everything. The actual application of of the physics forces (thrust etc) are handled
// by Unity's Rigidbody, and all that math works out the same because physics is just physics.
// ====================================================================================================
private void ConfigureRigidbody()
{
Rigidbody = gameObject.AddComponent<Rigidbody>();
Rigidbody.mass = Mass;
Rigidbody.useGravity = false;
Rigidbody.angularDrag = 0f;
Rigidbody.drag = 0f;
Rigidbody.inertiaTensor = AngularInertia;
Rigidbody.centerOfMass = Vector3.zero;
}
private void RunShipPhysics()
{
// Ship thrust
if (GetIsEngineRunning())
{
var forwardThrustForce = FlightInput.IsReversing
? -ThrustForce * ReverseFraction
: ThrustForce * FlightInput.Throttle;
forwardThrustForce += FlightInput.IsThrusterActive ? BoosterForce : 0f;
var appliedLinearForce = new Vector3(
StrafeForce * FlightInput.StrafeHorizontal,
StrafeForce * FlightInput.StrafeVertical,
forwardThrustForce);
Rigidbody.AddRelativeForce(appliedLinearForce, ForceMode.Force);
// Linear drag forces
var dragForce = -Rigidbody.velocity * LinearDrag;
Rigidbody.AddForce(dragForce, ForceMode.Force);
}
// Ship rotation
var appliedAngularForce = new Vector3(
SteeringTorque.x * FlightInput.Pitch,
SteeringTorque.y * FlightInput.Yaw,
SteeringTorque.z * FlightInput.Roll);
Rigidbody.AddRelativeTorque(appliedAngularForce, ForceMode.Force);
// Angular drag forces
var localAngularVelocity = transform.InverseTransformVector(Rigidbody.angularVelocity);
var localAngularDragForce = Vector3.Scale(-localAngularVelocity, AngularDrag);
Rigidbody.AddRelativeTorque(localAngularDragForce, mode: ForceMode.Force);
}
public bool GetIsEngineRunning()
{
return !FlightInput.IsEngineKill
|| FlightInput.IsThrusterActive
|| FlightInput.IsReversing
|| Mathf.Abs(FlightInput.StrafeHorizontal) > .1f
|| Mathf.Abs(FlightInput.StrafeVertical) > .1f;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment