Search Unity

Reload problem

Discussion in 'Scripting' started by Flynn_Prime, Jun 25, 2017.

  1. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    387
    I have a problem with my current reload script. As soon as my scene loads, it checks if the gun has any current ammo, but because this is happening via OnEnable() it is always 0 as my curAmmo is set to maxAmmo in Start(). If I moved it to OnEnable() then every time the weapon is swapped in and out the current ammo would be set to max.

    I tried to initiate all of my character stats in Awake() but for some reason they would not work (all remained 0). Can someone please elaborate as to why this may be?

    Also, a second bug I have is that once the weapon reloads, the player can continue to shoot for a certain time before curAmmo will start to decrease again. No idea what is causing this delay, and I am not sure if it is a problem in the first script below, or the second; but I suspect it is more than likely the first causing the issue.

    Any help would be much appreciated. I have spent the best part of 2 days trying to debug this to no avail.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5. using DarkTonic.CoreGameKit;
    6.  
    7. public class GunBaseClass : MonoBehaviour, IShoot {
    8.  
    9.     [SerializeField] public string gunName;
    10.  
    11.     //[SerializeField] public int gunRank; (Higher rank weapon increases gunLvl)
    12.     [SerializeField] public int gunLvl;
    13.  
    14.     [SerializeField] public float minGunDamage;
    15.     [SerializeField] public float maxGunDamage;
    16.     [SerializeField] public float gunDmgBase;
    17.     [SerializeField] public float gunDmgGrowth;
    18.  
    19.     [SerializeField] public float critDmg; //Critical hit dmg multiplier
    20.     [SerializeField] public float critDmgBase;
    21.     [SerializeField] public float critDmgGrowth;
    22.     [SerializeField] public float critDmgCap;
    23.  
    24.     [SerializeField] public int curAmmo;
    25.     [SerializeField] public int maxAmmo;
    26.     [SerializeField] public int maxAmmoBase;
    27.     [SerializeField] public int maxAmmoGrowth;
    28.     [SerializeField] public int maxAmmoCap;
    29.  
    30.     [SerializeField] public float reloadTime;
    31.     public bool isReloading = false;
    32.     private Image reloadBar;
    33.  
    34.     [SerializeField] public float fireRate; //fireRate = bullets per/sec
    35.  
    36.     public void Start ()
    37.     {
    38.         minGunDamage = (gunDmgBase + (Mathf.Pow(gunLvl, gunDmgGrowth)) - (0.2f * (gunDmgBase + (Mathf.Pow(gunLvl, gunDmgGrowth)))));
    39.         maxGunDamage = (gunDmgBase + (Mathf.Pow(gunLvl, gunDmgGrowth)) + (0.2f * (gunDmgBase + (Mathf.Pow(gunLvl, gunDmgGrowth)))));
    40.  
    41.         critDmg = critDmgBase + (Mathf.Pow (gunLvl, critDmgGrowth));
    42.  
    43.         maxAmmo = maxAmmoBase + (gunLvl * maxAmmoGrowth);
    44.         curAmmo = maxAmmo; //Needs to be called before OnEnable but howwwww?
    45.     }
    46.  
    47.     public virtual void Update ()
    48.     {
    49.         if (critDmg > critDmgCap)
    50.             critDmg = critDmgCap;
    51.         if (maxAmmo > maxAmmoCap)
    52.             maxAmmo = maxAmmoCap;
    53.  
    54.         if (curAmmo <= 0)
    55.         {
    56.             StartCoroutine(Reload ());
    57.             return;
    58.         }
    59.     }
    60.  
    61.     public virtual void OnEnable ()
    62.     {
    63.         reloadBar = GameObject.Find("ReloadImage").GetComponent<Image> ();
    64.  
    65.         if (curAmmo != 0)
    66.         {
    67.             isReloading = false;
    68.             reloadBar.fillAmount = 1f;
    69.             GameObject.Find ("CurAmmoCount").GetComponent<Animator> (). SetBool ("Reloading", false);
    70.             GameObject.Find ("MaxAmmoCount").GetComponent<Animator> (). SetBool ("Reloading", false);
    71.         }
    72.         else
    73.         {
    74.             StartCoroutine (Reload());
    75.         }
    76.     }
    77.  
    78.     public virtual void Shoot ()
    79.     {
    80.         //Unique weapon behaviours
    81.     }
    82.  
    83.     public bool CritChance ()
    84.     {
    85.         int temp = Random.Range (0, 100);
    86.  
    87.         if (temp < GameObject.FindGameObjectWithTag("Player").GetComponent<CharacterBaseClass>().curCritRate) { //1 crit rate = 1% chance of a crit
    88.             return true;
    89.         }
    90.         else
    91.         {
    92.             return false;
    93.         }
    94.     }
    95.  
    96.     public IEnumerator Reload ()
    97.     {
    98.         isReloading = true;
    99.         var reloadTimeActual = reloadTime - ((reloadTime / 100) * GameObject.FindGameObjectWithTag ("Player").GetComponent<CharacterBaseClass> ().curReloadSpd);
    100.         reloadBar.fillAmount -= 1.0f / reloadTimeActual * Time.deltaTime;
    101.         GameObject.Find ("CurAmmoCount").GetComponent<Animator> (). SetBool ("Reloading", true);
    102.         GameObject.Find ("MaxAmmoCount").GetComponent<Animator> (). SetBool ("Reloading", true);
    103.  
    104.         yield return new WaitForSeconds (reloadTimeActual);
    105.  
    106.         GameObject.Find ("CurAmmoCount").GetComponent<Animator> (). SetBool ("Reloading", false);
    107.         GameObject.Find ("MaxAmmoCount").GetComponent<Animator> (). SetBool ("Reloading", false);
    108.         isReloading = false;
    109.         curAmmo = maxAmmo;
    110.         reloadBar.fillAmount = 1.0f;
    111.         gameObject.GetComponent<AmmoUI> ().UpdateAmmo ();
    112.  
    113.         StopCoroutine (Reload());
    114.     }
    115. }

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. public class AmmoUI : MonoBehaviour {
    7.  
    8.     private Text curAmmo;
    9.     private Text maxAmmo;
    10.  
    11.     void Awake ()
    12.     {
    13.         curAmmo = GameObject.Find("CurAmmoCount").GetComponent<Text>();
    14.         maxAmmo = GameObject.Find("MaxAmmoCount").GetComponent<Text>();
    15.     }
    16.  
    17.     void Start ()
    18.     {
    19.         UpdateAmmo ();
    20.     }
    21.  
    22.     void OnEnable ()
    23.     {
    24.         UpdateAmmo ();
    25.     }
    26.  
    27.     public void UpdateAmmo ()
    28.     {
    29.         curAmmo.text = gameObject.GetComponent<GunBaseClass>().curAmmo.ToString () + " ";
    30.         maxAmmo.text = "/ " + gameObject.GetComponent<GunBaseClass> ().maxAmmo.ToString ();
    31.     }
    32. }
     
  2. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,187
    How is maxammo and curammo being set in your GunBaseClass. You should be able to use Awake, which is why I'm curious if something else isn't right. And I'm not referring to if your UI script is showing the correct number, but if it actually has a value that isn't 0 for those two fields.
     
  3. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    387
    As above, maxAmmo is calculated from Base, and Growth (this is the basis on which all of my stats are derived) within the Start () function. Base and Growth for all stats is set in the Inspector.

    If I simply change Start () to Awake () then all of my stats, other than those set in the Inspector, are not calculated and show as 0.

    EDIT:

    Not sure on how execution/read order of variables set in the Inspector works. So when I can I will set the Base and Grouth values initially within the script. Hopefully this will fix the issue.

    Any idea on the reload issue? I thought it may be a problem with the reload time but don't think that is the case now, as the bool 'isReloading' acts as it is supposed to, and I can fire once 'isReloading' equals false. There is a few split seconds when reloading is complete where I can still fire, and both my curAmmo and the UI text do not decrease with each shot
     
    Last edited: Jun 26, 2017
  4. cstooch

    cstooch

    Joined:
    Apr 16, 2014
    Posts:
    354
    Haven't looked at your issue with the reloading and ammo not decreasing, but re: the Awake thing...

    The order of events is:

    Awake..
    OnEnable
    Start

    (There's other stuff in here too, but I ignored that since you only care about these 3).

    Awake should work for initializing your variables. Make sure that maxAmmoBase is set somewhere (inspector?). Looking at your GunBaseClass script, maxAmmoBase drives both your maxAmmo and your curAmmo variables, so if you haven't set maxAmmonBase in Awake or in the inspector of GunBaseClass, then that is of course why your maxAmmo and curAmmo are not set.


    Re: your reloading and ammo issue.. your shooting function does check that isReloading == false before allowing you to shoot?
     
  5. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    387
    Thanks for the reply.

    As mentioned above, maxAmmoBase is set via the Inspector. Yet if I try to set maxAmmo in Awake, it doesn't work; curAmmo and maxAmmo are never calculated and remain 0.

    And yes, my shoot function checks that isReloading == false before allowing a shot. I can see in the Inspector that isReloading is false, but for a short period after reloading ammo count still does not decrease.
     
  6. cstooch

    cstooch

    Joined:
    Apr 16, 2014
    Posts:
    354
    Sorry, I missed you saying maxAmmoBase was set in inspector in your follow up.

    It really should work in Awake though. You don't have your Awake function overridden in a class that derives from this by chance (and obviously that is attached to your game object instead of this script)? I noticed your OnEnable was using virtual, so that's why I was wondering that.

    If you override Awake in the derived class, you'll of course either want to do your set up of the ammo stuff within there, or be sure to call base.Awake.
     
  7. cstooch

    cstooch

    Joined:
    Apr 16, 2014
    Posts:
    354
    Just to make sure I got this right, curAmmo is the value that isn't decreasing, right?

    I'm not clear where you're actually decreasing this value (I presume on your shoot function of the derived class, but you haven't included that in the code above). Can you point out and/or provide code to where you're decreasing this value? Also, when you shoot, I assume it makes a call to update your UI with "UpdateAmmo"?


    It might be best for you to update using Awake to set those ammo variables, and post your updated code along with the derived class script (or wherever your shoot function exists) to get help on why that isn't working right.
     
  8. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    387
    Thanks for that. I had an Awake function on a child class that didn't override and include base.Awake. So this has fixed the issue of the initial curAmmo being set. The other problem still persists.

    I use both raycast guns and projectile guns, and below are my Shoot() methods for each. They both have the same problem after a reload occurs, with curAmmo not decreasing.

    Code (CSharp):
    1. public override void Update ()
    2.     {
    3.         base.Update ();
    4.         if (JoystickFire.instance.Fire && isReloading == false)
    5.         {
    6.             Shoot ();
    7.         }
    8.         if (fireTimer < fireRate)
    9.             fireTimer += Time.deltaTime;
    10.     }
    11.  
    12.     public override void Shoot ()
    13.     {
    14.         if (fireTimer < fireRate)
    15.         {
    16.             return;
    17.         }
    18.  
    19.         curAmmo--;
    20.         gameObject.GetComponent<AmmoUI> ().UpdateAmmo ();
    21.  
    22.         StartCoroutine (ShotEffect ());
    23.         RaycastHit hit;
    24.         laserLine.SetPosition (0, raycastMuzzle.position);
    25.  
    26.         if (Physics.Raycast (raycastMuzzle.position, raycastMuzzle.transform.forward, out hit, gunRange))
    27.         {
    28.             laserLine.SetPosition (1, hit.point);
    29.  
    30.             if (hit.collider.tag == "Enemy")
    31.             {
    32.                 var gunDmgActual = Random.Range (gameObject.GetComponent<GunBaseClass> ().minGunDamage, gameObject.GetComponentInChildren<GunBaseClass> ().maxGunDamage) + GameObject.FindGameObjectWithTag ("Player").GetComponent<CharacterBaseClass> ().curGunDmg;
    33.                 hit.collider.GetComponent<EnemyHP> ().UpdateHealth (gunDmgActual, CritChance(), critDmg);
    34.             }
    35.         }
    36.         else
    37.         {
    38.             laserLine.SetPosition (1, raycastMuzzle.transform.position + raycastMuzzle.transform.forward * gunRange);
    39.         }
    40.  
    41.         fireTimer = 0.0f;
    42.     }

    Code (CSharp):
    1. public override void Update ()
    2.     {
    3.         base.Update ();
    4.         if (JoystickFire.instance.Fire && Time.time > fireRate + lastShot && isReloading == false)
    5.         {
    6.             Shoot ();
    7.         }
    8.     }
    9.  
    10.     public override void Shoot ()
    11.     {
    12.             curAmmo--;
    13.             gameObject.GetComponent<AmmoUI> ().UpdateAmmo ();
    14.  
    15.             Transform spawnedBullet = PoolBoss.SpawnInPool (ammo, muzzleTip.position, muzzleTip.rotation);
    16.             GameObject bullet = spawnedBullet.GetComponent<GameObject> ();
    17.  
    18.             if (bullet != null)
    19.             {
    20.                 bullet.transform.position = muzzleTip.position;
    21.                 bullet.transform.rotation = transform.rotation;
    22.                 bullet.SetActive (true);
    23.             }
    24.             lastShot = Time.time;
    25.     }
     
  9. cstooch

    cstooch

    Joined:
    Apr 16, 2014
    Posts:
    354
    You didn't re-declare "curAmmo" as part of your derived class, did you? (you shouldn't have). Just trying to get an understanding if curAmmo in your Raycast and Projectile classes is really the same as the Base class curAmmo.

    Completely unrelated here, but how come you have this in your Raycast class but not in projectile one?

    if (fireTimer < fireRate) return
     
  10. Flynn_Prime

    Flynn_Prime

    Joined:
    Apr 26, 2017
    Posts:
    387
    They both use the inherited curAmmo, nothing is redeclared.

    And that different code is because I'm a noob and couldn't figure out how to get fire rate the same for projectiles and raycasting using the same code :p My projectile gun uses and timer with invoke to instantiate projectiles at a set rate