Search Unity

Discussion A Bug free game seems impossible and it annoys me

Discussion in 'Scripting' started by Joggla, Oct 25, 2022.

  1. Joggla

    Joggla

    Joined:
    Dec 2, 2019
    Posts:
    88
    I have this ability in my game (its a shield that blocks the first incoming damage)
    95% of time the shield works as planned and negates the first damage taken.
    but like 5% of time the shield does not pop
    Its like so hard to debug when the bug itsself doesnt happen often.
    how to go about this problem?

    I was thinking of maby removing the shield ability completly or should i just be happy it works 95% of time?
     
  2. GonzoBonDonzo

    GonzoBonDonzo

    Joined:
    Jul 29, 2022
    Posts:
    63
    How are you doing the shield? Is the shield called when pressing a button and does it have a duration? (or is the duration while button pressed?).

    If you share that portion of the code, maybe some advice can be offered.

    When something is acting flaky, my go to solution is an IEnumerator for the function :D
     
    CodeSmile likes this.
  3. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    5,838
    Yup, post the code. Maybe the issue is obvious.
     
    Bunny83 likes this.
  4. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,425
    Maybe this shield has a collider and whatever hits it is using discrete collision-detection so depending on its motion (whatever it is) it's hitting both the shield and something else?

    As above, more details required if you really do want help.
     
  5. Joggla

    Joggla

    Joined:
    Dec 2, 2019
    Posts:
    88
    Code (CSharp):
    1. public class Shield : Ability, IAbility
    2. {
    3.     public override void AbilityEffect(Unit unit)
    4.     {
    5.        
    6.         if(unit.bulletsToCalculate.Count > 0) //if has been hit by any bullets
    7.         {
    8.             Bullet hitBullet = unit.bulletsToCalculate[0];
    9.             unit.bulletsToCalculate.Remove(hitBullet);
    10.             Destroy(hitBullet.gameObject);  
    11.             unit.abilities.Remove(this); //remove ability from unit
    12.             Destroy(this.gameObject);
    13.         }
    14.     }
    15. }
    Thats the code for the shield. Should basically remove the first bullet hit. And the destroy itsself.

    This function gets called every frame in update to cicle through all the abiities the unit has in the Unit class:

    Code (CSharp):
    1. private void UpdateAbilities()
    2.     {
    3.         abilities.OrderBy(x => x.priority).ToList();
    4.         foreach(Ability ability in abilities.ToList())
    5.         {
    6.             ability.AbilityEffect(this);
    7.         }
    8.     }
     
  6. Joggla

    Joggla

    Joined:
    Dec 2, 2019
    Posts:
    88
    Have tested it now for like 20 times + and the bug has not occured sofar anymore


    Edit: the small chance bug that a bullet is not removed has occured again.

    Code (CSharp):
    1. public class Shield : Ability, IAbility
    2. {
    3.     public override void AbilityEffect(Unit unit)
    4.     {
    5.        
    6.         if(unit.bulletsToCalculate.Count > 0) //if has been hit by any bullets
    7.         {
    8.             Debug.Log("Removing bullet");
    9.             Bullet hitBullet = unit.bulletsToCalculate[0];
    10.             unit.bulletsToCalculate.Remove(hitBullet);
    11.             Destroy(hitBullet.gameObject);  
    12.             unit.abilities.Remove(this); //remove ability from unit
    13.             Destroy(this.gameObject);
    14.         }
    15.     }
    16. }
    note: the debug log ("Removing bullet") is not being shown in the case that the bullet does not destroy the shield -> meaning the bulletsToCalculate list is empty and the bullet did not get added to it
     
    Last edited: Oct 25, 2022
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,674
    Remember that Destroy() does not happen until end of frame.
     
  8. GonzoBonDonzo

    GonzoBonDonzo

    Joined:
    Jul 29, 2022
    Posts:
    63
    Going on what Kurt mentioned (destroy doesn't happen until the end of the frame, regardless of order), why don't you try hitBullet = null when you want it disabled, then destroy it at the end.

    I suggest this, because there was a transform I needed to destory in a function (a ground detection transform), but because it wasn't being destroyed until the end of the frame, it was causing some funky reactions (during a "death" sequence). So = null on it when I needed it technically disabled, then destroyed it.
     
  9. Nad_B

    Nad_B

    Joined:
    Aug 1, 2021
    Posts:
    712
    EDIT: Just noticed that you're not assigning the OrderBy result to a new variable

    Code (CSharp):
    1. // This line just wastes CPU and RAM for nothing
    2. // OrderBy returns a new collection, it does not change the original collection
    3. // Do not confuse .Sort() (which is a List method) with .OrderBy() (which is a LINQ extension)
    4. one.abilities.OrderBy(x => x.priority).ToList();
    5.  
    6. // The correct way to do it:
    7. var sortedAbilities = abilities.OrderBy(x => x.priority);
    8.  
    9. foreach (var ability in sortedAbilities)
    10. {
    11.     ability.AbilityEffect(this);
    12. }

    Also this looks super unoptimized, especially if it's running each frame... A solution is that you should only order the abilities once when they're added/removed, which would happen a lot less often than each update. Or you could just use a SortedList, which will take care of sorting for you. Also in the foreach loop you don't need to create another copy of the list (.ToList()) if you're only using the IEnumerable result from OrderBy only once. (which is the case here)
     
    Last edited: Oct 26, 2022
  10. Joggla

    Joggla

    Joined:
    Dec 2, 2019
    Posts:
    88
    yep ur right, i already changed the ability ordering stuff when the unit is instatiated to only run once
    but in the end i gave up on the shield ability and removed it completly
     
  11. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,627
    Are you sure that aren't two bullets with the exact same position and velocity? In that case it would just look like one bullet. Only one of the two bullets would be deleted and the other would still hit, making it look like the shield did nothing.
     
    Nad_B likes this.