1
votes

I am building a clone of Doodle Jump in Unity to teach myself the basics and have come across a problem. The flow of this game goes:

Main menu ---(click start)--> Level select ---(click level)--> Selected level

The player controlled object is actually created in the main menu screen. It is controllable right from the very beginning with GameObject.DontDestroyOnLoad() stopping it from being destroyed throughout each scene transition. Once you get into your selected level, there is a script attached to the camera to get it to move with your character.

I have some code in the LateUpdate method which handles the camera movement:

void LateUpdate () {

    if (gameObject.transform.position.y > transform.position.y) {

        Vector3 newPosition = new Vector3(transform.position.x, gameObject.transform.position.y, transform.position.z);
        transform.position = Vector3.SmoothDamp(transform.position, newPosition, ref currentVelocity, smoothSpeed * Time.deltaTime);

    }

}

but for this to work correctly, I need to be able to reference the the player (gameObject in the code above). I was originally doing this by using

GameObject gameObject = GameObject.Find("Doodler");

in the same LateUpdate method, but there is no reason for me to find the Doodler every frame as it should not be replaced until you hit game over. For this reason, I moved the GameObject.Find line into the Start method, but it doesn't seem to be finding the Doodler and as a result, the camera doesn't move. Can anybody help with this?

EDIT:

I've now changed my Start method to be like this:

private GameObject gameObject;

void Start() {
    gameObject = GameObject.Find("Doodler");
    Debug.Log("START Found the Doodler: " + gameObject.GetInstanceID());
}

rather than this:

void Start() {
    GameObject gameObject = GameObject.Find("Doodler");
    Debug.Log("START Found the Doodler: " + gameObject.GetInstanceID());
}

and this seems to be working. I'm guessing the second method means gameObject is not accessible to LateUpdate?

Final Solution:

Whilst the code in the edit does work, it gives a warning because I called my GameObject gameObject and this is a predefined object referring to the object the script is attached to. The final code should look like this:

private GameObject doodler;

void Start() {
    doodler = GameObject.Find("Doodler");
    Debug.Log("START Found the Doodler: " + doodler.GetInstanceID());
}
2
"but it doesn't seem to be finding the Doodler and as a result" If the Doodler object is not active, GameObject.Find can't find it. If it is not in the scene yet, GameObject.Find can't find it too. Which one is it?Programmer
It was being found in the LateUpdate method, but not the Start method, so I was looking to find out when DontDestroyOnLoad objects are available in the new scene. However, it looks like I've fixed it as per my edit above.H4ZD4M4N
I decided to leave an answer after you updated your question with your current and old code. Please read.Programmer

2 Answers

4
votes

After the edit in your question and the fix you found, I still think it's worth leaving an answer to this problem because of your current code.

Obviously, you need to make a variable global before you can access it in another function. You fixed that but there is a big problem you don't know about yet and there is a reason you never got error while you were trying to access variable declared in a local function from another function. You should have received an error with your original code but you didn't.

You are currently doing this:

private GameObject gameObject;

void Start() 
{
    gameObject = GameObject.Find("Doodler");
}

then using it in the LateUpdate function:

void LateUpdate () 
{
    if (gameObject.transform.position.y > transform.position.y) {...}
}

Problem:

Your script derives from MonoBehaviour which derives from Behaviour which then derives from Component.

Inside that Component script, there is a variable named "gameObject" which is a type of GameObject. It is declared like this:

public GameObject gameObject { get; }

Since your script derives from MonoBehaviour, that gameObject variable is already declared and available to you. It refers to theGameObjectthat this script is attached to..

In fact, right now, you should be getting a warning that looks similar like this:

Severity Code Description Project File Line Suppression State Warning CS0108 'YourScript.gameObject' hides inherited member 'Component.gameObject'. Use the new keyword if hiding was intended.

What to do:

You could of-course use the new keyword to hide it and remove that warning:

private new GameObject gameObject;

Do not do that. Don't name your variable "gameObject" or any name that is already being used from the the MonoBehaviour class. You will run into many issues with this code. I've seen several questions that was caused by this and it was hard to discover that this was the issue. Something like below should be fine:

private GameObject doodler;

void Start()
{
    doodler = GameObject.Find("Doodler");
}
0
votes

One (of many) ways to handle this is to use SceneManager.sceneLoaded callback (https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager-sceneLoaded.html). In that you can do your Find operation after a new scene loads.

But if this script you reference above is on the "Doodler" gameObject already and you're getting null ref errors, then there may be another issue. The "gameObject" member in a MonoBehaviour class should always be the gameObject that the component (MonoBehaviour derived class) is attached to. If that's gone null, then you're forcing it to be destroyed somehow, but the Monobehaviour is staying alive which is weird.