Adding recoil to a third person camera but cannot slow it on the way back down

Hi - I have added recoil into my game as below, it moves up and down at the same speed, what I am looking to do is manipulate it so that on the way down it takes twice as long to reset the camera to its origonal position. However whenever I try manipulate it, it goes twice as far instead of taking twice as long.

The issue is that the camera is rotating per tick by a value, so if you try double or half the value the camera moves further / shorter. Is there a way of manipulating this method of recoil on the (third person) camera so it takes twice as long to reset?

    public static void rotateThirdPersonCamera()
    {
        // reference the game obejcts to manipulate
        GameObject cameraRotator = GameObject.Find("CameraRotator");
        GameObject player = GameObject.Find("mainCharacter");
       
            float h = _recoilX + _mouseSensitivity * Input.GetAxis("Mouse X");
            player.transform.Rotate(0, h, 0);
            float v = _mouseSensitivity * -Input.GetAxis("Mouse Y") - _recoilY;
            cameraRotator.transform.Rotate(new Vector3(1, 0, 0), v);

            // control reset direction of weapon recoil
            if ((_recoilState == RecoilState.Resetting))
            {
                player.transform.Rotate(0, h - _recoilXReset, 0);
                cameraRotator.transform.Rotate(new Vector3(1, 0, 0), v + _recoilYReset);
            }

            if (cameraRotator.transform.rotation.eulerAngles.x < 327.0f && cameraRotator.transform.rotation.eulerAngles.x > 270.0f)
            {
                cameraRotator.transform.rotation = Quaternion.Euler(
                    327.0f,
                    cameraRotator.transform.rotation.eulerAngles.y,
                    cameraRotator.transform.rotation.eulerAngles.z);

            }
            if (cameraRotator.transform.rotation.eulerAngles.x > 30.0f && cameraRotator.transform.rotation.eulerAngles.x < 270.0f)
            {
                cameraRotator.transform.rotation = Quaternion.Euler(
                    30.0f,
                    cameraRotator.transform.rotation.eulerAngles.y,
                    cameraRotator.transform.rotation.eulerAngles.z);
            }
            Camera.main.transform.LookAt(cameraRotator.transform.position);
        }

        _smoothRecoil();

    }
    private static void _smoothRecoil()
    {

        // smoothing for recoil
        if (_recoilState == RecoilState.Moving)
        {
            _recoilX -= _recoilSmoothing * Time.deltaTime;
            _recoilY -= _recoilSmoothing * Time.deltaTime;
        }
        else if (_recoilState == RecoilState.Resetting)
        {
            _recoilXReset -= _recoilSmoothing * Time.deltaTime;
            _recoilYReset -= _recoilSmoothing * Time.deltaTime;
        }

        // prevent negative recoil
        if (_recoilX <= 0) _recoilX = 0;
        if (_recoilY <= 0) _recoilY = 0;
        if (_recoilXReset <= 0) _recoilXReset = 0;
        if (_recoilYReset <= 0) _recoilYReset = 0;

        // configure for resetting animation
        if ((_recoilX == 0 && _recoilY == 0) && (_recoilXReset > 0 || _recoilYReset > 0)) _recoilState = RecoilState.Resetting;

        // stop the recoil if everything = 0
        if (_recoilX == 0 && _recoilY == 0 && _recoilXReset == 0 && _recoilYReset == 0) _recoilState = RecoilState.Stopped;

    }

You may want to consider making an AnimationCurve property in your script and putting the recoil curve there, so you can make it look “real,” the way it might if you were really recoiling.

public AnimationCurve RecoilUpwards;

Then you can set up something like this and drive it through your code using the .Evaluate() method on the curve. It makes it trivial to tweak the curve until it looks awesome sauce as you’re firing.

1 Like

I’ve not seen that before, thank you! Does this generate the math into something where i can add the value of the curve to:

float h = _recoilX + _mouseSensitivity * Input.GetAxis("Mouse X");
player.transform.Rotate(0, h, 0);
float v = _mouseSensitivity * -Input.GetAxis("Mouse Y") - _recoilY;
cameraRotator.transform.Rotate(new Vector3(1, 0, 0), v);

You would keep track of a “time” that the recoil is happening, say over 0.25 of a second.

float RecoilTimer;

The recoil would be in effect when that time goes from 0.0f to 0.25f (or whatever you want it to be)

You would set the AnimationCurve domain (left to right) to be from 0.0f to 0.25f

Then you can get the recoil by:

float recoilAmount = RecoilCurve.Evaluate( RecoilTimer);

You can scale that to however many degrees up you want it to be by tweaking key values in the curve.

It is often useful to have an extra Transform in your hierarchy that ONLY handles the recoiling deflection of the gun, to keep you from getting entangled with any other rotations or offsets or whatever. That also lets you make the recoil happen from a very specific point in the gun, which should be near the gun’s center of mass to make it look right, not around the zero mark of the player, for instance.

1 Like

Thanks, I think I have implemented most of this now, do you know what part of my script to I insert RecoilCurve.Evaluate( RecoilTimer);? I have tried both within the smoothing method and the main rotate method in place of _recoilX +

EDIT: nevermind, i have refactored my whole script and this is much better, thank you!

1 Like