Recoil Slerping back to original rotation

Hello. I am making a small FPS game so I can get used to gun mechanics etc. and I am making a recoil script at the moment, where after I shoot, the gun rotates either to the left or to the right (because a random number generator). However, I want my gun to rotate back to its original rotation after a certain amount of time after i stopped shooting. With my current script, it just puts my gun in a weird rotation.

public Quaternion hipFire;
    public GameObject ar;
    int x;
    float f;
   
    void LateUpdate () {
        StartCoroutine(Recoil());
       
    }
    IEnumerator Recoil()
    {
        if (Input.GetMouseButtonDown(0))
        {
            f = f + 0.3f;
            x = Random.Range(0, 2);
            if (x == 0)
            {
                transform.Rotate(0, 3.5f, 0);
                f = f + 0.25f;
            }

            if (x != 0)
            {
                transform.Rotate(0, -3.5f, 0);
                f = f + 0.25f;
            }
            yield return new WaitForSeconds(.2f + f);
            ar.transform.rotation = Quaternion.Slerp(ar.transform.rotation, hipFire, 15 * Time.deltaTime);

            f = -0.3f;
        }
    }
}

I know this code is very messy and could be improved, but this is just the basic stuff that i want to accomplish. Ar.transform.rotation = Quaternion.Slerp(ar.transform.rotation, hipFire, 15 * Time.deltaTime); is the line that should bring the gun back to its original rotation. ar is the gun object in my scene. And also, f is supposed to be the reset timer for the recoil. If you want to provide code to help me then i would really appreciate it, but i dont expect that in any way - just telling me what to do is just as helpful! Thanks for reading.

I suggest that you apply first hip fire, without any other rotation changes, or even directly to rotation, to see, if Quaterion is parametrs are correct. If hip fire don’t set ar rotation directly, then you found your initial problem.

also, f = f + x ; is the same as f += x ; So use the second, as is shorter and quicker.
Try use meaningful variables names. hipFire don’t appears anything like rotation even it is Quaternion. It should clearly indicate, what it is. At least put comments. You will appreciate yourself in future.

okay, first of all: thanks for replying! Now, doing what you told me to do definitely helped. I noticed that the hipFire was in fact the problem. Now that I have got the right coordinates, I tried going back to Slerp. However, now it doesn’t slerp back to the original rotation. It only goes back a little bit and not fully and it’s not smooth at all, got any tips for that? But still, thanks so much for the reply.

No probs.
Check if you not overriding your reference quaternion, for which you target return rotation. You can always use quaternion.eulerAngles, to get idea, what it looks like in degrees.
It makes sense o use it, if you have one axis changed, but if multiple axis is changed, you may get confused, if you are not familiar, so is not always good method.

Okay, so now I tried switching " Quaternion.Slerp(transform.rotation, hipFire, 15 * Time.deltaTime);" to " Quaternion.Slerp(hipFire, transform.rotation, 15 * Time.deltaTime);" and now after the reset time has ended, the gun goes back to its original rotation, but it does that instantly. Is there a way to fix that?

https://gyazo.com/d5dbc0a1d91cf617308864541f0584d2 - click on that link to see what it looks like for me

Quaternion.Slerp takes two rotation arguments, of which first one is the current state, and second is the target state. You need get to understand this, to get correct result. Otherwise you get funny behaviors. So initial way was correct.
If your rotation don’t comes back with Lerp / Slerp, then means, you still got problem somewhere with logic and hipFire.
Use debug/breakpoints to find out, what writes where to it. Oh btw, mind data is passed by reference, not a copy.

Okay so, I think I figured out what the problem is. Perhaps the slerp only doesnt work properly is because of MouseButtonDown. Because after I used MouseButton instead of MouseButtonDown, it did slerp like it should, but now its just repeating the coroutine a lot of times, is there a way to fix that?

That appears you have continuously triggering coruotine.

I would rather than having input detection in the if statement, put bool flag, that which triggers condition.

What you need, is trigger to initiate lerp procedure. Mouse input should be somewhere triggering bool flag.
When this flag is enabled, it allows lerp to do the job. At the same time, you have another procedure, which after given duration from the bool flag being triggered true, disables this flag. Means your rotation has returned.
This way, you decouple your script from direct input. And you can trigger this flag with anything else you like, if ever needed in future.

Im not sure if I understood what you said (i dont know what boolean flags are haha), but I tried this:

void LateUpdate () {
        StartCoroutine(Recoil());
        while (!isShooting && transform.localRotation != hipFire)
        {
            transform.localRotation = Quaternion.Slerp(transform.localRotation, hipFire, 0.5f);
        }

    }
    IEnumerator Recoil()
    {
        if (Input.GetMouseButtonDown(0))
        {
            isShooting = true;
            f += 0.3f;
            x = Random.Range(0, 2);
            if (x == 0)
            {
                transform.Rotate(0, 3.5f, 0);
                f += 0.25f;
               
            }

            if (x != 0)
            {
                transform.Rotate(0, -3.5f, 0);
                f += 0.25f;
              
            }
           
            yield return new WaitForSeconds(1f + f);
            isShooting = false;
           
            f = -0.3f;
        }
    }

So after shooting, isShooting is true; and after a certain amount of time, isShooting is set to false. After it becomes false, the if statement in lateupdate is called where it should slerp as long as localrotation and hipfire arent the same and isShooting is false, but that didnt work either. What am I doing wrong, or did i misunderstand your tip?

UPDATE: i changed the while statement to an if statement and now its finally working! Thank you so so much for your help!

Cool.

Just to explain, since you had this right anyway:
Flag is another term, for boolean state false, or true.
It just indicates, I am on, or I am off. Just like conquering land and sticking flag; “This is our now” :wink:

1 Like