So as the title suggests, when testing my game out, I did notice that the pause menu does not deactivate the UI that can be shown or hidden via hot-keys. That is, the Quests, Inventory, Equipment and Traits UI, allowing the player to be capable of doing modifications to these things when the game is paused. How do we block this from happening?
This is an ‘off-the-cuff’ answer and @Brian_Trotter will probably come in with a better one, but you could just find all the ShowHideUI
scripts and set a flag on them, or disable them altogether
ShowHideUI.cs
// I copied this code from the repo
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace GameDevTV.UI
{
public class ShowHideUI : MonoBehaviour
{
[SerializeField] KeyCode toggleKey = KeyCode.Escape;
[SerializeField] GameObject uiContainer = null;
private bool gameIsPaused = false;
// Start is called before the first frame update
void Start()
{
uiContainer.SetActive(false);
}
// Update is called once per frame
void Update()
{
// Check the flag, too
if (!gameIsPaused && Input.GetKeyDown(toggleKey))
{
Toggle();
}
}
public void Toggle()
{
uiContainer.SetActive(!uiContainer.activeSelf);
}
// Add this public method
public void SetPaused(bool isPaused)
{
gameIsPaused = isPaused;
}
}
}
PauseMenuUI.cs
using RPG.Control;
using RPG.SceneManagement;
using UnityEngine;
namespace RPG.UI
{
public class PauseMenuUI : MonoBehaviour
{
PlayerController playerController;
private void Start() {
playerController = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerController>();
}
private void OnEnable()
{
if (playerController == null) return;
Time.timeScale = 0;
playerController.enabled = false;
DisableShowHideUI(true); // Toggle Paused
}
private void OnDisable()
{
if (playerController == null) return;
Time.timeScale = 5;
playerController.enabled = true;
DisableShowHideUI(false); // Toggle Paused
}
public void Save()
{
SavingWrapper savingWrapper = FindObjectOfType<SavingWrapper>();
savingWrapper.Save();
}
public void SaveAndQuit()
{
SavingWrapper savingWrapper = FindObjectOfType<SavingWrapper>();
savingWrapper.Save();
savingWrapper.LoadMenu();
}
// Get all the ShowHideUI scripts and prevent them from activating
private void DisableShowHideUI(bool disabled)
{
foreach (ShowHideUI showHideUI in FindObjectsOfType<ShowHideUI>())
{
showHideUI.SetPaused(disabled);
}
}
}
}
The problem with this is that this change will also disable the ShowHideUI
of the pause menu, meaning it won’t work when you try to close the pause menu again. The solution is probably to keep a reference in the PauseMenuUI
script to the ShowHideUI
that activates the pause menu and skip it when disabling them
At this point in time, I’m convinced Brian is a coding wizard. He’d solve issues that would take me weeks to figure out, let alone solve, in 5 minutes, and I have no idea how. Bless him, he pulled me out of coding problems countless times
By all means, I’ll give the solution a read through and a go, to see what happens
You’re overestimating my abilities. This one took me 8 minutes.
using System.Linq;
using GameDevTV.UI.Inventories;
using UnityEngine;
namespace GameDevTV.UI
{
public class ShowHideUI : MonoBehaviour
{
[SerializeField] KeyCode toggleKey = KeyCode.Escape;
[SerializeField] GameObject uiContainer = null;
[SerializeField] GameObject otherInventoryContainer=null;
[SerializeField] InventoryUI otherInventoryUI = null;
[SerializeField] private bool modal = false;
private static bool locked = false;
public bool HasOtherInventory => otherInventoryContainer != null;
// Start is called before the first frame update
void Start()
{
uiContainer.SetActive(false);
if(otherInventoryContainer!=null) otherInventoryContainer.SetActive(false);
}
// Update is called once per frame
void Update()
{
if (locked && !modal) return;
if (Input.GetKeyDown(toggleKey))
{
Toggle();
}
}
public void ShowOtherInventory(GameObject go)
{
uiContainer.SetActive(true);
otherInventoryContainer.SetActive(true);
otherInventoryUI.Setup(go);
}
public void Toggle()
{
uiContainer.SetActive(!uiContainer.activeSelf);
if(otherInventoryContainer!=null) otherInventoryContainer.SetActive(false);
if (modal)
{
if (!locked && uiContainer.activeSelf) CloseOtherWindows();
else locked = false;
}
}
private void CloseOtherWindows()
{
foreach (ShowHideUI ui in FindObjectsOfType<ShowHideUI>().Where(s=>!s.modal))
{
ui.uiContainer.SetActive(false);
if(ui.otherInventoryContainer!=null) ui.otherInventoryContainer.SetActive(false);
}
locked = true;
}
}
}
I addition to locking out the other ShowHideUIs, it also force closes any windows currently open, with the exception of the Dialogue and QuestUI.
I have an idea for dealing with ShopUI and Dialogue, but it will require reconfiguring both UIs and I’m late for work.
You’re overestimating my abilities. This one took me 8 minutes.
Oh no, that’s too late (I’m just joking
)
That was an ideal solution, thank you Brian. It did turn off all UIs when the pause menu is hit (I didn’t test the Shops and Dialogue UIs yet)
Updates for anyone seeing this later on down the line: go to your Pause Menu UI, and turn on ‘Modal’ for that. This will make your pause menu the dominating UI, where activating your Pause Menu deactivates all other UI menus (well, except the shop and dialogue so far)
Have a great day at work today Brian
Hi again Brian. Any updates regarding this?
Force closing the ShopUI and TraitStoreUI is easy, just put a ShowHideUI on the relevant windows with a Keycode that is unlikely to be used. The windows will auto-close.
Preventing them from opening while the modal is active is a wee bit trickier.
The simplest thing I can think of is to add this little script to the GameObject that is enabled and disabled for each of the two UIs.
public class SuppressOnModal : Monobehaviour
{
void OnEnable()
{
if(ShowHideUI.IsLocked) gameObject.SetActive(false);
}
}
You would also need to expose the locked variable in ShowHideUI
public static bool IsLocked => locked;
Force closing the ShopUI and TraitStoreUI is easy, just put a ShowHideUI on the relevant windows with a Keycode that is unlikely to be used. The windows will auto-close.
I did add a second ShowHideUI on the both windows, but for the Trait it just gave me a second access button, and for the shop it made sure the UI never shows up again
As for the SuppressOnModal script, it really didn’t do much tbh… Any alternative solutions?
Hmmm… my ideas were off the cuff, but I’ve since discovered that they won’t work.
I’ll have to work on a different solution.
Remove the 2nd ShowHideUI from TraitStore, that was supposed to be DialogueUI, but I was clearly tired after work.
Take the SuppressOnModal script and delete it forever. We actually don’t need it because if the pause menu is active, then you can’t open a window anyways, at least not under the legacy input system (it’s a different story with the new input system).
Ok, with the code in hand and the project open, I have a solution:
To be clear, remove the ShowHideUI scripts from the ShopUI and DialogueUI if you have added them at my horrible instructions.
In ShowHideUI, add a new event
public static event System.Action OnModalActive;
And in CloseOtherWindows, add the line
OnModalActive?.Invoke();
Now in DialogueUI.Start(), add
ShowHideUI.OnModalActive += playerConversant.Quit;
Because this is a static event, it is mandatory that you also add
void OnDestroy()
{
ShowHideUI.OnModalActive -=playerConversant.Quit;
}
In ShopUI.cs, you’ll be doing the same thing, only the subscribed method will be Close
ShowHideUI.OnModalActive+=Close;
void OnDestroy()
{
ShowHideUI.OnModalActive-=Close;
}
Unlike my previous solution, this has been tested.
For Dialogue, it works. For shop, not yet… This is the injected ‘Shop.cs’ code, if it helps in anyway:
public static event System.Action Close;
void Start() {
ShowHideUI.OnModalActive += Close;
}
void OnDestroy() {
ShowHideUI.OnModalActive -= Close;
}
Edit: I forgot to implement it in my ‘ShowHideUI.cs’, but even by referencing the namespace, the compiler still can’t see my ‘Public static event System.Action Close;’
Ooops, take that code out of Shop.cs
It belongs in ShopUI.cs, where there is a convenient method already there called Close();
Yup, that worked beautifully. Thanks again Brian (btw can we work on the Crafting system tomorrow? I have another one in mind, just don’t want to overwhelm you, if that’s okay )