Search Unity

FPS Weapon Bug - Weapon using stats of multiple other guns at once.

Discussion in 'Getting Started' started by IVantedOrange, Dec 5, 2020.

  1. IVantedOrange

    IVantedOrange

    Joined:
    Nov 22, 2020
    Posts:
    1
    My apologies if I'm the wrong subforum for this. I'm currently working on what I hope will become a roguelite FPS. At the moment, I have a strange bug where a weapon I pick up from my scene will simultaneously use the stats of other guns in the scene unless I take all of them from the scene. For example:

    - There are 2 weapons in my scene: a pistol and a submachine gun. (I have other guns made, but I only have these 2 in the scene currently.) The handgun does 20 damage and fires once when Fire1 is clicked. The submachine gun deals 15 damage and fires fully automatically as long as Fire1 is held.
    - I pick up my handgun from the scene and fire it at my dummy enemy. I am currently holding the Fire1 button.
    - The target enemy takes 20 damage and 15 damage simultaneously on the first shot and then continues to take 15 damage automatically for every subsequent shot.
    - I pick up the submachine gun and swap back to the pistol. I shoot the dummy and hold Fire1.
    - The dummy takes 20 damage once and no other shots are fired. The pistol is currently behaving as it is intended to.
    - I do the same with the submachine gun. The dummy takes 15 damage repeatedly, as it is meant to.

    The odd behavior does not change if the submachine gun is picked up first. The SMG will deal 20 and 15 simultaneously and then default to 15 damage full auto shots until I grab the pistol, after which both guns now behave as intended. The same also happens if the player presses Fire1 on the dummy while not having picked up any of the guns, but I have a feeling this issue is related to the first. The weapons are prefabs comprised of a box collider, a script that assigns a Weapon ID value to them that is used to call them from a database, and their function script. Each weapon has its own individual function script that is derived from a base script called Gun.cs. (All weapons used to use the base script but that caused a bug where shooting would cause it to run down the stats of every single gun in the database per shot, causing the player to do ludicrous damage per shot) The function scripts not only control the functions of the gun, but also contain its base stats such as its damage, fire rate, range, etc. I've looked over all my code for a while now and I can't seem to find where this issue is coming from. Every solution I've attempted has amounted to basically throwing the proverbial excrement at the wall and hoping something sticks. The code I posted here are the scripts that I most suspect to be causing the bug.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Gun : MonoBehaviour
    6. {
    7.     public float damage;
    8.     public float fireRate;
    9.     public float range;
    10.  
    11.     public int id;
    12.     public float nextShot;
    13.  
    14.     public GameObject gameController;
    15.     public WeaponDatabase database;
    16.  
    17.     public Camera mainCam;
    18.  
    19.     public virtual void Shoot()
    20.     {
    21.         //override
    22.     }
    23. }
    24.  
    This is the base function that all guns derive from.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class B92 : Gun
    6. {
    7.     void Start()
    8.     {
    9.         damage = 20f;
    10.         fireRate = 15f;
    11.         range = 10000f;
    12.         nextShot = 0f;
    13.  
    14.         gameController = GameObject.FindGameObjectWithTag("GameController");
    15.         database = gameController.GetComponent<WeaponDatabase>();
    16.         mainCam = Camera.main;
    17.         id = GetComponent<WeaponID>().weaponID;
    18.     }
    19.  
    20.     void Update()
    21.     {
    22.         if (Input.GetButtonDown("Fire1") && Time.time >= nextShot)
    23.         {
    24.             nextShot = Time.time + 1f / fireRate;
    25.             Shoot();
    26.         }
    27.     }
    28.  
    29.     public override void Shoot()
    30.     {
    31.         RaycastHit hit;
    32.         if (Physics.Raycast(mainCam.transform.position, mainCam.transform.forward, out hit, range))
    33.         {
    34.             if (hit.transform.tag == "Enemy")
    35.             {
    36.                 Debug.Log(hit.transform.name + (" takes ") + damage + (" damage!"));
    37.                 CharacterStats enemyStats = hit.transform.GetComponent<CharacterStats>();
    38.                 enemyStats.TakeDamage(damage);
    39.             }
    40.         }
    41.     }
    42. }
    43.  
    The code for the pistol as an example. The Submachine gun code is basically the same, but the damage/fire rate values are different, and it uses GetButton instead of GetButtonDown.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class PickupScript : MonoBehaviour
    6. {
    7.     float pickupRange = 10f;
    8.  
    9.     int pickuplayerMask;
    10.  
    11.     GameObject gamecontroller;
    12.  
    13.     GameObject WeaponSlot1, WeaponSlot2, WeaponSlot3, WeaponSlot4;
    14.  
    15.     Camera cam;
    16.  
    17.     WeaponDatabase database;
    18.     PlayerInventory inventory;
    19.  
    20.     void Start()
    21.     {
    22.         gamecontroller = GameObject.FindGameObjectWithTag("GameController");
    23.         database = gamecontroller.GetComponent<WeaponDatabase>();
    24.         inventory = gamecontroller.GetComponent<PlayerInventory>();
    25.         cam = GetComponent<Camera>();
    26.  
    27.         pickuplayerMask = LayerMask.GetMask("Pickup");
    28.     }
    29.  
    30.     void Update()
    31.     {
    32.         Ray ray = cam.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0f));
    33.         RaycastHit hit;
    34.  
    35.         if (Physics.Raycast(ray, out hit, pickupRange, pickuplayerMask))
    36.         {
    37.             int id = hit.transform.GetComponent<WeaponID>().weaponID;
    38.             if (Input.GetKeyDown(KeyCode.E))
    39.             {
    40.  
    41.                 if (inventory.inventory[0] == 0)
    42.                 {
    43.  
    44.                     inventory.inventory[0] = id;
    45.                     WeaponSlot1 = Instantiate(database.weapons[id].weaponObject, inventory.weaponSlot[0].gameObject.transform.position, inventory.weaponSlot[0].gameObject.transform.rotation);
    46.                     WeaponSlot1.transform.SetParent(inventory.weaponSlot[0].transform);
    47.                     Destroy(hit.transform.gameObject);
    48.                 }
    49.                 else if (inventory.inventory[1] == 0)
    50.                 {
    51.  
    52.                     inventory.inventory[1] = id;
    53.                     WeaponSlot2 = Instantiate(database.weapons[id].weaponObject, inventory.weaponSlot[1].gameObject.transform.position, inventory.weaponSlot[1].gameObject.transform.rotation);
    54.                     WeaponSlot2.transform.SetParent(inventory.weaponSlot[1].transform);
    55.                     Destroy(hit.transform.gameObject);
    56.                 }
    57.                 else if (inventory.inventory[2] == 0)
    58.                 {
    59.  
    60.                     inventory.inventory[2] = id;
    61.                     WeaponSlot3 = Instantiate(database.weapons[id].weaponObject, inventory.weaponSlot[2].gameObject.transform.position, inventory.weaponSlot[2].gameObject.transform.rotation);
    62.                     WeaponSlot3.transform.SetParent(inventory.weaponSlot[2].transform);
    63.                     Destroy(hit.transform.gameObject);
    64.                 }
    65.                 else if (inventory.inventory[3] == 0)
    66.                 {
    67.  
    68.                     inventory.inventory[3] = id;
    69.                     WeaponSlot4 = Instantiate(database.weapons[id].weaponObject, inventory.weaponSlot[3].gameObject.transform.position, inventory.weaponSlot[3].gameObject.transform.rotation);
    70.                     WeaponSlot4.transform.SetParent(inventory.weaponSlot[3].transform);
    71.                     Destroy(hit.transform.gameObject);
    72.                 }
    73.                 else
    74.                 {
    75.                     Debug.Log("Inventory's full m80");
    76.                 }
    77.  
    78.             }
    79.         }
    80.  
    81.     }
    82. }
    83.  
    The pickup script code. This code was derived from a Youtube tutorial from Single Sapling Games, but I edited it so that the weapon inventory is not hardcoded into slots, so that any weapon can take up any slot in any order.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class WeaponDatabase : MonoBehaviour
    6. {
    7.     public List<WeaponStats> weapons = new List<WeaponStats>();
    8. }
    9.  
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. [System.Serializable]
    6. public class WeaponStats
    7. {
    8.     public int WeaponID;
    9.  
    10.     public string name;
    11.     public GameObject weaponObject;
    12. }
    13.  
    The database and the stats code respectively.

    Any assistance would be appreciated. If you need any more information that could help solve the problem, let me know and I'll reply as soon as possible. Thank you in advance and have a good day to all who read this :)