0
\$\begingroup\$

I have a UIManager meant to control the UI. The UI manager is attached to an empty game object.

The Canvas has three panels, each with a button. All the panels are initially set to inactive in the inspector.

When I run the program, the WelcomePanel displays. When I click the button on WelcomePanel, it closes the panel and sets the GenerateTerrainPanel to active as intended.

When I click the button on the GenerateTerrainPanel, it generates the terrain - so I know the call to the other class is working (this method takes 4-5 minutes to execute), and it closes the panel and then sets the BuildTownCenterPanel to active as intended.

But the button on that panel (BuildTownCenterPanel) will not execute the code attached to it.

I'm a noob, and way out of my league and trying to learn as I build my project. I thought I was understanding delegates/actions, and I do understand them enough to make the call across classes happen, but I cannot figure why this button doesn't seem to register the method passed in the onClick.AddListener() for the life of me. Any help is greatly appreciated.

Yes - buildTownCenterBtn is set to Interactable in the Inspector.

using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;


public class UIManager : MonoBehaviour
{
    // KEEP YOUR METHODS SIMPLE!

    // Create Actions
    Action onGenerateTerrain;
    

    [SerializeField]
    private GameObject generateTerrainPanel, welcomePanel, buildTownCenterPanel;
    [SerializeField]
    private Button welcomeGetStartedBtn, buildTownCenterBtn, generateTerrainBtn;

   
    // Start is called before the first frame update
    void Start()
    {
        // Add all our button listeners.
        welcomeGetStartedBtn.onClick.AddListener(onWelcomeGetStartedCallBack);
        generateTerrainBtn.onClick.AddListener(onGenerateTerrainCallBack);
        buildTownCenterBtn.onClick.AddListener(onBuildTownCenterCallBack);
                
        ShowWelcomePanel();
                        
    }

    // Update is called once per frame
    void Update()
    {
        
        
    }

    // Define button callbacks.
    private void onWelcomeGetStartedCallBack()
    {
        HideWelcomePanel();
        ShowTerrainGeneratorPanel();
    }
    private void onGenerateTerrainCallBack()
    {
        // Call the GenerateNewTerrain() in TerrainGenerator.cs.
        onGenerateTerrain?.Invoke();
        // Call the method to show the next panel.        
        ShowBuildTownCenterPanel();
                
    }

    private void onBuildTownCenterCallBack()
    {
        Debug.Log("This button works! You made it to onBuildTownCenterCallBack()!");
    }

    
    // This method allows GameManager.cs to assign the GenerateNewTerrain() in TerrainGenerator.cs to the onGenerateTerrain action.
    public void AddListenerOnGenerateTerrain(Action listener)
    {
        onGenerateTerrain += listener;
    }

    
    // Handle panels.
    private void ShowTerrainGeneratorPanel()
    {
        generateTerrainPanel.SetActive(true);
                        
    }

    private void HideTerrainGeneratorPanel()
    {
        // I think the ? either ensures it's not null, or checks to see if it's active.
        generateTerrainPanel?.SetActive(false);
    }

    private void ShowWelcomePanel()
    {
        welcomePanel.SetActive(true);
        
    }

    private void HideWelcomePanel()
    {
        welcomePanel.SetActive(false);
    }

    private void ShowBuildTownCenterPanel()
    {
        generateTerrainPanel?.SetActive(false);
        buildTownCenterPanel.SetActive(true);
                
    }

    

}
\$\endgroup\$
2
  • \$\begingroup\$ Where is buildTownCenterBtn assigned? Do you see any output including warnings or errors in your debug console when compiling and running this script? \$\endgroup\$
    – DMGregory
    Commented Jul 18, 2023 at 11:49
  • \$\begingroup\$ @DMGregory buildTownCenterBtn is assigned in the inspector. That's why I used [SerializedField] in my declaration. There is no warnings or errors in Visual Studio or in the Inspector. I'll try to get a video up on my channel and link to it so you can see the what's happening. \$\endgroup\$ Commented Jul 18, 2023 at 13:30

1 Answer 1

1
\$\begingroup\$

I found it. When I call the method GenerateNewTerrain(), is start by destroying all the game objects in the world unless they have a certain tag.

public void DestroyAllGameObjects()
    {
        GameObject[] GameObjects = (FindObjectsOfType<GameObject>() as GameObject[]);

        for (int i = 0; i < GameObjects.Length; i++)
        {
            if (!GameObjects[i].CompareTag("MainCamera") && !GameObjects[i].CompareTag("Light") && !GameObjects[i].CompareTag("EmptyObject") && !GameObjects[i].CompareTag("Terrain") && !GameObjects[i].CompareTag("UI"))
            {
                //Debug.Log("This ain't the camera.");
                Destroy(GameObjects[i]);
            }
            
        }
    }

When I had created my UIController as an empty game object, I never gave it a tag. Therefore, my GenerateNewTerrain() method was destroying the game object and the UIManager.cs that was attached to it, so the button had no script to control its behavior.

enter image description here

I discovered it this morning as I sat down to make a video to help you all understand.

This simple mistake has driven me mad for 3 or 4 days.

Thanks for taking a look, and for your willingness to help. Crisis averted for now.

Respectfully, Tim

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .