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

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Target : MonoBehaviour
{
    public float health = 50f;
    private EnemySpawn enemySpawnScript;
    public GameObject enemySpawner;
    public int enemiesKilled;
    // Start is called before the first frame update
    void Start()
    {
        enemySpawner = GameObject.Find("EnemySpawner2");
        enemySpawnScript = enemySpawner.GetComponent<EnemySpawn>();
    }

    public void TakeDamage(float amount)
    {
        health -= amount;
        if (health <= 0.0f)
        {
            enemySpawnScript.enemiesSpawned -= 2;
            Destroy(gameObject);
        }
    }
    // Update is called once per frame

}

The variable in question is enemySpawnScript.enemiesSpawned
The script this comes from is

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemySpawn : MonoBehaviour
{
    public GameObject theEnemy;
    public GameObject theTank;
    public GameObject theMiniBoss;
    private int xPos;
    private int zPos;
    public bool gameStart = false;
    double diffCount;
    int sc;
    bool loopRun = true;
    public bool levelTut = false;
    float stimer;
    public int enemiesSpawned = 0;
    // Start is called before the first frame update
    public void Start()
    {
       
    }
   
    // Update is called once per frame
    void Update()
    {
        print("EnemiesSpawned" + enemiesSpawned);
        if (enemiesSpawned == 0 && loopRun == true)
        {
            SpawnEnemies();
            loopRun = false;
        }
    }
  
    void GenerateEnemy()
    {
        xPos = UnityEngine.Random.Range(-5, 5);
        zPos = UnityEngine.Random.Range(-5, 5);
        Instantiate(theEnemy, new Vector3(xPos, 2, zPos), Quaternion.identity);
    }
    void GenerateTank()
    {
        xPos = UnityEngine.Random.Range(-5, 5);
        zPos = UnityEngine.Random.Range(-5, 5);
        Instantiate(theTank, new Vector3(xPos, 2, zPos), Quaternion.identity);
    }
    void GenerateMiniBoss()
    {
        xPos = UnityEngine.Random.Range(-5, 5);
        zPos = UnityEngine.Random.Range(-5, 5);
        Instantiate(theMiniBoss, new Vector3(xPos, 2, zPos), Quaternion.identity);
    }
    void SpawnEnemies()
    {
        if (levelTut != true)
        {
            if (gameStart == true)
            {
                for (sc = 0, stimer = 1; diffCount <= 1 && sc <= 2; sc++, stimer++)
                {
                    Invoke("GenerateEnemy", 1.5f * stimer);
                    enemiesSpawned+=2;
                }
                for (sc = 0, stimer = 1; diffCount <= 3 && sc <= 5 && diffCount > 1; sc++, stimer++)
                {
                    Invoke("GenerateEnemy", 1.2f * stimer);
                    enemiesSpawned++;
                }
                for (sc = 0, stimer = 1; diffCount <= 6 && sc <= 5 && diffCount > 3; sc++, stimer++)
                {
                    if (sc < 3)
                    {
                        Invoke("GenerateEnemy", 0.9f * stimer);
                        enemiesSpawned++;
                    }
                    else
                    {
                        Invoke("GenerateTank", 1.5f * stimer);
                        enemiesSpawned++;
                    }
                }
                for (sc = 0, stimer = 1; diffCount <= 9 && sc <= 7 && diffCount > 6; sc++, stimer++)
                {
                    if (sc < 3)
                    {
                        Invoke("GenerateEnemy", 0.9f * stimer);
                        enemiesSpawned++;
                    }
                    else if (sc < 6)
                    {
                        Invoke("GenerateTank", 0.9f * stimer);
                        enemiesSpawned++;
                    }
                    else
                    {
                        Invoke("GenerateMiniBoss", 0.9f * stimer);
                        enemiesSpawned++;
                    }
                }
                loopRun = true;
                diffCount++;
                if (diffCount == 10)
                    gameStart = false;
            }
        }
        else
        {
            for (sc = 0, stimer = 1; diffCount <= 9 && sc <= 7; sc++, stimer++)  //&& diffCount > 3
            {
                if (sc < 3)
                {
                    Invoke("GenerateEnemy", 0.9f * stimer);
                    enemiesSpawned++;
                }
                else if (sc < 6)
                {
                    Invoke("GenerateTank", 0.9f * stimer);
                    enemiesSpawned++;
                }
                else
                {
                    Invoke("GenerateMiniBoss", 0.9f * stimer);
                    enemiesSpawned++;
                }
            }
        }
    }
}

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?

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.

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?

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.

using UnityEngine;
using System.Collections.Generic;

public class Target : MonoBehaviour
{
   
    public float health = 50f;
    [System.NonSerialized]public EnemySpawn spawner;
   
    public void TakeDamage(float amount)
    {
        health -= amount;
        if (health <= 0.0f)
        {
            if (spawner) spawner.SignalDied(this);
            Destroy(gameObject);
        }
    }

}
using UnityEngine;
using System.Collections.Generic;

public class EnemySpawn : MonoBehaviour
{
   
    public GameObject theEnemy;
    public GameObject theTank;
    public GameObject theMiniBoss;
   
    public bool gameStart = false;
    public bool levelTut = false;
    public int enemiesSpawned = 0;
   
    int diffCount = 0;
    bool loopRun = true;
   
    public void SignalDied(Target targ)
    {
        enemiesSpawned -= 2; //again, why 2???
    }
   
    void Update()
    {
        print("EnemiesSpawned" + enemiesSpawned);
        if (loopRun && enemiesSpawned == 0)
        {
            SpawnEnemies();
            loopRun = false;
        }
    }
   
    void SpawnEnemies()
    {
        int sc, stimer;
        if (levelTut)
        {
            if (diffCount <= 9)
            {
                for (sc = 0, stimer = 1; sc <= 7; sc++, stimer++)  //&& diffCount > 3
                {
                    if (sc < 3)
                    {
                        Invoke("GenerateEnemy", 0.9f * stimer);
                        enemiesSpawned++;
                    }
                    else if (sc < 6)
                    {
                        Invoke("GenerateTank", 0.9f * stimer);
                        enemiesSpawned++;
                    }
                    else
                    {
                        Invoke("GenerateMiniBoss", 0.9f * stimer);
                        enemiesSpawned++;
                    }
                }
            }
        }
        else if (gameStart)
        {
            switch (diffCount)
            {
                case <= 1:
                    for (sc = 0, stimer = 1; sc <= 2; sc++, stimer++)
                    {
                        Invoke("GenerateEnemy", 1.5f * stimer);
                        enemiesSpawned+=2; //why 2???
                    }
                    break;
                case <= 3:
                    for (sc = 0, stimer = 1; sc <= 2; sc++, stimer++)
                    {
                        Invoke("GenerateEnemy", 1.2f * stimer);
                        enemiesSpawned++;
                    }
                    break;
                case <= 6:
                    for (sc = 0, stimer = 1; sc <= 2; sc++, stimer++)
                    {
                        if (sc < 3)
                        {
                            Invoke("GenerateEnemy", 0.9f * stimer);
                            enemiesSpawned++;
                        }
                        else
                        {
                            Invoke("GenerateTank", 1.5f * stimer);
                            enemiesSpawned++;
                        }
                    }
                    break;
                case <= 9:
                    for (sc = 0, stimer = 1; sc <= 2; sc++, stimer++)
                    {
                        if (sc < 3)
                        {
                            Invoke("GenerateEnemy", 0.9f * stimer);
                            enemiesSpawned++;
                        }
                        else if (sc < 6)
                        {
                            Invoke("GenerateTank", 0.9f * stimer);
                            enemiesSpawned++;
                        }
                        else
                        {
                            Invoke("GenerateMiniBoss", 0.9f * stimer);
                            enemiesSpawned++;
                        }
                    }
                    break;
            }
           
            loopRun = true;
            diffCount++;
            if (diffCount == 10)
            {
                gameStart = false;
            }
    }

    void GenerateEnemy()
    {
        int xPos = UnityEngine.Random.Range(-5, 5);
        int zPos = UnityEngine.Random.Range(-5, 5);
        var inst = Instantiate(theEnemy, new Vector3(xPos, 2, zPos), Quaternion.identity);
        if (inst.TryGetComponent(out Target targ)) targ.spawner = this;
    }
    void GenerateTank()
    {
        int xPos = UnityEngine.Random.Range(-5, 5);
        int zPos = UnityEngine.Random.Range(-5, 5);
        var inst = Instantiate(theTank, new Vector3(xPos, 2, zPos), Quaternion.identity);
        if (inst.TryGetComponent(out Target targ)) targ.spawner = this;
    }
    void GenerateMiniBoss()
    {
        int xPos = UnityEngine.Random.Range(-5, 5);
        int zPos = UnityEngine.Random.Range(-5, 5);
        var inst = Instantiate(theMiniBoss, new Vector3(xPos, 2, zPos), Quaternion.identity);
        if (inst.TryGetComponent(out Target targ)) targ.spawner = this;
    }

}

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?

1 Like
  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.

Code like this will break your neck:

    for (sc = 0, stimer = 1; diffCount <= 1 && sc <= 2; sc++, stimer++)
    {
    }
    for (sc = 0, stimer = 1; diffCount <= 3 && sc <= 5 && diffCount > 1; sc++, stimer++)
    {
    }
    for (sc = 0, stimer = 1; diffCount <= 6 && sc <= 5 && diffCount > 3; sc++, stimer++)
    {
    }
    for (sc = 0, stimer = 1; diffCount <= 9 && sc <= 7 && diffCount > 6; sc++, stimer++)
    {
    }

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.

    if (diffCount <= 1)
    {
        for (var sc = 0; sc <= 2; sc++)
        {
        }
    }
    else if (diffCount <= 3)
    {
        for (var sc = 0; sc <= 5; sc++)
        {
        }
    }
    else if (diffCount <= 6)
    {
        for (var sc = 0; sc <= 5; sc++)
        {
        }
    }
    else if (diffCount <= 9)
    {
        for (var sc = 0; sc <= 7; sc++)
        {
        }
    }
3 Likes

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:

void SpawnEnemies()
{
    if (levelTut != true)
    {
        if (gameStart == true)
        {
            if (diffCount <= 1)
            {
                InvokeQueue(GenerateEnemy, count: 3, delay: 1.5f);
            }
            else if (diffCount > 1 && diffCount <= 3)
            {
                InvokeQueue(GenerateEnemy, count: 2, delay: 1.2f);
            }
            else if (diffCount > 3 && diffCount <= 6)
            {
                float endTime = InvokeQueue(GenerateEnemy,  count: 3, delay: 0.9f);
                endTime =       InvokeQueue(GenerateTank,   count: 3, delay: 1.5f, delayOffset: endTime);
            }
            else if (diffCount > 6 && diffCount <= 9)
            {
                float endTime = InvokeQueue(GenerateEnemy,      count: 3, delay: 0.9f);
                endTime =       InvokeQueue(GenerateTank,       count: 3, delay: 0.9f, delayOffset: endTime);
                endTime =       InvokeQueue(GenerateMiniBoss,   count: 2, delay: 0.9f, delayOffset: endTime);
            }

            loopRun = true;
            diffCount++;
            if (diffCount == 10)
                gameStart = false;
        }
    }
    else
    {
        if (diffCount <= 9)
        {
            float endTime = InvokeQueue(GenerateEnemy,  count: 3, delay: 0.9f);
            endTime = InvokeQueue(GenerateTank,         count: 3, delay: 0.9f, delayOffset: endTime);
            endTime = InvokeQueue(GenerateMiniBoss,     count: 2, delay: 0.9f, delayOffset: endTime);
        }
    }
}

private float InvokeQueue(Action action, int count, float delay, float delayOffset = 0)
{
    for (int i = 1; i <= count; i++)
    {
        Invoke(action.Method.Name, delayOffset + (delay * i));
        enemiesSpawned++;
    }

    return delayOffset + (delay * count);
}
1 Like

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} … ].

1 Like

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.