Another issue with enable/disable PlayerController

This is a follow up to what I posted earlier here https://community.gamedev.tv/t/nasty-bug-with-disabling-playercontroller/232421/7.

In our game we now have multiple things that can enable or disable the PlayerController often around the same time including:

  1. PauseWindowUI
  2. CinematicControlRemover

I noticed that these can interfere with eachother. For example when one script removes removes control but then another script enables control before the first script was ready to re-enable control.

In my case, I also need to keep the player controller disabled during dialogue (but keep the game unpaused) because I have Cinematics running during dialogue.

I must have tried a half dozen solutions on my own each one with its own unique quirks. Here is the latest I came up with inspired by PauseWhenActive - Can I get some feedback on it?

PlayerController.cs edits
    public class PlayerController : MonoBehaviour
    {
        private static readonly Dictionary<MonoBehaviour, bool> ActiveInstances = new();
       
        // If you're wondering why this exits it's keeping UI in sync.
        // In my case I have a virtual joystick and buttons on my UI
        // these need to be turned off when the player controller is disabled.
        public event Action ControllerStateChanged;

        private void OnEnable()
        {
            ControllerStateChanged?.Invoke();
        }
        
        private void OnDisable()
        {
            ControllerStateChanged?.Invoke();
        }

       /// This is necessary because you could have stale
       /// references after a scene load
        private void OnDestroy()
        {
            ActiveInstances.Clear();
        }

        void Update()
        {
            if (!IsInputAllowed()) return;
        }

 
        public bool IsInputAllowed()
        {
            return ActiveInstances.Count == 0;
        }
        
        public void RequestInputSuspend(MonoBehaviour requester)
        {
            ActiveInstances[requester] = true;
            ControllerStateChanged?.Invoke();
        }

        public void RequestInputEnable(MonoBehaviour requester)
        {
            if (ActiveInstances.ContainsKey(requester))
            {
                ActiveInstances.Remove(requester);
                ControllerStateChanged?.Invoke();
            }
        }
   }
SuspendInputWhenActive.cs
    /// <summary>
    /// Class to disable player controller when a certain component is active. For 
    /// example you may put on UI if you want the control to be disabled when that UI 
    /// is active.
    /// </summary>    
    public class SuspendInputWhenActive : MonoBehaviour
    {
        private PlayerController playerController;
        
        private void Awake()
        {
            playerController = GameObject.FindWithTag("Player").GetComponent<PlayerController>();
        }

        private void OnEnable()
        {
            // need to check for null since PlayerController can be destroyed while this is 
            // still alive
            if (playerController)
            {
                playerController.RequestInputSuspend(this);
            }
        }
        
        private void OnDisable()
        {
            // need to check for null since PlayerController can be destroyed while this is 
            // still alive
            if (playerController)
            {
                playerController.RequestInputEnable(this);
            }
        }
    }
CinematicControlRemover.cs edits
        private void DisableControl(PlayableDirector aDirector)
        {
            player.GetComponent<ActionScheduler>().CancelCurrentAction();
            player.GetComponent<Mover>().StartMoveAction(player.transform.position, 1f);
            player.GetComponent<PlayerController>().RequestInputSuspend(this);
        }

        private void EnableControl(PlayableDirector aDirector)
        {
            // Need to check for null because .stopped can trigger as a result of scene 
            // load. Player may be destroyed as a result.
            if (player)
            {
                player.GetComponent<PlayerController>().RequestInputEnable(this);                
            }
        }
    }

This is a pretty good solution.

To be honest, I think the CinematicControlRemover got forgotten about by Sam by the time he got to this course. After the 3154th time of the camera sequence firing off while playtesting, you tend to delete or disable the Cinematic sequences (you won’t find one in the final project, hehe).

1 Like

Awesome. Thank you! And a few days after building it, it seems to continue to do its job.

LOL. Yeah I disabled mine right away and forgot about it as well. Even after I went back in to add cinematics after the SAB course I didn’t realize we had it. Then I realized a few small changes could solve my problem.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms