- Home /
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!
Answer by viknesh2020 · Sep 26, 2018 at 06:31 AM
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
Thank you so much for the help. Sadly when I do what you said it changes positions very fast and goes back too quickly, making it seem like it is activating and deactivating very fast. I created a boolean that becomes true once the recoil function is done, and it can only shoot if that boolean is true, but I get the same result. Do you $$anonymous$$d helping me to fix this? Thanks.
@BankShotZombies Did you try tweaking the recoilSpeed? The position change must be smooth as we are using Time.deltaTime. Try reducing the recoilSpeed as low as possible and see the result.
I changed the recoilSpeed down as much as I could (to 0.01) and now I can see the movement. But it is still changing positions to fast. I can now see it going up and down, but it is too quick. Thanks for your help.
I'll share some more thoughts here:
Since a recoil is comprised of a backwards motion (accelerate back and then decelerate), followed by a forward motion (return to initial position). It would probably be best to use a rigidbody AddForce method (per my previous comment) for the backwards motion, and then Lerp for the forward motion.
Having said that, I want to add that I suspect that the best solution might be provided by creating a suitable recoil animation that would play every time the gun fired. I tend to think that playing an animation would be better than simulating the recoil through code.
...and there's always the Asset Store to consider:
The animation thing that you said is much better replacement for the Lerp function. Animation would come in handy for sure. !
Your answer
Follow this Question
Related Questions
Distribute terrain in zones 3 Answers
Animation script 1 Answer
How to add fire rate/Force to my gun 0 Answers
separate script to reload. 0 Answers
Multiple Cars not working 1 Answer