Gun Recoil C#

Hello. Can someone help me create some recoil for my guns? I have looked everywhere for a good C# script for my gun, and either it doesn’t work how I want it to, or it’s in Javascript. Even if I search up “C#” it still gives Javascript. Right now I am using the script that Brackeys made on my gun, and added some stuff to it:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class Gun : MonoBehaviour {

    public float damage = 8f;
    public float range = 100f;
    public float fireRate = 10f;
    public float impactForce = 30f;

    public int maxAmmo = 20;
    public int fullAmmo = 160;
    private int remainingAmmo;
    private int currentAmmo;
    public float reloadTime = 1.5f;
    private bool isReloading = false;
    private bool didFunction = false;
    private bool lastClip = false;
    private bool hasGnomePlayed = false;

    public Camera fpsCam;
    public ParticleSystem muzzleFlash;
    public AudioSource gunShot;
    public AudioSource noAmmo;
    public AudioSource pullOutRifle;
    public AudioSource rifleReload;
    public AudioSource gnomeLaugh;
    public AudioClip gnomeLaughClip;
    public GameObject impactEffect;
    public GameObject hand;
    public GameObject trigger;
    public GameObject holoSight;
    public GameObject crosshair;
    public GameObject fpsController;
    public GameObject fpsCharacter;
    public GameObject gnome;
    Vector3 positionTriggerWhenShooting;
    Vector3 originalTriggerPos;
    Vector3 crosshairScale;
    Vector3 crosshairScaleWhenCrouched;
    Vector3 gnomePosition;
    Quaternion gnomeRotation;
    Vector3 gnomeScale;

    private float nextTimeToFire = 0f;

    public Animator animator;
    public GameObject ammoUI;

    public float maxDeviation = 10f;

    void Start ()
    {
        currentAmmo = maxAmmo;
        positionTriggerWhenShooting = new Vector3(-0.0003835559f, -0.002273885f, -0.108f);
        originalTriggerPos = new Vector3(-0.0003835559f, -0.002273885f, -0.1002108f);
        crosshairScale = new Vector3(1f, 1f, 1f);
        crosshairScaleWhenCrouched = new Vector3(0.8f, 0.8f, 0.8f);
        gnomePosition = new Vector3(-1f, -0.676f, 0.892f);
        gnomeRotation = new Quaternion(0.7f, -217.11f, 0.021f, 0.69f);
        gnomeScale = new Vector3(10f, 10f, 10f);
    }

    void OnEnable ()
    {
        isReloading = false;
        animator.SetBool("Reloading", false);
        StartCoroutine(ChangeToWeapon());
    }

    void Update() {

        ammoUI.GetComponent<Text>().text = currentAmmo.ToString() + "/" + fullAmmo.ToString();

        remainingAmmo = 20 - currentAmmo;

        hand.SetActive(true);

        if (fpsController.GetComponent<CharacterController>().height == 1.0f && !holoSight.activeSelf)
        {
            crosshair.transform.localScale = crosshairScaleWhenCrouched;
            maxDeviation = 8f;
        }

        if(holoSight.activeSelf)
        {
            maxDeviation = 5f;
        } 
        if(!holoSight.activeSelf && fpsController.GetComponent<CharacterController>().height != 1.0f)
        {
            maxDeviation = 10f;
        }

        if(gameObject.activeSelf && fpsController.GetComponent<CharacterController>().height != 1.0f)
        {
            crosshair.transform.localScale = crosshairScale;
        }

        if(pullOutRifle.isPlaying)
        {
            return;
        }

        if(currentAmmo == 0 && fullAmmo == 0 && Input.GetMouseButtonDown(0))
        {
            noAmmo.Play();
        }

        if (currentAmmo <= 0 && lastClip == true)
        {
            currentAmmo = 0;
            fullAmmo = 0;
            return;
        }

        if(fullAmmo <= 20 && didFunction == true)
        {
            currentAmmo = fullAmmo;
            didFunction = false;
            lastClip = true;
        }

        if(currentAmmo == fullAmmo)
        {
            fullAmmo = 0;
        }

        if (isReloading)
            return;

        if(currentAmmo <= 0 || Input.GetKeyDown(KeyCode.R) && currentAmmo != 20)
        {
            StartCoroutine(Reload());
            return;
        }

        if(Input.GetButton("Fire1") && Time.time >= nextTimeToFire)
        {
            nextTimeToFire = Time.time + 1f / fireRate;
            Shoot();
        } else
        {
            trigger.transform.localPosition = originalTriggerPos;
        }
		
	}

    IEnumerator Reload ()
    {
        isReloading = true;

        animator.SetBool("Reloading", true);
        yield return new WaitForSeconds(0.01f);
        rifleReload.Play();

        yield return new WaitForSeconds(reloadTime - .25f);
        animator.SetBool("Reloading", false);
        yield return new WaitForSeconds(.25f);

        currentAmmo = maxAmmo;
        fullAmmo -= remainingAmmo;
        isReloading = false;
        didFunction = true;
    }

    IEnumerator ChangeToWeapon()
    {
        animator.SetBool("PullOutWeapon", true);

        yield return new WaitForSeconds(1.041f);

        animator.SetBool("PullOutWeapon", false);
    }

    void Shoot ()
    {
        muzzleFlash.Play();
        gunShot.Play();

        currentAmmo--;
        trigger.transform.localPosition = positionTriggerWhenShooting;

        RaycastHit hit;

        Vector3 forwardVector = Vector3.forward;
        float deviation = Random.Range(0f, maxDeviation);
        float angle = Random.Range(0f, 360f);
        forwardVector = Quaternion.AngleAxis(deviation, Vector3.up) * forwardVector;
        forwardVector = Quaternion.AngleAxis(angle, Vector3.forward) * forwardVector;
        forwardVector = fpsCam.transform.rotation * forwardVector;

        if(Physics.Raycast(fpsCam.transform.position, forwardVector, out hit, range))
        {
            //Debug.Log(hit.transform.name);
            if(hit.transform.name == "Gnome")
            {
                gnome.transform.parent = fpsCharacter.transform;
                gnome.transform.localPosition = gnomePosition;
                gnome.transform.localRotation = gnomeRotation;
                gnome.transform.localScale = gnomeScale;
            }

            if(gnome.transform.parent == fpsCharacter.transform) 
            {
                gnome.layer = 9;
                if (hasGnomePlayed == false)
                {
                    hasGnomePlayed = true;
                    gnomeLaugh.clip = gnomeLaughClip;
                    gnomeLaugh.Play();
                }
            }

            Target target = hit.transform.GetComponent<Target>();
            if(target != null)
            {
                target.TakeDamage(damage);
            }

            if(hit.rigidbody != null)
            {
                hit.rigidbody.AddForce(-hit.normal * impactForce);
            }

            GameObject impactGO = Instantiate(impactEffect, hit.point, Quaternion.LookRotation(hit.normal));
            Destroy(impactGO, 2f);
        }
    }
}

I would much appreciate either a script, or just some code to get me going. Thanks!

Hi,

You can consider using Vector3.Lerp.

public bool recoilOn = false;
public Transform recoilBeginPos;        *//You can also use Vector3 variables instead of Transform*
public Transform recoilEndPos;
public float recoilSpeed;                   *//Play with values that suits your need for the recoil speed*

Now, under Shoot() function, make the recoilOn to true.

      void Shoot(){
       muzzleFlash.Play();
       gunShot.Play(); 
      recoilOn = true;
}

You are all set to call the Recoil function now. In the update function, create a If loop like below,

if( recoilOn){
    
    Recoil();                                      //*Call recoil function every time you fire the gun.*
    recoilOn = false;                     *//Immediately make this to false, so that you can initiate the recoil again in the next fire*
    }

public void Recoil(){

                       transform.position = Vector3.Lerp(recoilBeginPos.position, recoilEndPos.position, Time.deltaTime * recoilSpeed);

*//Adjust the speed so that the movement is as expected. I assumed you wanted to apply the recoil motion to the entire gun and this script is attached to the gun*
}

Make sure you are not clashing with the fire duration. Create a boolean to check whether the recoil is finished or not. And add a condition in your script so that the fire happens only after the recoil is done. I couldn’t write a script for this, as I find it difficult to read your script because of too many lines for a single script.

Tips/Suggestions:

  1. Always make sure your script is readable and understandable by any third person (Split up functions and variables in different scripts. Do not put every variables and functions of the game in one single script).

  2. Personally, I felt you have added too many Audio sources for one gameobject (i.e., the Gun). You can have one Audio Source and an Array of AudioClips.

    public AudioSource GunAudio;
    public AudioClip gunAudioClips; //You can store all the audios related to your Gun, like Fire, reload, No ammo etc…

    GunAudio.clip = gunAudioClips[0]; //From the array of audio clips, use anyone based on the situation, here I can say gunAudioClips[0] is Fire;
    GunAudio.Play();

Please comment to this answer if this script creates any issues. If this is solved your problem, please mark this question as answered so that others can make use of it.

Cheers
TK