So, I have a RigidBody that rotates around the Y axis only in an RTS style game. I need a script that will AddTorque to the rigid body in the right direction (clockwise / anticlockwise) until it is pointing at the point given… or close to it. Kind of like the LookAt method, but using forces and therefore smooth.
I’m a bit late, but I wanted to add an answer for future googlers:
This is doable with AddTorque. What you need is two PIDs that operate on Vector3s instead of floats. One PID attempts to steer the up vector of your object towards the desired heading, while the other PID attempts to drive the angular velocity to zero.
First a simple PID (which I “borrowed” from somewhere and modified for Vector3s):
public class VectorPid
{
public float pFactor, iFactor, dFactor;
private Vector3 integral;
private Vector3 lastError;
public VectorPid(float pFactor, float iFactor, float dFactor)
{
this.pFactor = pFactor;
this.iFactor = iFactor;
this.dFactor = dFactor;
}
public Vector3 Update(Vector3 currentError, float timeFrame)
{
integral += currentError * timeFrame;
var deriv = (currentError - lastError) / timeFrame;
lastError = currentError;
return currentError * pFactor
+ integral * iFactor
+ deriv * dFactor;
}
}
And now the behavior:
public class LookAtController : MonoBehaviour
{
private readonly VectorPid angularVelocityController = new VectorPid(33.7766f, 0, 0.2553191f);
private readonly VectorPid headingController = new VectorPid(9.244681f, 0, 0.06382979f);
public Transform target;
public void FixedUpdate ()
{
var angularVelocityError = rigidbody.angularVelocity * -1;
Debug.DrawRay(transform.position, rigidbody.angularVelocity * 10, Color.black);
var angularVelocityCorrection = angularVelocityController.Update(angularVelocityError, Time.deltaTime);
Debug.DrawRay(transform.position, angularVelocityCorrection, Color.green);
rigidbody.AddTorque(angularVelocityCorrection);
var desiredHeading = target.position - transform.position;
Debug.DrawRay(transform.position, desiredHeading, Color.magenta);
var currentHeading = transform.up;
Debug.DrawRay(transform.position, currentHeading * 15, Color.blue);
var headingError = Vector3.Cross(currentHeading, desiredHeading);
var headingCorrection = headingController.Update(headingError, Time.deltaTime);
rigidbody.AddTorque(headingCorrection);
}
}
This isn’t so easy as you think: you would need a PID controller to rotate the object using torque, and it’s a hard job in Unity because you can’t have a reliable angle information to use as feedback. Take a look at this question, about a simulated controller. It simulates the torque effects, accelerating the object to the target angle and decelerating it to stop at the desired angle. It’s physically correct, but doesn’t use AddTorque to keep track of the current object rotation.