using UnityEngine; namespace _Project.Scripts.LevelGenerating { // ===================================================================== // Контроллер ДВОЙНОЙ двери (левая + правая створка). // Сейчас сам создаёт Trigger-коллайдер и открывает створки при подходе игрока. // Позже оркестратор сможет управлять дверью через Open(), Close() и SetLocked(). // ===================================================================== public class DoorController : MonoBehaviour { public enum OpenType { Sliding, // раздвижная: левая створка едет влево (-X), правая вправо (+X) Rotating // распашная: створки поворачиваются на петлях в разные стороны } [Header("Створки двойной двери")] [Tooltip("Левая створка двери")] [SerializeField] private Transform leftWing; [Tooltip("Правая створка двери")] [SerializeField] private Transform rightWing; [Header("Режим и скорость открытия")] [SerializeField] private OpenType openType = OpenType.Sliding; [SerializeField] private float openSpeed = 3.5f; [Tooltip("Для Sliding: на сколько метров каждая створка отъезжает в свою сторону по локальной оси X")] [SerializeField] private float slideDistance = 1f; [Tooltip("Для Rotating: на какой угол (в градусах) распахивается каждая створка")] [SerializeField] private float openAngle = 90f; [Header("Авто-открытие (временно, до оркестратора)")] [Tooltip("Выключи, когда дверями начнёт управлять оркестратор")] [SerializeField] private bool autoOpenNearPlayer = true; [SerializeField] private string playerTag = "Player"; [SerializeField] private Vector3 triggerSize = new Vector3(3.5f, 2.5f, 4.5f); public bool IsOpen { get; private set; } public bool IsLocked { get; private set; } private Vector3 _leftClosedPos, _rightClosedPos; private Quaternion _leftClosedRot, _rightClosedRot; private int _playersInsideTrigger; private void Awake() { // Если створки не назначены в инспекторе, пробуем найти первые два дочерних объекта автоматически if (leftWing == null && transform.childCount > 0) leftWing = transform.GetChild(0); if (rightWing == null && transform.childCount > 1) rightWing = transform.GetChild(1); if (leftWing != null) { _leftClosedPos = leftWing.localPosition; _leftClosedRot = leftWing.localRotation; } if (rightWing != null) { _rightClosedPos = rightWing.localPosition; _rightClosedRot = rightWing.localRotation; } if (autoOpenNearPlayer) { SetupProximityTrigger(); } } private void SetupProximityTrigger() { var col = GetComponent(); if (col == null || !col.isTrigger) { var trigger = gameObject.AddComponent(); trigger.isTrigger = true; trigger.size = triggerSize; trigger.center = new Vector3(0f, triggerSize.y / 2f, 0f); } } private void Update() { if (openType == OpenType.Sliding) { // Левая створка едет в -X, правая в +X if (leftWing != null) { Vector3 targetL = IsOpen ? _leftClosedPos + Vector3.left * slideDistance : _leftClosedPos; leftWing.localPosition = Vector3.MoveTowards( leftWing.localPosition, targetL, openSpeed * Time.deltaTime); } if (rightWing != null) { Vector3 targetR = IsOpen ? _rightClosedPos + Vector3.right * slideDistance : _rightClosedPos; rightWing.localPosition = Vector3.MoveTowards( rightWing.localPosition, targetR, openSpeed * Time.deltaTime); } } else // Rotating { float rotSpeed = openSpeed * 60f * Time.deltaTime; if (leftWing != null) { Quaternion targetL = IsOpen ? _leftClosedRot * Quaternion.Euler(0f, -openAngle, 0f) : _leftClosedRot; leftWing.localRotation = Quaternion.RotateTowards(leftWing.localRotation, targetL, rotSpeed); } if (rightWing != null) { Quaternion targetR = IsOpen ? _rightClosedRot * Quaternion.Euler(0f, openAngle, 0f) : _rightClosedRot; rightWing.localRotation = Quaternion.RotateTowards(rightWing.localRotation, targetR, rotSpeed); } } } // ---------- API для будущего Оркестратора ---------- public void Open() { if (IsLocked) return; IsOpen = true; } public void Close() => IsOpen = false; public void SetLocked(bool locked) { IsLocked = locked; if (locked) Close(); } // ---------- Триггер приближения игрока ---------- private void OnTriggerEnter(Collider other) { if (!autoOpenNearPlayer || !IsPlayer(other)) return; _playersInsideTrigger++; Open(); } private void OnTriggerExit(Collider other) { if (!autoOpenNearPlayer || !IsPlayer(other)) return; _playersInsideTrigger = Mathf.Max(0, _playersInsideTrigger - 1); if (_playersInsideTrigger == 0) Close(); } private bool IsPlayer(Collider col) { if (col.CompareTag(playerTag)) return true; if (col.transform.root.CompareTag(playerTag)) return true; return col.name.Contains("Player") || col.transform.root.name.Contains("Player"); } } }