Problem with physics: GetPointVelocity & AddForceAtPosition (airplane control script)

Im trying to make a simple airplane control script. I've seen some advise on the subject on the forums (here) which helped a lot.

In summary:

Make a script that is applied to a GameObject parented to a rigidbody. This script calculates a lift force from its speed and angle and applies it to the parent at its position.

Only that my script uses the velocity of the parent rigidbody instead of its own. That isn't a good solution and limits the use of my script more or less to the main wings of a plane (their velocity is close to the velocity of the plane most of the time).

I believe I have to use GetPointVelocity() to get the speed of the child. When i do that my plane starts to rotate violently around various axes and moves rather slow in some random direction. Im a little lost here. I'm also new to javascript, any help would be appreciated.


I have tried some fixes but nothing worked so far.

The updated script is postet below.

I believe the Problem is, that when I calculate a force based on a velocity from GetPointVelocity() and use that Force with AddForceAtPosition() on the same rigidbody, some sort of feedback messes things up. Is that possible?

Here is my script:

This script simulates a simple Wing.

var sizeX = 7.0; //dimensions of Wing
var sizeZ = 1.2;

var maxAngleOfAttack = 0.7; //above this Angle no Lift will be generatet because of stall
var maxForce = 1000;

private var debug_vec1 =;
private var debug_vec2 =;

private var liftVec =;

function OnDrawGizmos () {
    Gizmos.color = Color (0.20, 0.74, 0.27, 0.50);
    var leftEdge = transform.right * (-sizeX/2);
    var rightEdge =transform.right * (sizeX/2);
    var leadingEdge = transform.forward * (sizeZ/2);
    var trailingEdge = transform.forward * (-sizeZ/2);

    var ourPosition = transform.position;

    Gizmos.DrawLine (ourPosition+leftEdge+leadingEdge, ourPosition+rightEdge+leadingEdge);
    Gizmos.DrawLine (ourPosition+rightEdge+leadingEdge, ourPosition+rightEdge+trailingEdge);
    Gizmos.DrawLine (ourPosition+rightEdge+trailingEdge, ourPosition+leftEdge+trailingEdge);
    Gizmos.DrawLine (ourPosition+leftEdge+trailingEdge, ourPosition+leftEdge+leadingEdge);

    Gizmos.color = Color (0.28, 0.32, 0.97, 0.50);
    Gizmos.DrawLine (ourPosition, ourPosition+debug_vec1);
    Gizmos.color = Color (0.80, 0.17, 0.17, 0.50);
    Gizmos.DrawLine (ourPosition, ourPosition+debug_vec2);

function FixedUpdate () {

//Get velocity at our location (brroken use root velocity instead)
  var v : Vector3;
  //v = transform.root.rigidbody.GetPointVelocity(transform.position);
  v = transform.root.rigidbody.velocity;
  //only y and z contribute to lift
  v -= Vector3.Project(v, transform.right);
  debug_vec1 = v;

//forward speed
  var airspeed = v.magnitude;

//angle of attack (-1 = moving up; 1 = m. down; 0 = m. forward or backward)
  var attacKAngle = Vector3.Dot(v.normalized, transform.up.normalized * -1);
    if (attacKAngle >  maxAngleOfAttack || attacKAngle < -maxAngleOfAttack)  attacKAngle = 0;

  //area of the wing * density of air / 2 (used as Multiplier to liftforce)
  var liftMult = sizeX * sizeZ * 0.645;

  var liftForce = airspeed * liftMult * attacKAngle;
    if (liftForce > maxForce) liftForce = maxForce;
    if (liftForce < -maxForce) liftForce = -maxForce;

//Apply Lift Force to Parent rigidbody at our Position
  transform.root.rigidbody.AddForceAtPosition(liftForce*transform.up, transform.position);
  debug_vec2 = liftForce*transform.up;


I don't think there is any feedback effect here - this is a common technique for implementing car physics, for example.

It is often difficult to keep things consistent between local and world coordinates spaces. Since most forces affecting a vehicle are best expressed in local coordinates, it helps to convert all velocities, forces etc into local space first, do all the calculations and then convert back. You can use transform.InverseTransformDirection to go from world to local space and then transform.TransformDirection to go back to world space.

For example, get the point velocity for a wing using GetPointVelocity and then convert it to local coordinates:-

var worldWingVel: Vector3 = rigidbody.GetPointVelocity(wingPoint);
var localWingVel: Vector3 = transform.InverseTransformDirection(worldWingVel);

You can then remove the sideways component of the wing velocity using

localWingVel.x = 0;

...and get the lift using

var localLift: Vector3 = liftValue * Vector3.up;

Eventually, you need to convert this back to world space, because AddForceAtPosition doesn't have a local space equivalent:-

var worldLift: Vector3 = transform.TransformDirection(localLift);
rigidbody.AddForceAtPosition(wingPos, worldLift);

It is often difficult to diagnose what has gone wrong when a force is being applied in the wrong coordinate space because the rigidbody just tends to go crazy without giving you much to work with. Keeping things in local space as far as possible will help you to narrow problems down.

Don’t you think you misplaced arguments in AddForceAtPosition?