Souljack/Assets/_Project/Scripts/LevelGenerating/DoorController.cs

163 lines
6.7 KiB
C#

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<BoxCollider>();
if (col == null || !col.isTrigger)
{
var trigger = gameObject.AddComponent<BoxCollider>();
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");
}
}
}