Right now in our first-person game we have an aiming system similar to (but not exactly like) Red Orchestra (- YouTube if you’re not familiar): when the player moves the mouse, the screen will reorient perfectly, but the gun’s aim will interpolate to follow the player’s head with a little lag (to simulate imperfect aim when firing from the hip).
However, though right now the implementation we have works, it doesn’t constrain the gun’s movement when the player moves their aim too quickly for the gun to catch up. The result is that if the player moves the aim too quickly the gun will fall so far behind that it ends up just rotating around and around if the player moves their aim quickly enough. Anyway, here’s the relevant code we have so far, along with some failed solutions I’ve already tried. Anyone have any ideas on how to solve this problem? Obviously I don’t understand Quaternions well enough to solve this myself.
public float maxAngle; //maximum angle of difference between gun and aim point
public float aimDistance; //the distance at which to aim along the player's actual line of vision.
public float aimSpeed; //the speed at which the gun point catches up to the view point
private Vector3 aimPoint; //the line at which the gun is aiming - i.e., the line from the gun point to the point directly in front of from the player's vision. Currently sets the gun's rotation to follow to that point
private void aimLook() //called once per frame from Update()
{
//calculate the aimPoint as the current look direction outwards aimDistance distance
aimPoint = transform.forward * aimDistance;
//calculate new rotation to have the gun look at the aimPoint
Quaternion aimAtAimPoint = Quaternion.LookRotation(aimPoint);
//interpolate between the current aim and the desired aim point
Quaternion modAimAtAimPoint = Quaternion.Lerp(unmodifiedAimRotation, aimAtAimPoint, Time.deltaTime * aimSpeed);
//BEGIN SOLUTION ATTEMPT 1
//if the interpolated rotation angles are too far away from the center, constrain them
//Vector3 rotation = modAimAtAimPoint.eulerAngles;
//if(modAimAtAimPoint.eulerAngles.z > maxAngle || modAimAtAimPoint.eulerAngles.z < -maxAngle)
// rotation.z = maxAngle;
//if(modAimAtAimPoint.eulerAngles.y > maxAngle || modAimAtAimPoint.eulerAngles.y < -maxAngle)
// rotation.y = maxAngle;
//if(aimAtAimPoint.eulerAngles.z > maxAngle || aimAtAimPoint.eulerAngles.z < -maxAngle)
// rotation.z = maxAngle;
//modAimAtAimPoint.eulerAngles = rotation;
//END SOLUTION ATTEMPT 1
//BEGIN SOLUTION ATTEMPT 2
// Quaternion modAimAtAimPoint;
// float difference;
//
// //if the interpolated aim is too far away from the aimAtAimPoint, keep interpolating until it isn't
// do
// {
// //interpolate between the current aim and the desired aim point
// modAimAtAimPoint = Quaternion.Lerp(unmodifiedAimRotation, aimAtAimPoint, Time.deltaTime * aimSpeed + .1f);
//
// difference = Quaternion.Angle(modAimAtAimPoint, aimAtAimPoint);
// Debug.Log(difference);
// }while(difference > maxAngle || difference < -maxAngle);
// END SOLUTION ATTEMPT 2
//set the gun's actual aim to the interpolated aim
gunPoint.transform.rotation = modAimAtAimPoint;
}