GameObject.SetActive() not working

Hi!
I’d like to activate an end screen once the player touches the goal pad. I use an OnCollisionEnter2D on my player to detect it, and then call a function on my UI container, as seen below

    public void Finish()
    {
        Debug.Log("finished!");
        finishMenu.SetActive(true);
        GameIsFinished = true;
        Time.timeScale = 0f;
    }

However, my finishMenu isn’t activating. I’m getting the log in the console, and timeScale is 0. The same finishMenu does activate when I try other ways of activating it (Input.GetKeyDown). Why doesn’t it activate?

EDIT:
After some debugging, I noticed that after finishMenu.SetActive(true), finishMenu.activeSelf is true, but it is not activeInHierarchy. This info does not show up in the inspector, only when debugging with breakpoints. In the inspector, it seems like it isn’t activeSelf or activeInHierarchy. The parent GameObject of finishMenu, is active, so I don’t know why finishMenu is activeSelf, but not activeInHierachy.

Debug:
8938305--1227618--Screenshot 2023-04-12 153051.png
Hierarchy:
8938305--1227621--Screenshot 2023-04-12 153333.png
When using Input.GetKeyDown:
8938305--1227006--Screenshot 2023-04-12 160504.png

We know the Unity Physics2D system works, so go read the docs and make sure you are spelling it properly and meeting 100% of the requirements.

If that doesn’t do it, then time to start debugging! Here is how you can begin your exciting new debugging adventures:

You must find a way to get the information you need in order to reason about what the problem is.

Once you understand what the problem is, you may begin to reason about a solution to the problem.

What is often happening in these cases is one of the following:

  • the code you think is executing is not actually executing at all
  • the code is executing far EARLIER or LATER than you think
  • the code is executing far LESS OFTEN than you think
  • the code is executing far MORE OFTEN than you think
  • the code is executing on another GameObject than you think it is
  • you’re getting an error or warning and you haven’t noticed it in the console window

To help gain more insight into your problem, I recommend liberally sprinkling Debug.Log() statements through your code to display information in realtime.

Doing this should help you answer these types of questions:

  • is this code even running? which parts are running? how often does it run? what order does it run in?
  • what are the names of the GameObjects or Components involved?
  • what are the values of the variables involved? Are they initialized? Are the values reasonable?
  • are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

Knowing this information will help you reason about the behavior you are seeing.

You can also supply a second argument to Debug.Log() and when you click the message, it will highlight the object in scene, such as Debug.Log("Problem!",this);

If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

You could also just display various important quantities in UI Text elements to watch them change as you play the game.

Visit Google for how to see console output from builds. If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer or iOS: How To - Capturing Device Logs on iOS or this answer for Android: How To - Capturing Device Logs on Android

If you are working in VR, it might be useful to make your on onscreen log output, or integrate one from the asset store, so you can see what is happening as you operate your software.

Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

Here’s an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

“When in doubt, print it out!™” - Kurt Dekker (and many others)

Note: the print() function is an alias for Debug.Log() provided by the MonoBehaviour class.

It’s unlikely a simple API like this isn’t working. It’s much more likely some other code is deactivating the menu again right after this code activates it. Different methods get called at different points in the update loop, in this case the physics collision could be called before the other code deactivates the menu, while the Input.GetKeyDown (presumably in an Update) could be called after it.

The way I usually debug these issues is to put a script on the game object being de-/activated, with a log message in both OnEnable/OnDisable. Since those happen during the SetActive call, you can see when objects are de-/activated multiple times in the same frame and the stack trace of the log message will tell you which parts of your code are responsible.

1 Like

Doesn’t time scale zero stop the execution of scripts?
It won’t be until the next frame the thing that sets active is visible. But if time stopped. Maybe the next frame never happens. Try remove timescale 0 and see does it set active?

This is a stab in the dark I did not test this code yet. But if you can test it before I do and confirm timescale is not preventing the active then you might be able to fix the problem.

The reason I jump to this conclusion is messing with timescale in an options menu means your frame rate can tank to 30 or less than 10 which makes hitting clicks difficult

No. Setting timeScale to 0 will only stop FixedUpdate from being called. Everything else continues as usual, it’s up to the user code to take account of timeScale or multiply with deltaTime to actually slow down / pause the game.

With one teeny-tiny exception that bit me once long ago:

// will NOT return when Time.timeScale is zero (eg, it will hold indefinitely):
yield return new WaitForSeconds(0);

// WILL return after each frame, even when Time.timeScale is zero:
yield return null;

Oh my mistake sorry