One week later, and we fixed the dynamic crafting tables problem. Anyway, the next thing I want to do, is to make sure that in ‘WindowController.cs’, only when you open the pause menu do you freeze the time scale. In other words, if you open the inventory, quest list, etc… don’t freeze the time. Only freeze it when the pause menu is opened
I’ll work on this, but I figured I should let you know @Brian_Trotter (in case you got any ideas for that one, xD).
Anyway, here’s the ‘WindowController.cs’ script:
using System.Collections.Generic;
using RPG.InputReading;
using UnityEngine;
namespace RPG.UI
{
// Generic script, responsible for common behaviour between User Interface Systems
public abstract class WindowController: MonoBehaviour
{
protected static HashSet<WindowController> activeWindows = new();
public static event System.Action OnAnyWindowOpened;
public static event System.Action OnAllWindowsClosed;
protected InputReader InputReader;
// Protected and Virtual, therefore this method can be overridden (because it's virtual) by any inheriting scripts (because it's protected),
// and tuned:
protected virtual void Awake()
{
InputReader = GameObject.FindWithTag("Player").GetComponent<InputReader>();
Subscribe();
}
// Protected and Virtual, therefore this method can be overridden by any inheriting scripts, and tuned:
protected virtual void OnDestroy()
{
Unsubscribe();
}
// when any window is open:
void OnEnable()
{
activeWindows.Add(this);
Time.timeScale = 0.0f;
OnAnyWindowOpened?.Invoke();
Debug.Log($"Window enabled");
}
// when any window is closed:
protected virtual void OnDisable()
{
activeWindows.Remove(this);
if (activeWindows.Count == 0) {
Time.timeScale = 1.0f;
OnAllWindowsClosed?.Invoke();
}
Debug.Log($"Window disabled");
}
/// <summary>
/// Override this method to subscribe to any events that will call this implementation of 'WindowController'
/// </summary>
protected abstract void Subscribe();
/// <summary>
/// Override this method to ubsubscribe to any events that will call this implementation of 'WindowController'
/// </summary>
protected abstract void Unsubscribe();
protected void CloseWindow()
{
gameObject.SetActive(false);
Debug.Log($"Window closed");
}
protected void ToggleWindow()
{
gameObject.SetActive(!gameObject.activeSelf);
Debug.Log($"Window toggled to {(gameObject.activeSelf ? "active" : "inactive")}");
}
}
}
Anyway, here’s what I came up with:
- In ‘InputReader.cs’, I introduced a circular dependency (I realized that one was there from the days of me creating the parrying system… I will need to find a way around this). Apart from that, I swapped out ‘EnableControls’ and ‘DisableControls’ in ‘InputReader.cs’ for new ‘EnableFreeLookCamera’ and ‘DisableFreeLookCamera’. That way, you don’t lose your controls, you just freeze the Free Look camera when you got an inventory of some sort open in your game:
private PlayerStateMachine playerStateMachine;
private void Start()
{
controls = new Controls();
controls.Player.SetCallbacks(this);
controls.Player.Enable();
controls.UI.SetCallbacks(this);
controls.UI.Enable();
// WindowController.OnAnyWindowOpened += DisableControls;
// WindowController.OnAllWindowsClosed += EnableControls;
// TEST - DELETE IF FAILED
WindowController.OnAnyWindowOpened += DisableFreeLookCamera;
WindowController.OnAllWindowsClosed += EnableFreeLookCamera;
playerStateMachine = GetComponent<PlayerStateMachine>();
animationEventRelay = GetComponent<AnimationEventRelay>();
}
/* void EnableControls()
{
controls.Player.Enable();
}
void DisableControls()
{
controls.Player.Disable();
} */
// TEST FUNCTION - DELETE IF FAILED
void EnableFreeLookCamera()
{
// (HARD-CODED VALUES. IF YOU CHANGE THEM IN CINEMACHINE FREE LOOK CAMERA, CHANGE THEM HERE TOO!)
playerStateMachine.PlayerFreeLookCamera.m_XAxis.m_MaxSpeed = 200;
playerStateMachine.PlayerFreeLookCamera.m_YAxis.m_MaxSpeed = 0;
// Do the same for the Boat driving camera as well
}
void DisableFreeLookCamera()
{
playerStateMachine.PlayerFreeLookCamera.m_XAxis.m_MaxSpeed = 0f;
playerStateMachine.PlayerFreeLookCamera.m_YAxis.m_MaxSpeed = 0f;
// Do the same for the Boat driving camera as well
}
private void OnDestroy()
{
// WindowController.OnAnyWindowOpened -= DisableControls;
// WindowController.OnAllWindowsClosed -= EnableControls;
// TEST - DELETE IF FAILED
WindowController.OnAnyWindowOpened -= DisableFreeLookCamera;
WindowController.OnAllWindowsClosed -= EnableFreeLookCamera;
controls.Player.Disable();
controls.UI.Disable();
}
- in ‘WindowController.cs’, I removed the time scale freeezing, and strictly placed it in ‘PauseMenuUI.cs’:
// when any window is open:
void OnEnable()
{
activeWindows.Add(this);
// Time.timeScale = 0.0f;
OnAnyWindowOpened?.Invoke();
Debug.Log($"Window enabled");
}
// when any window is closed:
protected virtual void OnDisable()
{
activeWindows.Remove(this);
if (activeWindows.Count == 0)
{
// Time.timeScale = 1.0f;
OnAllWindowsClosed?.Invoke();
}
Debug.Log($"Window disabled");
}
- in ‘PauseMenuUI.cs’, I modified ‘HandleCancelEvent()’, so that we can freeze the time on pause only for pausing, and not anything else:
private void HandleCancelEvent()
{
if (activeWindows.Count > 0)
{
var windows = activeWindows.ToList();
for (int i = 0; i < activeWindows.Count; i++)
{
windows[i].gameObject.SetActive(false);
}
// TEST LINE - DELETE IF FAILED
Time.timeScale = 1.0f;
}
else
{
// TEST LINE - DELETE IF FAILED
Time.timeScale = 0.0f;
gameObject.SetActive(true);
}
}
Now I gotta find which other cameras need to freeze as well (like the boat-driving camera for example), and work on that
But I also noticed something, the Quest UI is not part of the WindowController yet, so it doesn’t play by it’s rules just yet. I’ll need to work on that later
Is this the best approach? I truly don’t know, but time will tell
I also have to mention that the Resume button from the pause menu, along with the quit button, will suffer because of this setup. Here’s how I fixed it:
- Place this simple function in ‘PauseMenuUI.cs’:
public void RestoreTimeSpeedToNormal()
{
Time.timeScale = 1.0f;
}
- Apply this to both the quit button, and the resume button, to restore the game speed:
and I also did the same for my own custom Pickup Inventory UI, where I restore the speed when it’s closed:
(I’ll work on the code of freezing it to begin with)
The one major drawback I believe I will face with my variant, is you’ll be strangled quite a lot by NPCs and your camera will be frozen. I’ll probably just need to make a button for that or something, instead of this setup