163 lines
6.7 KiB
C#
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");
|
|
}
|
|
}
|
|
} |