Scripts Require Reassigning For Them To Work After Reopening Unity

Whenever I reopen unity, some of my spawner object scripts stop working.
I’ve been following unity’s scripting tutorials, and decided to go blindfolded to try doing solutions in a different way and it got messy:

  • I have a “Spawn Manager” gameobject that handles all spawn related jobs:

  • I made a file “SpawnManager.cs” that has abstract class that inherits MonoBehaviour (this file isn’t attached to a gameobject. Rather referranced in another script):
public abstract class SpawnManager : MonoBehaviour
{
    public GameObject objectToSpawn;
    public float spawnRadius = 7.0f;
    public float spawnHeight = 0.1f;
    public bool JustSpawned { get; private set; } = false;

    protected void SpawnJob()
    {
        JustSpawned = false;
        if (IsSpawnable())
        {
            int spawnAmount = GetSpawnCount();
            for (int i = 0; i < spawnAmount; i++)
            {
                Vector3 spawnPos = GenerateSpawnPosition();
                Instantiate(objectToSpawn, spawnPos, objectToSpawn.transform.rotation);
            }
            JustSpawned = true;
        }
    }
    private Vector3 GenerateSpawnPosition()
    {
        return Quaternion.AngleAxis(UnityEngine.Random.Range(0.0f, 360.0f), Vector3.up) * Vector3.forward * spawnRadius + Vector3.up * spawnHeight;
    }
    public int GetCurrentAmount()
    {
        return GameObject.FindGameObjectsWithTag(objectToSpawn.tag).Length;
    }
    public static GameObject[] GetAllEnemyKindObjects()
    {
        GameObject[] enemies = GameObject.FindGameObjectsWithTag("Enemy");
        enemies = enemies.Concat(GameObject.FindGameObjectsWithTag("Enemia")).ToArray<GameObject>();
        return enemies;
    }
    public static GameObject[] GetAllAbilityUpKindObjects()
    {
        GameObject[] powers = GameObject.FindGameObjectsWithTag("PowerUp");
        powers = powers.Concat(GameObject.FindGameObjectsWithTag("HomingUp")).ToArray<GameObject>();
        return powers;
    }
    abstract public bool IsSpawnable();
    abstract public int GetSpawnCount();

}
  • Then I made 2 enemy (enemy, enemia) spawn manager files and 2 ability (homingup, powerup) spawn manager files. Classes inherit “SpawnManager”. Here are two of them:
    • EnemySpawnManager:
public class EnemySpawnManager : SpawnManager
{
    public int difficulty = 0;

    void Update()
    {
        SpawnJob();

        if (JustSpawned)
        {
            difficulty++;
        }
    }
    
    public override bool IsSpawnable()
    {
        return (GetCurrentAmount() <= 0);
    }
    public override int GetSpawnCount()
    {
        int falloffNumber = 3;
        return (difficulty>falloffNumber?falloffNumber+Convert.ToInt32(Mathf.Sqrt(difficulty)):difficulty) + 1;
    }
}
    • PowerUpSpawnManager:
public class PowerUpSpawnManager : SpawnManager
{
    EnemySpawnManager enemySpawnManager;
    // Start is called before the first frame update
    void Start()
    {
        enemySpawnManager = GetComponent<EnemySpawnManager>();
    }

    // Update is called once per frame
    void Update()
    {
        SpawnJob();
    }
    public override bool IsSpawnable()
    {
        return enemySpawnManager.IsSpawnable();
    }
    public override int GetSpawnCount()
    {
        return enemySpawnManager.difficulty / 8 + 1 - GameObject.FindGameObjectsWithTag("PowerUp").Length; // every 8 difficulty, given powerup amount increases
    }
}

This setup initially worked. But when I reopen project, it breaks and just spawns regular enemies. In all the other spawn manager files, “EnemySpawnManager” component is being used (like in the powerup example above). When I do “remove component” and add the script again , let’s say PowerUpSpawnManager, and reassign the prefab on the public variable, powerups start to spawn the way I intented.

I am guessing this problem is Inheritence related, but I couldn’t find any related posts (that’s probably my bad). Maybe I’ve used inheritence in a way that unity couldn’t register every time it opens? Or maybe inheritence isn’t meant to be used like this at all in unity? But then why enemy spawning has no issues?

Extra note; there are no errors or warnings. Everything compiles and runs without an error showing up in unity or visual studio. Also please don’t mention better methods of achieveing the same thing. I know this isn’t the best way of doing it, but the reason I opened this discussion is to figure out why this method doesn’t work, so focusing on that would be much appreciated.

Thank you for your patience and help.

I figured it out, if someone’s curious; appearently it was about component script execution order.
What I was expecting the order of execution to be was;

  1. Last enemy is destroyed.
  2. Check enemy amount in PowerUpSpawnManager, and spawn since enemy amount is zero.
  3. Check enemy amount in EnemySpawnManager, and spawn since enemy amount is zero.
  4. Enemy amount is no longer zero.

What it really was;

  1. Last enemy is destroyed
  2. Check enemy amount in EnemySpawnManager, and spawn since enemy amount is zero.
  3. Enemy amount is no longer zero.
  4. Check enemy amount in PowerUpSpawnManager, it won’t spawn since enemy amount is no longer zero.

Conclusion: When writing a script, we should accept that the order of update functions is unknown. One update function should not be expected to be called before or after another.

Added note: even though it’s probably a bad practice, in some cases you might find it useful that you can change the order that your scripts will execute. In “Edit > Project Settings > Script Execution Order” you can click ‘+’ button and add your scripts in so you can order them.