Unity c#: Code-structure or how to access a method/variable from another class/script?

524 Views Asked by At

I have two classes: Menu_Buttons, in which there are definitions for methods executed on clicking different buttons in the menu, and PauseMenu, which defines what happens when the Menu key is pressed during the game.

Menu_Buttons:

public class Menu_Buttons : MonoBehaviour
{
    public void Menu_NewGameClick()
    {
        SceneManager.LoadScene(1);
    }
    
    public void Menu_ContinueClick()
    {
        Debug.Log("This will continue the game from the last save");
    }

    public void Menu_LoadGameClick()
    {
        SceneManager.LoadScene(1);
        Debug.Log("Another menu will show to choose which save to load");
    }

    public void Menu_SaveGameClick()
    {
        SaveItem();
        Debug.Log("This will save the game");
    }

    public void Menu_OptionsClick()
    {
        Debug.Log("This will show the game options");
    }

    public void Menu_QuitClick()
    {
        Application.Quit();
        Debug.Log("The Game should quit now");
    }
}

PauseMenu:

public class PauseMenu : MonoBehaviour
{
    //private bool isPauseMenuOpened = false;
    public GameObject pauseMenu;
    

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.B))
        {
            if (pauseMenu.activeSelf)   { ClosePauseMenu(); }
            else                        { OpenPauseMenu(); }
        }
    }

    public void OpenPauseMenu()
    {
        pauseMenu.SetActive(true);
        Cursor.visible = true;
        Cursor.lockState = CursorLockMode.Confined;
        //isPauseMenuOpened = true;
        Time.timeScale = 0f;
    }

    public void ClosePauseMenu()
    {
        pauseMenu.SetActive(false);
        Cursor.visible = false;
        Cursor.lockState = CursorLockMode.Locked;
        //isPauseMenuOpened = false;
        Time.timeScale = 1f;
    }
}

I wanted to add another method called Menu_ResumeClick, which would resume the game from the Pause Menu. Of course, I could just create this method in the PauseMenu script and then everything is fine. It looks like this:

public void Menu_ResumeClick()
    {
        ClosePauseMenu();
    }

But since I would like to keep things organised, I thought it would be better to put this method in the Menu_Buttons script along with all the other similar methods. So I tried this:

public void Menu_ResumeClick()
    {
        PauseMenu.ClosePauseMenu();
    }

And then problems begin... I get an error: an object reference is required for the non-static field method or property. Then if I change any of those classes to static, I get errors saying: cannot declare instance members in a static class. Not to mention that static classes canot inherit from MonoBehaviour. Maybe I would be able to solve those problems somehow, but the thing is I don't want to change the whole code just because I would rather have a method in another class. It's just for keeping things organised, nothing more.

I have to admit that I'm a bit frustrated by how these things work. I can easily put the Menu_ResumeClick() method in the PauseMenu class, but in the future it may be difficult to keep track of things if I have various methods scattered around different scripts. The most reasonable solution is to put every menu button in the Menu_Buttons class and then access them from there, but it poses problems that I described. Actually this is not the first time when I'm having problems with accessing methods or variables from other classes - there always seem to be some difficulties. It seems the best way to write code would be to just have a single class for the whole game because then I would be able to access absolutely anything easily - but again the problem would be with keeping things organised.

So, the question is: can I easily use methods (or variables) from other classes, without changing the whole code for this purpose? In other words can I somehow just call a method from another class like this: className.MethodName(); or set a variable from another class like this: className.varName = 2; without making everything static, etc.? And a bonus question: If it's not possible, then how should I structure my code? Should I try to squeeze as many things as possible into a single class to be able to access them easily, should I make classes static, whenever it's possible, etc.?

1

There are 1 best solutions below

6
h4ri On

In PauseMenu, you can add a field for the Menu_Buttons, which Unity can serialize, so you can pull the GameObject (what contains the Menu_Buttons) in the inspector, and you can call its public methods (and access its public members) from PauseMenu.

public Menu_Buttons MenuButtons;

// or (I much more like this version, keeping things as encapsulated as possible)
[SerializeField] private Menu_Buttons _menuButtons;

private void Resume() => _menuButtons.Menu_ResumeClick();

Edit based on comments:

Both script can have references to each other. As both logically related, I wouldn't separate them, because with the references, we couple them anyway.

Example:

public class Menu_Buttons : MonoBehaviour
{
    [SerializeField] private PauseMenu _pauseMenu;

    public void Menu_ResumeClick() => _pauseMenu.ClosePauseMenu();

    // ...
}

public class PauseMenu : MonoBehaviour
{
    [SerializeField] private Menu_Buttons _menuButtons;

    // ...

    public void ClosePauseMenu()
    {
        // ...
    }
}