2

I'm currently developing a game in Unity and I ran into a small problem. I'm trying to access a variable that is located in another class because I need it in order to be able to spawn a gameobject ("clock") at random during a specified amount of time while an update method is running. However for some reason even if I change the variable to a static variable or create a new instance of the class in which the variable I'm trying to access is located. I keep on getting an error message stating:

NullReferenceException: Object reference not set to an instance of an object InteractControl.Update () (at Assets/Scripts/Scene 2 Scripts/InteractControl.cs:87)

This is part of the class that I'm trying to access showing how the variable in question ("public Transform[] spawnPoints") is declared:

    public class BallSpawnerControl : MonoBehaviour
    {
        public Transform[] spawnPoints = new Transform[] { };
        int randomSpawnPoint, Interact;
        int index = 1;
        public static bool spawnAllowed;
        public static int TimerOn = 1;
        ObjectPooler objectPooler;
        public static int LevelTrans = 1;
        public static bool HeartSpawn = false;
        private int Hearts = 1;

        // Use this for initialization
        public void Start()
        {
            objectPooler = ObjectPooler.Instance;
            spawnAllowed = true;
            InvokeRepeating("SpawnAInteract", 0f, 1f);
        }

This is part of the class that is trying to access the variable showing how the variable in question ("public Transform[] spawnPoints") is being accessed:

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

    public class InteractControl : MonoBehaviour, IPooledObject
    {
        private Rigidbody2D rb;
        GameObject target;
        Vector3 directionToTarget;
        public static int LevelStart = 0;
        Renderer m_Renderer;
        public static float moveSpeed = 5f;
        public static bool isSlowMotion = true;
        public static float timeLeft = 5f;
        ObjectPooler objectPooler = ObjectPooler.Instance;
        int randomSpawnPosition;
        float randomSpawnTime;
        int Spawn = 1;
        BallSpawnerControl Bc = new BallSpawnerControl();

     void Update()
        {
            if (target != null)
            {
                if (ScoreScript.scoreValue > 10) 
                {
                    timeLeft -= Time.deltaTime;

                    if (timeLeft > 0)
                    {
                        directionToTarget = (target.transform.position - transform.position).normalized;
                        rb.velocity = new Vector2(directionToTarget.x * moveSpeed,
                                                    directionToTarget.y * moveSpeed);

                        if (Spawn == 1)
                        {
                            randomSpawnTime = Random.Range(1, 5);
                            randomSpawnPosition = Random.Range(0, Bc.spawnPoints.Length);
                            Spawn++;
                        }

                        if (timeLeft > randomSpawnTime && Spawn <= 2)
                        {
                            objectPooler.SpawnFromPool("Clock", Bc.spawnPoints[randomSpawnPosition].position, Quaternion.identity);
                        }

                    }

                    if (timeLeft < 0)
                    {
                        GameObject[] gos = GameObject.FindGameObjectsWithTag("ColouredBall Highress");

                        foreach (GameObject go in gos)
                        {
                            go.SetActive(false);
                        }

                        BallSpawnerControl.HeartSpawn = true;
                    }
                }    
            }            
        }
    }

What normally should happen is that the clock will spawn randomly at position "Bc.spawnPoints[randomSpawnPosition].position" during the 5 first seconds that ScoreScript.scoreValue > 10 .

Maurice Bekambo
  • 325
  • 6
  • 21
  • Possible duplicate of [Calling a Variable from another Class](https://stackoverflow.com/questions/1392017/calling-a-variable-from-another-class) – Ahmed Ali Sep 12 '19 at 10:05
  • You can access it, it just `null`. You never initialize it `spawnPoints = new Transform[size];`. – Guy Sep 12 '19 at 10:05
  • Possible duplicate of [What is a NullReferenceException, and how do I fix it?](https://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – derHugo Sep 12 '19 at 12:58
  • In which line is the exception thrown .. the code you showed here has only 63 lines ...? Did you actually fill the `spawnPoints` array with elements? Btw `new Transform[] { };` is unnecessary here since this is a `MonoBehaviour` and your array public Unity will serialize it and initialize it by default. – derHugo Sep 12 '19 at 13:01
  • Possible duplicate of [How to access a variable from another script in another gameobject through GetComponent?](https://stackoverflow.com/questions/26551575/how-to-access-a-variable-from-another-script-in-another-gameobject-through-getco) – Draco18s no longer trusts SE Sep 12 '19 at 13:52
  • Is it possible that the `spawnPoints` referenced get destroyed on runtime or are prefabs? – derHugo Sep 12 '19 at 16:26
  • I found another way to solve the problem. I just created a public static bool in BallSpawnerControl the class I normally instantiate from and set it to true when I need to instantiate the object. It's not as accurate as instantiating from InteractControl since it is dependent on an invoke repeating but it works – Maurice Bekambo Sep 14 '19 at 09:38

1 Answers1

1

The problem is in this line of code.

BallSpawnerControl Bc = new BallSpawnerControl();

You create a new ballspawnercontrol in your class. However, since BallSpawnerControll is a MonoBehaviour, it will not instantiate correctly.

you should either attach the ballspawner control to a gameobject within Unity and then drag it into a field on your InteractControl. Or you can create it via script by using the AddComponent method.

However, if you create it via script then you would also have to manually declare the spawnPoints from script. I suspect that you want to assign the values from within the inspector.

I suggest making your Bc variable either serializable or public.

public BallSpawnerControl Bc;

OR

[SerializeField]
private BallSpawnerControl Bc;

Now you can assign the correct control from the scene into your script.

Immorality
  • 2,164
  • 2
  • 12
  • 24
  • I changed the code to reflect the comments made by @Markus , I also changed the if statement that encapsulates objectPooler.SpawnFromPool("Clock", Bc.spawnPoints.... since it didnt work when I just did == however now I get the error message: IndexOutOfRangeException: Index was outside the bounds for the line: objectPooler.SpawnFromPool("Clock", Bc.spawnPoints[randomSpawnPosition].position, Quaternion.identity); do you possibly know why? – Maurice Bekambo Sep 12 '19 at 10:30
  • I found another way to solve the problem. I just created a public static bool in BallSpawnerControl the class I normally instantiate from and set it to true when I need to instantiate the object. It's not as accurate as instantiating from InteractControl since it is dependent on an invoke repeating but it works – Maurice Bekambo Sep 14 '19 at 09:38