Danro/Assets/Scripts/Entities/Props/Platforms/TrajectoryPlatform.cs
Danil Iarosh bd57b74d8b level 1-3 updates, bug fixes etc
- улучшил структуру уровня 1-3
- пофиксил баг с застреванием персонажа на уровне 1-3
- пофиксил баг с прилипанием игрока к платформе сбоку
- изменил логику платформ
- добавил больше динамичности в уровень 1-3
2025-11-28 16:48:31 +03:00

138 lines
5.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Linq;
using UnityEngine;
namespace RR.Game2D.Entities.Platforms
{
public class TrajectoryPlatform : MonoBehaviour
{
[Header("Настройки движения платформы")]
[SerializeField] private float moveSpeed = 1f;
[SerializeField] private Vector3[] coordinates;
[SerializeField] private bool loop = true;
[Header("Прикрепление игрока")]
[SerializeField] private bool attachPlayer = true;
[Tooltip("Минимальный угол нормали контакта к вертикали для прикрепления (0.7 ≈ 45°)")]
[SerializeField, Range(0f, 1f)] private float normalThreshold = 0.7f;
[Header("Задержка перед началом движения (в секундах)")]
[SerializeField] private float startDelay;
private int _currentTargetIndex;
private float _delayTimer;
private bool _isWaiting;
private void Start()
{
// Если задержка задана, начинаем с ожидания
if (!(startDelay > 0f)) return;
_isWaiting = true;
_delayTimer = startDelay;
}
private void FixedUpdate()
{
if (coordinates == null || coordinates.Length == 0) return;
// Если платформа в режиме ожидания, уменьшаем таймер
if (_isWaiting)
{
_delayTimer -= Time.fixedDeltaTime;
if (_delayTimer <= 0f)
{
_isWaiting = false;
}
else
{
return; // пока ждём, не двигаемся
}
}
// Определяем целевую точку
Vector3 targetPoint = coordinates[_currentTargetIndex];
// Двигаем платформу к целевой точке
transform.position = Vector3.MoveTowards(transform.position, targetPoint, moveSpeed * Time.fixedDeltaTime);
// Проверяем, достигли ли целевой точки
if (!(Vector3.Distance(transform.position, targetPoint) < 0.01f)) return;
if (loop)
{
// Режим зацикливания: переходим к следующей точке по кругу
_currentTargetIndex = (_currentTargetIndex + 1) % coordinates.Length;
// Если вернулись в начальную точку (индекс 0), активируем задержку
if (_currentTargetIndex != 0 || !(startDelay > 0f)) return;
}
else
{
_currentTargetIndex++;
if (_currentTargetIndex < coordinates.Length) return;
// Возвращаемся в начальную точку
transform.position = coordinates[0];
_currentTargetIndex = 0;
// Активируем задержку перед следующим циклом
if (!(startDelay > 0f)) return;
}
_isWaiting = true;
_delayTimer = startDelay;
}
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);
}
}
/// <summary>
/// Проверяет, находится ли игрок на верхней части платформы
/// </summary>
/// <param name="collision">Данные о столкновении</param>
/// <returns>True, если игрок стоит сверху</returns>
private bool IsPlayerOnTop(Collision2D collision)
{
// Проверяем нормали всех контактных точек
// Нормаль направлена от другого объекта (игрока) к платформе,
// поэтому если игрок сверху, нормаль будет направлена вниз
return collision.contacts.Any(contact => Vector2.Dot(contact.normal, Vector2.down) > normalThreshold);
}
}
}