Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice
  3. Dismiss Notice

Bug This code when executed 3 times only subtracts the variable twice, I don't know what to do anymore.

Discussion in 'Scripting' started by sieglew25, May 17, 2024.

  1. sieglew25

    sieglew25

    Joined:
    Dec 19, 2023
    Posts:
    2
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Target : MonoBehaviour
    6. {
    7.     public float health = 50f;
    8.     private EnemySpawn enemySpawnScript;
    9.     public GameObject enemySpawner;
    10.     public int enemiesKilled;
    11.     // Start is called before the first frame update
    12.     void Start()
    13.     {
    14.         enemySpawner = GameObject.Find("EnemySpawner2");
    15.         enemySpawnScript = enemySpawner.GetComponent<EnemySpawn>();
    16.     }
    17.  
    18.     public void TakeDamage(float amount)
    19.     {
    20.         health -= amount;
    21.         if (health <= 0.0f)
    22.         {
    23.             enemySpawnScript.enemiesSpawned -= 2;
    24.             Destroy(gameObject);
    25.         }
    26.     }
    27.     // Update is called once per frame
    28.  
    29. }
    The variable in question is enemySpawnScript.enemiesSpawned
    The script this comes from is
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. public class EnemySpawn : MonoBehaviour
    5. {
    6.     public GameObject theEnemy;
    7.     public GameObject theTank;
    8.     public GameObject theMiniBoss;
    9.     private int xPos;
    10.     private int zPos;
    11.     public bool gameStart = false;
    12.     double diffCount;
    13.     int sc;
    14.     bool loopRun = true;
    15.     public bool levelTut = false;
    16.     float stimer;
    17.     public int enemiesSpawned = 0;
    18.     // Start is called before the first frame update
    19.     public void Start()
    20.     {
    21.        
    22.     }
    23.    
    24.     // Update is called once per frame
    25.     void Update()
    26.     {
    27.         print("EnemiesSpawned" + enemiesSpawned);
    28.         if (enemiesSpawned == 0 && loopRun == true)
    29.         {
    30.             SpawnEnemies();
    31.             loopRun = false;
    32.         }
    33.     }
    34.  
    35.     void GenerateEnemy()
    36.     {
    37.         xPos = UnityEngine.Random.Range(-5, 5);
    38.         zPos = UnityEngine.Random.Range(-5, 5);
    39.         Instantiate(theEnemy, new Vector3(xPos, 2, zPos), Quaternion.identity);
    40.     }
    41.     void GenerateTank()
    42.     {
    43.         xPos = UnityEngine.Random.Range(-5, 5);
    44.         zPos = UnityEngine.Random.Range(-5, 5);
    45.         Instantiate(theTank, new Vector3(xPos, 2, zPos), Quaternion.identity);
    46.     }
    47.     void GenerateMiniBoss()
    48.     {
    49.         xPos = UnityEngine.Random.Range(-5, 5);
    50.         zPos = UnityEngine.Random.Range(-5, 5);
    51.         Instantiate(theMiniBoss, new Vector3(xPos, 2, zPos), Quaternion.identity);
    52.     }
    53.     void SpawnEnemies()
    54.     {
    55.         if (levelTut != true)
    56.         {
    57.             if (gameStart == true)
    58.             {
    59.                 for (sc = 0, stimer = 1; diffCount <= 1 && sc <= 2; sc++, stimer++)
    60.                 {
    61.                     Invoke("GenerateEnemy", 1.5f * stimer);
    62.                     enemiesSpawned+=2;
    63.                 }
    64.                 for (sc = 0, stimer = 1; diffCount <= 3 && sc <= 5 && diffCount > 1; sc++, stimer++)
    65.                 {
    66.                     Invoke("GenerateEnemy", 1.2f * stimer);
    67.                     enemiesSpawned++;
    68.                 }
    69.                 for (sc = 0, stimer = 1; diffCount <= 6 && sc <= 5 && diffCount > 3; sc++, stimer++)
    70.                 {
    71.                     if (sc < 3)
    72.                     {
    73.                         Invoke("GenerateEnemy", 0.9f * stimer);
    74.                         enemiesSpawned++;
    75.                     }
    76.                     else
    77.                     {
    78.                         Invoke("GenerateTank", 1.5f * stimer);
    79.                         enemiesSpawned++;
    80.                     }
    81.                 }
    82.                 for (sc = 0, stimer = 1; diffCount <= 9 && sc <= 7 && diffCount > 6; sc++, stimer++)
    83.                 {
    84.                     if (sc < 3)
    85.                     {
    86.                         Invoke("GenerateEnemy", 0.9f * stimer);
    87.                         enemiesSpawned++;
    88.                     }
    89.                     else if (sc < 6)
    90.                     {
    91.                         Invoke("GenerateTank", 0.9f * stimer);
    92.                         enemiesSpawned++;
    93.                     }
    94.                     else
    95.                     {
    96.                         Invoke("GenerateMiniBoss", 0.9f * stimer);
    97.                         enemiesSpawned++;
    98.                     }
    99.                 }
    100.                 loopRun = true;
    101.                 diffCount++;
    102.                 if (diffCount == 10)
    103.                     gameStart = false;
    104.             }
    105.         }
    106.         else
    107.         {
    108.             for (sc = 0, stimer = 1; diffCount <= 9 && sc <= 7; sc++, stimer++)  //&& diffCount > 3
    109.             {
    110.                 if (sc < 3)
    111.                 {
    112.                     Invoke("GenerateEnemy", 0.9f * stimer);
    113.                     enemiesSpawned++;
    114.                 }
    115.                 else if (sc < 6)
    116.                 {
    117.                     Invoke("GenerateTank", 0.9f * stimer);
    118.                     enemiesSpawned++;
    119.                 }
    120.                 else
    121.                 {
    122.                     Invoke("GenerateMiniBoss", 0.9f * stimer);
    123.                     enemiesSpawned++;
    124.                 }
    125.             }
    126.         }
    127.     }
    128. }
     
  2. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 5, 2024
    Posts:
    549
    Are you sure it doesn't immediately starts to spawn new enemies as per you instruct it in the Update method if the
    enemiesSpawned == 0
    ?
     
  3. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,684
    Honestly it might be best for you to explain what you're trying to do with that code than how to fix it because that seems way too complex for a spawner.
     
  4. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,594
    I tried reading though this code... this code is bonkers.

    Why do you have a bunch of variables defined at the classes field level when they're intended only for local use in the 'SpawnEnemies' method?

    What on god's green earth is this?
    Code (csharp):
    1. for (sc = 0, stimer = 1; diffCount <= 1 && sc <= 2; sc++, stimer++)
    This is the most unreadable level of nonsense. Why is 'diffCount' being checked in the for loop?

    Also, why is your enemiesCount += 2 in some places, ++ in another, and -= 2 in 'Target'? This is possibly related to why it's subtracting only twice?

    ...

    I tried refactoring it so it was slightly more readable, but I still don't quite get what you're attempting.

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections.Generic;
    3.  
    4. public class Target : MonoBehaviour
    5. {
    6.    
    7.     public float health = 50f;
    8.     [System.NonSerialized]public EnemySpawn spawner;
    9.    
    10.     public void TakeDamage(float amount)
    11.     {
    12.         health -= amount;
    13.         if (health <= 0.0f)
    14.         {
    15.             if (spawner) spawner.SignalDied(this);
    16.             Destroy(gameObject);
    17.         }
    18.     }
    19.  
    20. }
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections.Generic;
    3.  
    4. public class EnemySpawn : MonoBehaviour
    5. {
    6.    
    7.     public GameObject theEnemy;
    8.     public GameObject theTank;
    9.     public GameObject theMiniBoss;
    10.    
    11.     public bool gameStart = false;
    12.     public bool levelTut = false;
    13.     public int enemiesSpawned = 0;
    14.    
    15.     int diffCount = 0;
    16.     bool loopRun = true;
    17.    
    18.     public void SignalDied(Target targ)
    19.     {
    20.         enemiesSpawned -= 2; //again, why 2???
    21.     }
    22.    
    23.     void Update()
    24.     {
    25.         print("EnemiesSpawned" + enemiesSpawned);
    26.         if (loopRun && enemiesSpawned == 0)
    27.         {
    28.             SpawnEnemies();
    29.             loopRun = false;
    30.         }
    31.     }
    32.    
    33.     void SpawnEnemies()
    34.     {
    35.         int sc, stimer;
    36.         if (levelTut)
    37.         {
    38.             if (diffCount <= 9)
    39.             {
    40.                 for (sc = 0, stimer = 1; sc <= 7; sc++, stimer++)  //&& diffCount > 3
    41.                 {
    42.                     if (sc < 3)
    43.                     {
    44.                         Invoke("GenerateEnemy", 0.9f * stimer);
    45.                         enemiesSpawned++;
    46.                     }
    47.                     else if (sc < 6)
    48.                     {
    49.                         Invoke("GenerateTank", 0.9f * stimer);
    50.                         enemiesSpawned++;
    51.                     }
    52.                     else
    53.                     {
    54.                         Invoke("GenerateMiniBoss", 0.9f * stimer);
    55.                         enemiesSpawned++;
    56.                     }
    57.                 }
    58.             }
    59.         }
    60.         else if (gameStart)
    61.         {
    62.             switch (diffCount)
    63.             {
    64.                 case <= 1:
    65.                     for (sc = 0, stimer = 1; sc <= 2; sc++, stimer++)
    66.                     {
    67.                         Invoke("GenerateEnemy", 1.5f * stimer);
    68.                         enemiesSpawned+=2; //why 2???
    69.                     }
    70.                     break;
    71.                 case <= 3:
    72.                     for (sc = 0, stimer = 1; sc <= 2; sc++, stimer++)
    73.                     {
    74.                         Invoke("GenerateEnemy", 1.2f * stimer);
    75.                         enemiesSpawned++;
    76.                     }
    77.                     break;
    78.                 case <= 6:
    79.                     for (sc = 0, stimer = 1; sc <= 2; sc++, stimer++)
    80.                     {
    81.                         if (sc < 3)
    82.                         {
    83.                             Invoke("GenerateEnemy", 0.9f * stimer);
    84.                             enemiesSpawned++;
    85.                         }
    86.                         else
    87.                         {
    88.                             Invoke("GenerateTank", 1.5f * stimer);
    89.                             enemiesSpawned++;
    90.                         }
    91.                     }
    92.                     break;
    93.                 case <= 9:
    94.                     for (sc = 0, stimer = 1; sc <= 2; sc++, stimer++)
    95.                     {
    96.                         if (sc < 3)
    97.                         {
    98.                             Invoke("GenerateEnemy", 0.9f * stimer);
    99.                             enemiesSpawned++;
    100.                         }
    101.                         else if (sc < 6)
    102.                         {
    103.                             Invoke("GenerateTank", 0.9f * stimer);
    104.                             enemiesSpawned++;
    105.                         }
    106.                         else
    107.                         {
    108.                             Invoke("GenerateMiniBoss", 0.9f * stimer);
    109.                             enemiesSpawned++;
    110.                         }
    111.                     }
    112.                     break;
    113.             }
    114.            
    115.             loopRun = true;
    116.             diffCount++;
    117.             if (diffCount == 10)
    118.             {
    119.                 gameStart = false;
    120.             }
    121.     }
    122.  
    123.     void GenerateEnemy()
    124.     {
    125.         int xPos = UnityEngine.Random.Range(-5, 5);
    126.         int zPos = UnityEngine.Random.Range(-5, 5);
    127.         var inst = Instantiate(theEnemy, new Vector3(xPos, 2, zPos), Quaternion.identity);
    128.         if (inst.TryGetComponent(out Target targ)) targ.spawner = this;
    129.     }
    130.     void GenerateTank()
    131.     {
    132.         int xPos = UnityEngine.Random.Range(-5, 5);
    133.         int zPos = UnityEngine.Random.Range(-5, 5);
    134.         var inst = Instantiate(theTank, new Vector3(xPos, 2, zPos), Quaternion.identity);
    135.         if (inst.TryGetComponent(out Target targ)) targ.spawner = this;
    136.     }
    137.     void GenerateMiniBoss()
    138.     {
    139.         int xPos = UnityEngine.Random.Range(-5, 5);
    140.         int zPos = UnityEngine.Random.Range(-5, 5);
    141.         var inst = Instantiate(theMiniBoss, new Vector3(xPos, 2, zPos), Quaternion.identity);
    142.         if (inst.TryGetComponent(out Target targ)) targ.spawner = this;
    143.     }
    144.  
    145. }
    Part of me wanted to refactor out this whole 'enemiesSpawned' and instead have a collection to hold all spawned enemies. The count of that collection would reflect how many exist.

    Then in SignalDied you'd just remove them from the list.

    BUT

    I don't know why some enemies count by 2 rather than 1.

    If 'Target' exists on every enemy type (enemy, tank, miniboss).

    Also what should happen if they die from some other means than TakeDamage.

    ...

    I'm with @Ryiah, what are you trying to do here?
     
    Ryiah likes this.
  5. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,556
    1. Use the single-stepping feature of your debugger. Barring that, use print/Debug.Log more liberally, showing values as they're computed or acting as proof you got to a certain line of code.

    2. When you have multiple Debug.Log statements, make sure their strings are identifiably different. You can't tell if you're in the
    if
    or the
    else
    when you just see
    GenerateEnemy
    .
     
  6. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    6,922
    Code like this will break your neck:
    Code (CSharp):
    1.     for (sc = 0, stimer = 1; diffCount <= 1 && sc <= 2; sc++, stimer++)
    2.     {
    3.     }
    4.     for (sc = 0, stimer = 1; diffCount <= 3 && sc <= 5 && diffCount > 1; sc++, stimer++)
    5.     {
    6.     }
    7.     for (sc = 0, stimer = 1; diffCount <= 6 && sc <= 5 && diffCount > 3; sc++, stimer++)
    8.     {
    9.     }
    10.     for (sc = 0, stimer = 1; diffCount <= 9 && sc <= 7 && diffCount > 6; sc++, stimer++)
    11.     {
    12.     }
    13.  
    Do NOT use a for loop iteration variable outside the for loop. Declare it inside. Use a separate variable to record the last iteration value if necessary.

    Do NOT initialize more than the iteration variable. Any additional variable that needs resetting should be on a separate line before the for loop.

    Do NOT increment/decrement more than the iteration variable. Any additional counter value can be inferred from the iteration variable. Here it would be (sc+1) in every place where you use stimer, so you can omit stimer entirely.

    Do NOT abuse the for loop condition for anything else BUT the for loop iteration variable. Use if statements or a switch for the diffCount conditionals.

    All of this is for the sake of code readability, maintainability, and your ability to reason about and debug your code.
    Code (CSharp):
    1.     if (diffCount <= 1)
    2.     {
    3.         for (var sc = 0; sc <= 2; sc++)
    4.         {
    5.         }
    6.     }
    7.     else if (diffCount <= 3)
    8.     {
    9.         for (var sc = 0; sc <= 5; sc++)
    10.         {
    11.         }
    12.     }
    13.     else if (diffCount <= 6)
    14.     {
    15.         for (var sc = 0; sc <= 5; sc++)
    16.         {
    17.         }
    18.     }
    19.     else if (diffCount <= 9)
    20.     {
    21.         for (var sc = 0; sc <= 7; sc++)
    22.         {
    23.         }
    24.     }
     
    pm007, Kurt-Dekker and Ryiah like this.
  7. samana1407

    samana1407

    Joined:
    Aug 23, 2015
    Posts:
    282
    This is about refactoring the enemy spawn method. If you only need to generate a queue of calls without additional or unique features for each call, it might be worth consolidating such calls into a separate method. For example, a refactoring option that is visually easier to understand (in my opinion). The code has not been tested; it's just a draft:

    Code (CSharp):
    1. void SpawnEnemies()
    2. {
    3.     if (levelTut != true)
    4.     {
    5.         if (gameStart == true)
    6.         {
    7.             if (diffCount <= 1)
    8.             {
    9.                 InvokeQueue(GenerateEnemy, count: 3, delay: 1.5f);
    10.             }
    11.             else if (diffCount > 1 && diffCount <= 3)
    12.             {
    13.                 InvokeQueue(GenerateEnemy, count: 2, delay: 1.2f);
    14.             }
    15.             else if (diffCount > 3 && diffCount <= 6)
    16.             {
    17.                 float endTime = InvokeQueue(GenerateEnemy,  count: 3, delay: 0.9f);
    18.                 endTime =       InvokeQueue(GenerateTank,   count: 3, delay: 1.5f, delayOffset: endTime);
    19.             }
    20.             else if (diffCount > 6 && diffCount <= 9)
    21.             {
    22.                 float endTime = InvokeQueue(GenerateEnemy,      count: 3, delay: 0.9f);
    23.                 endTime =       InvokeQueue(GenerateTank,       count: 3, delay: 0.9f, delayOffset: endTime);
    24.                 endTime =       InvokeQueue(GenerateMiniBoss,   count: 2, delay: 0.9f, delayOffset: endTime);
    25.             }
    26.  
    27.             loopRun = true;
    28.             diffCount++;
    29.             if (diffCount == 10)
    30.                 gameStart = false;
    31.         }
    32.     }
    33.     else
    34.     {
    35.         if (diffCount <= 9)
    36.         {
    37.             float endTime = InvokeQueue(GenerateEnemy,  count: 3, delay: 0.9f);
    38.             endTime = InvokeQueue(GenerateTank,         count: 3, delay: 0.9f, delayOffset: endTime);
    39.             endTime = InvokeQueue(GenerateMiniBoss,     count: 2, delay: 0.9f, delayOffset: endTime);
    40.         }
    41.     }
    42. }
    43.  
    44. private float InvokeQueue(Action action, int count, float delay, float delayOffset = 0)
    45. {
    46.     for (int i = 1; i <= count; i++)
    47.     {
    48.         Invoke(action.Method.Name, delayOffset + (delay * i));
    49.         enemiesSpawned++;
    50.     }
    51.  
    52.     return delayOffset + (delay * count);
    53. }
     
    Ryiah likes this.
  8. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    2,001
    A thing that stands out to me is an enemy-count variable is usually a pain -- just as you've seen, too easy to get out-of-step with the actual number of enemies. In practice there will eventually need to be a list of the enemies for various reasons, and when an enemy dies, it will need to be removed from the list. Then the enemy count is just the length of the list.

    With the
    if(diff<=1) ... else if(diff>1 && diff<=3)
    part it can be nicer to use a cascading-if style listing only the top end: if(diff<=1) ... else if(diff<=3) ... else if(diff<=7). A little less error-prone (not having to write each cut-off twice and getting > and <= correct) and helps communicate how we're slicing the range.

    But I've found it easier to put level-spawning sequences in a list instead of in code like that. Something like: SpawnDiff1=[{secs:3,enemies:3,type:drone}, {secs:6,enemies:3,type:drone} ... ].
     
    samana1407 likes this.
  9. sieglew25

    sieglew25

    Joined:
    Dec 19, 2023
    Posts:
    2
    Thanks for the help! I able to get the enemiesSpawned variable to get to 0 but the switch case statements still don't run.
    The first enemy wave runs, but the others don't
    ALSO the reason I had some of the counters go up by 2 was for testing, it is back to one now.
    Every enemy has the target script on it.
    Enemies cannot die from any other means.