How do I call a method in another game objects script without creating another instance of it.

I have checked to see if I am asking a duplicate question. While I may have found one question that seems the same as mine, it doesn’t actually answer my version of it. (ref: How do I call a method from another script without creating another instance of it? - Questions & Answers - Unity Discussions )

So I have an object that has a generic wave spawner script on it. and each enemy that gets spawned has its own behaviour script attached to it. I want to calculate the enemies health, based on the wave_number variable in the EnemySpawner.cs

EnemySpawner.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemySpawner : MonoBehaviour
{
    public enum SpawnState { SPAWNING, WAITING, COUNTING};

    public Transform enemy;

    public int count;
    public float rate;

    private int wave_number;

    public float time_between_waves;
    private float wave_countdown;

    private float search_countdown;

    public SpawnState state;

    void Start()
    {
        wave_number = 0;
        wave_countdown = time_between_waves;
        search_countdown = 1.0f;
        state = SpawnState.COUNTING;
    }

    void Update()
    {
        if (state == SpawnState.WAITING)
        {
            if (AllEnemiesAreDead())
            {
                WaveCompleted();
            }
        }
        // Everything else within this scope is not important
    }

    void WaveCompleted()
    {
        wave_number++;
        Debug.Log("wave number: " + (wave_number));
        state = SpawnState.COUNTING;
        wave_countdown = time_between_waves;
    }

    bool AllEnemiesAreDead()
    {
         // Not important
    }

    private IEnumerator SpawnWave()
    {
        // Not important
    }

    private void SpawnEnemy()
    {
        Instantiate(enemy, transform.position, transform.rotation);
    }

    public int GetSpawnedEnemyHealth()
    {
        return (100 * (wave_number + 1));
    }
}

Now below is the script attached to each of the enemies. when they are spawned, the Start() method tries to call GetSpawnedEnemyHealth() from the EnemySpawner script. But I am always getting 100. I am fairly confident that this is because I am creating an instance of the Spawner script in each of the enemy behaviour scripts.

EnemyBehaviour.cs

public class EnemyBehaviour : MonoBehaviour
{

    public int health;
    public GameObject enemy_spawner_script;

    void Start()
    {
        health = enemy_spawner_script.GetComponent<EnemySpawner>().GetSpawnedEnemyHealth();

I wanted to post this on here to see if anyone can either tell me I’m wrong and that its not working for a different reason, or how I can call a method from another script without making a new instance of it. (i feel like the answer has something to do with being static, but that’s all I got so far). Thanks in advance

I expect the issue here is you are accessing the prefab enemy_spawner_script rather than the instance of it in scene.

If you click on the reference of enemy_spawner_script in the inspector, does it highlight an object in the scene or in the project? If it’s in the project then I think this is the problem.

If so, you can solve this in one of two ways:

  1. Initialise the enemy with its health:

    (in EnemySpawner)
    private void SpawnEnemy()
    {
    var enemyObj = Instantiate(enemy, transform.position, transform.rotation);
    var enemyInstance = enemyObj.GetComponent();

    enemyInstance.health = GetSpawnedEnemyHealth();
    

    }

or 2. If you’ll only ever have 1 EnemySpawner at any time, make it a singleton:

public static EnemySpawner Instance;

void Start()
{
    if (Instance)
    {
        throw new Exception("There is already an enemy spawner in scene!");
    }
    Instance = this;
    
    wave_number = 0;
    wave_countdown = time_between_waves;
    search_countdown = 1.0f;
    state = SpawnState.COUNTING;
}

Then instead of:

health = enemy_spawner_script.GetComponent<EnemySpawner>().GetSpawnedEnemyHealth();

write:

health = EnemySpawner.Instance.GetSpawnedEnemyHealth();

Let me know if this wasn’t the issue or any of this requires clarification!

So for anyone else that is interested in this. the answer given here is great. I am going to use the singleton method for this because if I end up spawning 100’s of enemies at a time. then storing and changing values of each enemy object will use more memory and could slow the game down.

I have a generic singleton script that could be used for many other scenarios when needing a singleton class.

using UnityEngine;

public abstract class Singleton<T> : MonoBehaviour where T : Singleton<T>
{
    private static T _instance;
    public static T Instance
    {
        get
        {
            if (_instance == null)
            {
               Debug.LogError(typeof(T).ToString() + " is null");
            }

            return _instance;
        }
    }

    private void Awake()
    {
        if (_instance == null)
        {
            _instance = (T)this;
            _instance.Init();
        }
        else if (_instance != this)
        {
            Debug.LogError(typeof(T).ToString() + " already exists. Destroying self...");
            DestroyImmediate(this);
        }
    }

    protected abstract void Init();
}

Now you can add:

public class EnemySpawner : Singleton <EnemySpawner>

to your class that you want to become a singleton.
Now you can use that class in another script like so:

health = EnemySpawner.Instance.GetSpawnedEnemyHealth();

Thank you for your answer jackmw94. this has helped a lot.