using System.Collections.Generic; using NightclubArcadia.Player; using StarterAssets; using UnityEngine; namespace NightclubArcadia.UI { /// /// Ref-counted freeze of the player's ThirdPersonController. Multiple /// independent holders (dialogue, menu) can Acquire/Release; the controller /// stays disabled until the last holder releases. /// public sealed class PlayerControlLock : MonoBehaviour { readonly HashSet holders = new HashSet(); ThirdPersonController playerController; StarterAssetsInputs playerInputs; Animator playerAnimator; PlayerMotionArbiter motionArbiter; static readonly int AnimIDSpeed = Animator.StringToHash("Speed"); static readonly int AnimIDMotionSpeed = Animator.StringToHash("MotionSpeed"); public bool IsLocked => holders.Count > 0; void Awake() { playerController = GetComponent(); playerInputs = GetComponent(); playerAnimator = GetComponent(); motionArbiter = GetComponent(); } public void Acquire(object reason) { if (reason == null) { throw new System.ArgumentNullException(nameof(reason)); } var wasLocked = IsLocked; holders.Add(reason); if (!wasLocked && IsLocked) { ApplyLock(true); } } public void Release(object reason) { if (reason == null) { return; } var wasLocked = IsLocked; holders.Remove(reason); if (wasLocked && !IsLocked) { ApplyLock(false); } } void ApplyLock(bool locked) { if (playerController == null) { return; } if (locked) { // Clear pending input and the locomotion blend before freezing // the controller. Disabling it mid-stride otherwise leaves // Speed at its last value, and the character keeps running on // the spot for the whole conversation. if (playerInputs != null) { playerInputs.MoveInput(Vector2.zero); playerInputs.LookInput(Vector2.zero); playerInputs.SprintInput(false); playerInputs.JumpInput(false); } if (playerAnimator != null) { playerAnimator.SetFloat(AnimIDSpeed, 0f); playerAnimator.SetFloat(AnimIDMotionSpeed, 0f); } motionArbiter?.ResetState(); } // cursor state hook — see plan §3.4 playerController.enabled = !locked; } } }