1
\$\begingroup\$

I need some sort of an if statement, which allows me to disable any input and increment score while I'm in the pause menu.

The problem is that I don't really understand this kind of pausing code, I'm "used to" the regular boolean one. So, I show all the code.

First script:

public enum GameState
{
    Gameplay,
    Paused
}

Second script:

public class GameStateManager
{
    private static GameStateManager _instance;

    public static GameStateManager Instance
    {
        get
        {
            if (_instance == null)
                _instance = new GameStateManager();

            return _instance;
        }
    }

    public GameState CurrentGameState { get; private set; }

    public delegate void GameStateChangeHandler(GameState newGameState);
    public event GameStateChangeHandler OnGameStateChanged;

    private GameStateManager()
    {

    }

    public void SetState (GameState newGameState)
    {
        if (newGameState == CurrentGameState)
            return;

        CurrentGameState = newGameState;
        OnGameStateChanged?.Invoke(newGameState);
    }
}

Third script:

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

public class PauseController : MonoBehaviour
{
    public void PauseGame()
    {
        GameState currentGameState = GameStateManager.Instance.CurrentGameState;
        GameState newGameState = currentGameState == GameState.Gameplay
            ? GameState.Paused
            : GameState.Gameplay;

        GameStateManager.Instance.SetState(newGameState);
    }
}

And as of last, here is what I've done in my character movement script:

void Start()
{
    GameStateManager.Instance.OnGameStateChanged += 
    OnGameStateChanged;
}

private void OnDestroy()
{
        GameStateManager.Instance.OnGameStateChanged -= OnGameStateChanged;
}

private void OnGameStateChanged (GameState newGameState)
{
    enabled = newGameState == GameState.Gameplay;
}

This is all the code. Where and how am I supposed to write the input and score increment "blocking"? I am so sorry for this being so long and I am grateful if you read all this! :)

EDIT: the missing states, which should be disabled. Score:

if (Input.GetMouseButtonDown(0))
{
    if (EventSystem.current.IsPointerOverGameObject())
        return;
    if (ShootOnClick.onGround == false) // this is for disabling input when the player is colliding with the ground
    {
        //functions
    }
    else
    {
        score++;
        scoreText.text = score.ToString();
        moneyText.text = money.ToString();
    }
}

Input:

void CheckInput()
{
    //if first input then ignore
    if (firstInput)
    {
        firstInput = false;
        return;
    }

    if (Input.GetMouseButtonDown(0))
    {
        ChangeDirection();
    }
}
\$\endgroup\$
6
  • 1
    \$\begingroup\$ You aren't showing the code where you actually increment the score (which is likely where you would put the block). Can you add that code, please? \$\endgroup\$
    – Evorlor
    Commented Dec 8, 2021 at 17:15
  • \$\begingroup\$ The code we likely need to see is the code for your two states, Gameplay and Paused, as this is likely where the code for what to do each in state is. \$\endgroup\$ Commented Dec 8, 2021 at 17:25
  • \$\begingroup\$ Yes, sorry for that! i edited the question, the missing states are at the very botton of the question. I really don't understand how this should work, I am not an expert, never even heard about GameState before. \$\endgroup\$
    – imbruceter
    Commented Dec 8, 2021 at 19:47
  • \$\begingroup\$ Hi, so you have two states defined in an enum "Gameplay" and "Paused" at the very top, are these used in your code anywhere? if so can you include that code, it might be in a if or switch statement somewhere something like if(state == GameplayState.Gameply) or a switch(state) etc. Since you are already using a statemachine it's probably best to keep the behaviour specific to each state, I can already see the code above for changing the state when PauseGame is called but it doesn't look like you've provided the code for what happens when you're in the Gameplay state for example. \$\endgroup\$ Commented Dec 8, 2021 at 19:56
  • \$\begingroup\$ It also looks like in the OnGameStateChanged event you are setting the state to always be in the Gameplay state. \$\endgroup\$ Commented Dec 8, 2021 at 19:58

2 Answers 2

1
\$\begingroup\$

The problem is that I don't really understand this kind of pausing code, I'm "used to" the regular boolean one.

You can grab your boolean using your GameState:

bool paused = GameStateManager.Instance.CurrentGameState == GameState.Paused;

Then with this, you can use a regular boolean:

if(GameStateManager.Instance.CurrentGameState == GameState.Paused)
{
    return;
}
if (Input.GetMouseButtonDown(0))
{
    if (EventSystem.current.IsPointerOverGameObject())
        return;
    if (ShootOnClick.onGround == false) // this is for disabling input when the player is colliding with the ground
    {
        //functions
    }
    else
    {
        score++;
        scoreText.text = score.ToString();
        moneyText.text = money.ToString();
    }
}

There are 100 different ways to architect this, but this solution should be relatively simple.

\$\endgroup\$
1
  • \$\begingroup\$ This actually worked, thank you! There is only one problem remaining, that if I press the pause button, it also "senses" as az input. So, the counter and even the movement gets disables while the game is paused, but when I click the pause button, the input is also responds. Tried to insert this: if (EventSystem.current.IsPointerOverGameObject()) return; into the PauseController script but it just completely disables the buttons interactibility. Do you know what to do in this situation? \$\endgroup\$
    – imbruceter
    Commented Dec 8, 2021 at 23:08
1
\$\begingroup\$

So because I can't see how your StateMachine is running, I've made up a simple example that hopefully demonstrates what the purpose of the Statemachine is in the first place.

In your scenario described (and in the enum) you have two possible states your GameManager can be in, one is in GamePlay, which I imagine processes input and updates the score.

The other is the Paused state which I imagine, sets the timeScale to 0 effectively pausing everything.

So you have already defined yourself how you want these two states to behave, you want GamePlay to work as it should and when you are paused you want the input to not even be checked.

In that case your code might look something like this, if you drag this onto a GameObject and press play you will the see debug logs when you press the right mouse button down, if you press P and toggle the state, you will see your input goes from being "noticed" to being completely disregarded, not even checked.

This seems to be the best way with what you already have to achieve your desired behaviour.

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

public class TestFSM : MonoBehaviour
{
    //Define our current state with an enum
    private GamePlayState CurrentState = GamePlayState.Gameplay;

    public void SetState(GamePlayState newState)
    {
        CurrentState = newState;
        Debug.Log("Switching to State" + newState.ToString());
    }


    private void Update()
    {
        //this is basically a fancier-ish if statement, we are checking what the CurrentState value is, if its Currently GamePlayState.Gameplay then we run the "DoGamePlay" method, if its pause we run the "DoPausedState" method.
        switch (CurrentState)
        {
            case GamePlayState.Gameplay:
                DoGamePlayState();
            break;
            case GamePlayState.Paused:
                DoPausedState();
            break;
        }

        //when P is pressed, if we are paused, unpause if we aren't paused then pause it.
        //not really nessacry you might have your own way of pausing already
        if (Input.GetKeyDown(KeyCode.P))
        {
            switch (CurrentState)
            {
                case GamePlayState.Gameplay:
                    SetState(GamePlayState.Paused);
                break;
                case GamePlayState.Paused:
                    SetState(GamePlayState.Gameplay);
                break;
            }
        }
    }

    private void DoGamePlayState()
    {
        Debug.Log("In Gameplay state");

        if (Input.GetMouseButtonDown(1))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            if (Physics.Raycast(ray, out RaycastHit hit, 1000f))
            {
                Debug.Log("Hit " + hit.transform.name);
            }

        }
    }
    private void DoPausedState()
    {
        //and in here we are doing literally nothing since you want nothing to happen while paused! notice the key check to toggle the state is outside statemachine states, as we want this to work in either state.
        Debug.Log("In Paused state");
    }

    public enum GamePlayState
    {
        Gameplay,
        Paused
    }
}

And in this way we can define behaviour per state, which seems to be how your current code is set up, I hope this helps you apply this to your own code base, feel free to ask any questions.

So lets take your code and try apply it to this simple state machine, what do we get? Bear in mind, I have no real idea how your games supposed to work im just making a guess based on your code :)

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

public class testFSM : MonoBehaviour
{
    //Define our current state with an enum
    public GamePlayState CurrentState = GamePlayState.Gameplay;
    public LayerMask RayCastLayerMask;
    public void SetState(GamePlayState newState)
    {
        CurrentState = newState;
        Debug.Log("Switching to State" + newState.ToString());
    }


    private void Update()
    {
        switch (CurrentState)
        {
            case GamePlayState.Gameplay:
                DoGamePlayState();
                break;
            case GamePlayState.Paused:
                DoPausedState();
                break;
        }

        //when P is pressed, if we are paused, unpause if we aren't paused then pause it.
        //not really nessacry you might have your own way of pausing already
        if (Input.GetKeyDown(KeyCode.P))
        {
            switch (CurrentState)
            {
                case GamePlayState.Gameplay:
                    SetState(GamePlayState.Paused);
                    break;
                case GamePlayState.Paused:
                    SetState(GamePlayState.Gameplay);
                    break;
            }
        }
    }

    private void DoGamePlayState()
    {
        Debug.Log("In Gameplay state");

        if (Input.GetMouseButtonDown(0))
        {
            //if the mouse is over a UI GameObject return from this function
            if (EventSystem.current.IsPointerOverGameObject())
                return;


            //create a ray going from the camera to the mouse position in world space
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

            //fire this ray and check if we hit anything on the "RayCastLayerMask" layer you can change this to whatever layer you need in the editor
            if (Physics.Raycast(ray, out RaycastHit hit, 1000f, RayCastLayerMask))
            {
                //you hit an enemy, so update your score, update the UI component for it too
                score++;
                scoreText.text = score.ToString();
                moneyText.text = money.ToString();
                Debug.Log("Hit An Enemy " + hit.transform.name);
            }

        }
    }
    private void DoPausedState()
    {
        //and in here we are doing literally nothing since you want nothing to happen while paused! notice the key check to toggle the state is outside statemachine states, as we want this to work in either state.
        Debug.Log("In Paused state");
    }

    public enum GamePlayState
    {
        Gameplay,
        Paused
    }
}
\$\endgroup\$
2
  • \$\begingroup\$ This question has been updated multiple times due to mistakes, so please make sure to refresh the page cache before reading. \$\endgroup\$ Commented Dec 8, 2021 at 20:24
  • \$\begingroup\$ At this part, I might be annoying but so many questions still from me. First of all, I am really-really thankful for what you've done there, such a detailed professional kind of tutorial you wrote there! I am amazed! There are some things I don't really get. I don't really get what Raycast is all about, even after reading about it, remaing blurry. There are no enemy types in this game. I keep watching your code and wow, this is chinese for me :D The debug confirmed that the code works, but it worked before as well. I mean the gameplay stopped, only the input and the count increase didn't. \$\endgroup\$
    – imbruceter
    Commented Dec 8, 2021 at 22:06

You must log in to answer this question.

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