-6

I have a C# script attached to an empty object called GameManager. The script is GameManager.cs. Here are the first few lines:

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

public class GameManager : MonoBehaviour {
    public GameObject tilePrefab;
    public GameObject startTile;
    public GameObject lastTile;

I have another script attached to a camera called CameraManager.cs. I'm attempting to reference lastTile from GameManager but it's always null. Here is the full code for CameraManager.cs:

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

public class CameraManager : MonoBehaviour
{
    // Start is called before the first frame update
    private Vector3 currPos;
    private Vector3 newPos;
    public float CamMoveSpeed = 5f;
    GameManager gameManager;

    private void Awake() {
        gameManager = gameObject.AddComponent<GameManager>();
    }
    private void Start() {
    }

    private void Update() {
        if (gameManager.lastTile != null) {
            currPos = gameObject.transform.position;
            Vector3 tilePos = gameManager.lastTile.transform.position;
            newPos = new Vector3(currPos.x + tilePos.x, currPos.y + tilePos.y, currPos.z + tilePos.z);
            this.transform.position = Vector3.Lerp(currPos, newPos, CamMoveSpeed * Time.deltaTime);
            Debug.Log("Moving Camera...");
        } else {
            Debug.LogWarning("gameManager.lastTile is NULL");
        }
    }
}

This latest iteration is based on this SO question. The previous iteration was based on this SO question.

What is the proper way to reference a value from another script/class?

  • 1
    Are you assigning them in the inspector?? – BugFinder Feb 18 '23 at 23:40
  • `gameManager = gameObject.AddComponent();` would add a new instance of `GameManager` to the same object this `CameraManager` is attached to .. it will have all its fields uninitialized .. that is of course clearly not what you want to do .. you rather want to reference the already existing instance – derHugo Feb 19 '23 at 19:21

3 Answers3

1

All I had to do was make the property public and then assign it in the inspector by dragging the GameManager object to the corresponding field. I was able to remove everything in the awake routine.

enter image description here

0

In the awake method of your camera class you assign gameManager with AddComponent, that will create a new instance of the GameManager script on the same object that your camera manager class is on, meaning that the reference that your camera manager class has to the GameManager class is not the one that’s on your GameManager gameObject.

What people do usually with GameManager classes is to use a Signlton structure

Basically you can have a static field of type GameManager in your GameManager class and assign it to its own instance on the Awake method of your GameManager class. Something like this

public class GameManager : MonoBehaviour {
    public GameObject tilePrefab = new GameObject("Name");
    public GameObject startTile = new GameObject("Name");
    public GameObject lastTile = new GameObject("Name");

    public static GameManager Instance;

    private void Awake(){
        Instance = this;
    }
}

And then you can use your game manager in any other class with this line GameManager.Instance.lastTitle

James Risner
  • 5,451
  • 11
  • 25
  • 47
ZikosFF
  • 44
  • 4
  • It would be pretty useless to assign three new `GameObject` to your fields .. (besides the fact that Unity doesn't allow to instantiate objects during field initialization time) .. you rather want to reference already existing objects. Also **don't** just make things static ... It's lazy and causes way more issues than it solves! Use proper reference management – derHugo Feb 19 '23 at 19:01
  • The three gameObjects were his example, I was just editing their class. And a singleton structure is a very common way for manager classes in Unity. Yes you usually want to handle it properly so that it does not override any instances and ensures there is only 1 instance assigned to this static field but this was just a quick example of how you can set one – ZikosFF Feb 19 '23 at 19:09
  • There are [many reasons](https://stackoverflow.com/questions/137975/what-are-drawbacks-or-disadvantages-of-singleton-pattern) why Singleton patterns should be used as little to never as possible! And yes the three GameObjects was OPs example .. but as said it makes zero sense to use `new GameObject` in order to assign them .. this creates new empty objects in the scene .. what would be the use of those? You of course want to use objects that already exist and reference them via the Inspector – derHugo Feb 19 '23 at 19:16
  • This person is clearly fairly new to unity and probably has a small/personal project here. I agree on big projects you should probably not be using singletons but for solo/small projects are perfectly viable and very useful. Sure you can go ahead and try to explain to this person how to do Dependency injection instead, but they probably don't need it. You don’t have to be so pedantic :) – ZikosFF Feb 19 '23 at 19:46
  • Well if all you really need to do is exposing a `public` or `[SerializeField] private GameManager gameManager;` and drag according object into the now exposed field in the Inspector this would be very much preferred over anything `static` especially in Unity .. this basically already is a kind of dependency injection/management without the need to mention that phrase ;) – derHugo Feb 19 '23 at 19:48
-3
public class GameManager : MonoBehaviour {
    public GameObject tilePrefab;
    public GameObject startTile;
    public GameObject lastTile;
}

It doesnt look like your ever assigning these variables to anything, therefore they will always be null.

For them not to be null you need to assign them to something e.g.

public class GameManager : MonoBehaviour {
    public GameObject tilePrefab = new GameObject("Name");
    public GameObject startTile = new GameObject("Name");
    public GameObject lastTile = new GameObject("Name");
}

Or you can set them dynamically by doing

private void Update() {
    gameManager.lastTile = new GameObject("Name");
}
JDChris100
  • 146
  • 9
  • It would be pretty useless to create new empty `GameObject`s .. especially spamming your scene by doing so in `Update` every frame ... you rather want to reference already existing ones ... – derHugo Feb 19 '23 at 19:03
  • Then create a singleton instance or something, all im saying is its obviously going to be null if you never asign it to anything – JDChris100 Feb 19 '23 at 19:20
  • Well yes that's quite obvious ;) and no .. Singleton shouldn't be used for this but proper reference management – derHugo Feb 19 '23 at 19:21
  • Like i said or something else. I havent messed around much with unity but in C# if u dont assign something its gonna be null, hence why he needs to assign it to something. Thats all my reply said – JDChris100 Feb 19 '23 at 19:28
  • Yes .. and I said that is pretty obvious.. that is what `null` is telling us .. the question is most probably rather **why** and how to solve that issue .. properly :) – derHugo Feb 19 '23 at 19:30