using OctoCore.Components; using UnityEngine; using UnityEngine.Rendering.Universal; public class SpiralStaircase : MonoBehaviour { [System.Serializable] public class References { public UniversalRendererData RendererData; public GameObject Stairs; public GameObject[] Inside; public GameObject[] Outside; } [System.Serializable] public class Settings { public float Offset = -12.25f; public float StartAngle = 450; public float EndAngle = 720; } [SerializeField] private References _references; [SerializeField] private Settings _settings; private bool _playerInside; [SerializeField] private int _turns; [SerializeField] private float _totalAngle; [SerializeField] private float _progression; void Start() { ManageInside(); } void OnDisable() { _playerInside = false; ManageInside(); } void Update() { if (_playerInside) Count(); } void OnTriggerEnter(Collider col) { if (OctoPlayer.Instance && OctoPlayer.Instance.gameObject == col.gameObject) { if (!_playerInside) { _playerInside = true; ManageInside(); } } } void OnTriggerExit(Collider col) { if (OctoPlayer.Instance && OctoPlayer.Instance.gameObject == col.gameObject) { if (_playerInside) { _playerInside = false; ManageInside(); } } } private void Count() { if (!OctoPlayer.Instance) return; Vector2[] steps = new Vector2[4] { Vector2.up, Vector2.left, Vector2.down, Vector2.right }; Vector2 nextStep = steps[_turns % steps.Length]; Vector3 relativePos3D = transform.InverseTransformPoint(OctoPlayer.Instance.transform.position); Vector2 relativePos2D = new Vector2(relativePos3D.x, relativePos3D.z); float quarterAngle = Vector2.Angle(nextStep, relativePos2D) * Mathf.Sign(Vector3.Cross(nextStep, relativePos2D).z); _totalAngle = Mathf.Max(0, _turns * 90 + quarterAngle); if (quarterAngle > 90 && quarterAngle < 100) { _turns++; } else if (quarterAngle < 0 && _turns > 0) { _turns--; } _progression = Mathf.Clamp01(Mathf.InverseLerp(_settings.StartAngle, _settings.EndAngle, _totalAngle)); _references.Stairs.transform.localPosition = new Vector3(0, _progression * _settings.Offset, 0); } private void ManageInside() { foreach (GameObject obj in _references.Inside) obj.SetActive(_playerInside); foreach (GameObject obj in _references.Outside) obj.SetActive(!_playerInside); Shader.SetGlobalFloat("_MaskEnabled", _playerInside ? 0 : 1); foreach (var feature in _references.RendererData.rendererFeatures) { // Stencil Mask // VisibleThroughMask // HiddenThroughMask if (feature.name == "HiddenThroughMask") { feature.SetActive(!_playerInside); break; } } } }