Camera not moving with procedural recoil script (Cinemachine 3D)

Hi,

So, it’s my first time posting, as I’m entirely new to Unity, and as a means of learning how to code and familiarizing myself with the 3D Built-In Render Pipeline, I’ve been following a series of tutorials on YouTube, which I’ll link to below, and it’s been going great up until today, where I’ve been experiencing a problem that I haven’t been able to solve after watching and re-watching the segment on implementing a procedural recoil system.

In the video, the author demonstrates how to write a C# script for managing the recoil function in order to move a Cinemachine virtual camera back and forth in sync with the weapon firing, which is attached to the weapon game-object, which I believe I have accurately reproduced, however, because of my ongoing confusion, I’m honestly beginning to question myself on that due to the fact that in testing, the camera isn’t behaving as it should according to the tutorial. Following the writing of the recoil script, the author outlined the necessary additions to the WeaponManager script from previous lessons in the series, which I’m pretty sure I also reproduced correctly, but again, I’m not so sure any more.

To be entirely frank, I have no idea what I’m missing here, but my theory is that maybe it has something to do with my in-Unity setup of the components being used by the relevant game objects? I’m not sure if maybe my vitrual camera or my recoilFollowPos game object or possibly cinemachine itself has been somehow misconfigured by my setting up of the components with some potentially incorrect parameters or something? I honestly have no clue, however I have screenshots of my project hierarchy and the inspectors for the relevant game objects that I am also able to provide, if that helps?

My weapon recoil code is as follows:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class WeaponRecoil : MonoBehaviour
{
    [SerializeField] Transform recoilFollowPos;
    [SerializeField] float kickBackAmount = -1;
    [SerializeField] float kickBackSpeed = 10, returnSpeed = 20;
    float currentRecoilPosition, finalRecoilPosition;
    

    // Update is called once per frame
    void Update()
    {
        currentRecoilPosition = Mathf.Lerp(currentRecoilPosition, 0, returnSpeed * Time.deltaTime);
        finalRecoilPosition = Mathf.Lerp(finalRecoilPosition, currentRecoilPosition, kickBackSpeed * Time.deltaTime);
        recoilFollowPos.localPosition = new Vector3(0, 0, finalRecoilPosition);
    }

    public void TriggerRecoil()
    {
        currentRecoilPosition += kickBackAmount;
    }
    
}

My WeaponManager code is as follows:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class WeaponManager : MonoBehaviour
{
    [Header("Fire Rate")]
    [SerializeField] float fireRate;
    float fireRateTimer;
    [SerializeField] bool semiAuto;

    [Header("Bullet Properties")]
    [SerializeField] GameObject bullet;
    [SerializeField] Transform barrelPos;
    [SerializeField] float bulletVelocity;
    [SerializeField] int bulletsPerShot; 
    AimStateManager aim;

    [SerializeField] AudioClip gunShot;
    AudioSource audioSource;
    WeaponAmmo ammo;
    ActionStateManager actions;
    WeaponRecoil recoil;

    // Start is called before the first frame update
    void Start()
    {
        recoil = GetComponent<WeaponRecoil>();
        audioSource = GetComponent<AudioSource>();
        aim = GetComponentInParent<AimStateManager>();
        ammo = GetComponent<WeaponAmmo>();
        actions = GetComponentInParent<ActionStateManager>();
        fireRateTimer = fireRate;
    }

    // Update is called once per frame
    void Update()
    {
        if(ShouldFire()) Fire();
    }

    bool ShouldFire()
    {
        fireRateTimer += Time.deltaTime;
        if (fireRateTimer < fireRate) return false;
        if (ammo.currentAmmo == 0) return false;
        if (actions.currentState == actions.Reload) return false;
        if (semiAuto && Input.GetKeyDown(KeyCode.Mouse0)) return true;
        if (!semiAuto && Input.GetKey(KeyCode.Mouse0)) return true;
        return false;
    }

    void Fire()
    {
        fireRateTimer = 0;
        barrelPos.LookAt(aim.aimPos);
        audioSource.PlayOneShot(gunShot);
        recoil.TriggerRecoil();
        ammo.currentAmmo--;
        for(int i =0; i < bulletsPerShot; i++)
        {
            GameObject currentBullet = Instantiate(bullet, barrelPos.position, barrelPos.rotation);
            Rigidbody rb = currentBullet.GetComponent<Rigidbody>();
            rb.AddForce(barrelPos.forward * bulletVelocity, ForceMode.Impulse);
        }
    }
}

The lines in the WeaponManager that are relevant to calling the recoil functions are the following:

WeaponRecoil recoil; //Declared in the public class on line 23

recoil = GetComponent<WeaponRecoil>(); //Within the start method on line 28

recoil.TriggerRecoil(); //Within the Fire method on line 58

Youtube Links:
The playlist for the YouTube tutorials that I’m following can be found here: https://www.youtube.com/playlist?list=PLX_yguE0Oa8QmfmFiMM9_heLBeSA6sNKx

The video pertaining to the issue in question is " Third Person Shooter (Unity Tutorial) Ep 9 Procedural Recoil & Gunshot VFX," which can be found here: https://youtu.be/k8s3EgoYKX4?si=5kCWfpw67r0pHSk7

To anyone who’s read through all of this and looked over the information I’ve provided, thank you so much for your time, even if you aren’t able to help. I greatly appreciate you taking the time regardless of the outcome, and to anyone who is able to help or even just flat out point out the solution, thank you so much in advance. I am infinitely grateful to any and all of you, and I hope you have a lovely day or night in whichever timezone you find yourself in.

Best regards,
-Stef.

Hi there,

Thanks for reaching out! I’m going to have to post them one at a time since new users can only have one piece of embedded media per post/reply, so this may take a moment.

Project Hierarchy:

Virtual Camera Inspector 1:

Virtual Camera Inspector 2:

Main Camera Inspector 1:

Main Camera Inspector 2:

Weapon Inspector 1:

Weapon Inspector 2:

RecoilFollowPos Inspector:

That’s everything I think is relevant, but if necessary, I can easily retrieve further screenshots of other game objects, components, etc.

Thanks again for reaching out!

So quick update, at the suggestion of the video author, (Gadd Games on YouTube, who I must add is a super friendly and helpful) I’ve tried some rudimentary debugging to check if the scripts are actually running when tested using the line Debug.Log("Boop"); to check the weapon recoil script’s update and trigger methods are in fact running, and they were, so now I’m wondering what my next step should be. I have an idea what to try next, which would be using a debug log in the weapon manager’s firing method using something along the lines of “if recoil.TriggerRecoil(); returns true, then do the Debug.Log(“Boop”);” however, I’m not sure exactly how to properly write that in C#.

For reference my idea looks like this:

void Fire()
    {
        fireRateTimer = 0;
        barrelPos.LookAt(aim.aimPos);
        audioSource.PlayOneShot(gunShot);
        recoil.TriggerRecoil();
        ammo.currentAmmo--;
        for(int i =0; i < bulletsPerShot; i++)
        {
            GameObject currentBullet = Instantiate(bullet, barrelPos.position, barrelPos.rotation);
            Rigidbody rb = currentBullet.GetComponent<Rigidbody>();
            rb.AddForce(barrelPos.forward * bulletVelocity, ForceMode.Impulse);

           //"if recoil.TriggerRecoil(); returns true, then do the Debug.Log("Boop");"
        }
    }

I know the last line is totally not even close to proper syntax, because to be honest, I have no idea how to write that the right way or even if using an “if” statement is the right way to go about this.

Another quick update, after closing Unity last night, restarting my computer this morning and reopening Unity, I have managed to get the camera to slightly move sometimes which is giving me the impression the script is sort of working, but something is preventing it from behaving exactly as intended. Rather than consistently moving the set distance back and forth with the weapon recoil, it appears to be occasionally moving back about half as far, and only on one out of every thirty to fifty rounds fired. I’m not sure if this helps diagnose the problem, but I’m optimistic that this is at least a small step forward.

Okay, final update, thankfully, as I have finally found a solution, and boy do I feel silly now that I realize how simple and obvious it was, but I guess that’s just part of the process! Haha!

Firstly, in my recoil script, I simply removed the preassigned values for kickback amount, kickback speed and return speed, so the script now looks like this:

```
public class WeaponRecoil : MonoBehaviour
{
    [SerializeField] Transform recoilFollowPos;
    [SerializeField] float kickBackAmount;
    [SerializeField] float kickBackSpeed, returnSpeed;
    float currentRecoilPosition, finalRecoilPosition;
```

Once that was done, I simply tweaked the values assigned to the kickback and return speeds a few times just to see what would happen if I changed them, and in observing the behaviour changes, I was able to conclude that the original values were simply “too fast,” which eventually resulted in my assigned values being reduced to 50% of their original values, and now, almost as if by magic, the problem appears to be completely solved, as the camera now behaves exactly as expected in relation to the weapon recoil.

I definitely feel as though I totally missed the obvious solution, but this was definitely a learning experience, and perhaps this record of my foolishness can help others learn as well!