using System.Collections; using System.Linq; using UnityEngine; using RR.Game2D.Core; namespace RR.Game2D.Entities.Platforms { public class TriggeringPlatform : MonoBehaviour { [Header("Настройки движения платформы")] [SerializeField] private float moveSpeed = 3f; [SerializeField] private float pathLength = 5f; [SerializeField] private Direction2D moveDirection = Direction2D.Right; [Header("Прикрепление игрока")] [SerializeField] private bool attachPlayer = true; [Tooltip("Минимальный угол нормали контакта к вертикали для прикрепления (0.7 ≈ 45°)")] [SerializeField, Range(0f, 1f)] private float normalThreshold = 0.7f; private Vector3 _startPosition; private Vector3 _endPosition; private void Awake() { _startPosition = transform.position; _endPosition = moveDirection switch { Direction2D.Down => _startPosition + Vector3.down * pathLength, Direction2D.Left => _startPosition + Vector3.left * pathLength, Direction2D.Right => _startPosition + Vector3.right * pathLength, Direction2D.Up => _startPosition + Vector3.up * pathLength, _ => _startPosition }; } private void OnCollisionEnter2D(Collision2D other) { if (!attachPlayer) return; if (!other.gameObject.CompareTag("Player")) return; // Проверяем, что игрок стоит на верхней части платформы if (IsPlayerOnTop(other)) { other.transform.SetParent(transform); } } private void OnCollisionStay2D(Collision2D other) { if (!attachPlayer) return; if (!other.gameObject.CompareTag("Player")) return; // Если игрок уже прикреплён, но больше не на верхней части - отсоединяем if (other.transform.parent == transform && !IsPlayerOnTop(other)) { other.transform.SetParent(null); } // Если игрок не прикреплён, но теперь на верхней части - прикрепляем else if (other.transform.parent != transform && IsPlayerOnTop(other)) { other.transform.SetParent(transform); } } private void OnCollisionExit2D(Collision2D other) { if (!attachPlayer) return; if (!other.gameObject.CompareTag("Player")) return; if (other.transform.parent == transform) { other.transform.SetParent(null); } } /// /// Проверяет, находится ли игрок на верхней части платформы /// /// Данные о столкновении /// True, если игрок стоит сверху private bool IsPlayerOnTop(Collision2D collision) { // Проверяем нормали всех контактных точек // Нормаль направлена от другого объекта (игрока) к платформе, // поэтому если игрок сверху, нормаль будет направлена вниз return collision.contacts.Any(contact => Vector2.Dot(contact.normal, Vector2.down) > normalThreshold); } public void Move() { StopAllCoroutines(); StartCoroutine(MovePlatform(_endPosition)); } public void MoveBack() { StopAllCoroutines(); StartCoroutine(MovePlatform(_startPosition)); } private IEnumerator MovePlatform(Vector3 targetPosition) { while (transform.position != targetPosition) { transform.position = Vector3.MoveTowards( transform.position, targetPosition, Time.deltaTime * moveSpeed); yield return null; } transform.position = targetPosition; } } }