using UnityEngine;
namespace DanroJump.Gameplay
{
///
/// Двигает платформу по синусоиде вокруг позиции спавна.
///
public sealed class MovingPlatformBehaviour : MonoBehaviour, IPlatformLifecycle
{
[SerializeField] private Vector2 localMoveAxis = Vector2.right;
[SerializeField] [Min(0f)] private float amplitude = 1.25f;
[SerializeField] [Min(0.01f)] private float cycleDuration = 2.5f;
[SerializeField] private bool useSpawnIndexOffset = true;
private const float TwoPi = Mathf.PI * 2f;
private Transform cachedTransform;
private Rigidbody2D body;
private Vector3 basePosition;
private Vector2 normalizedMoveAxis = Vector2.right;
private float angularSpeed;
private float phaseOffset;
private void Awake()
{
cachedTransform = transform;
body = GetComponent();
RefreshMoveAxis();
}
#if UNITY_EDITOR
private void OnValidate()
{
RefreshMoveAxis();
}
#endif
///
/// Обновляет позицию платформы вдоль локальной оси движения.
///
private void Update()
{
if (body != null)
{
return;
}
MoveVisual(Time.time);
}
private void FixedUpdate()
{
if (body == null)
{
return;
}
body.MovePosition((Vector2)CalculatePosition(Time.fixedTime));
}
///
/// Двигает visual-only платформу через Transform.
///
private void MoveVisual(float time)
{
if (amplitude <= 0f || cycleDuration <= 0f)
{
return;
}
cachedTransform.position = CalculatePosition(time);
}
///
/// Рассчитывает позицию платформы на указанном времени симуляции.
///
private Vector3 CalculatePosition(float time)
{
if (amplitude <= 0f || cycleDuration <= 0f)
{
return basePosition;
}
var phase = time * angularSpeed + phaseOffset * TwoPi;
return basePosition + (Vector3)(normalizedMoveAxis * (Mathf.Sin(phase) * amplitude));
}
///
/// Запоминает позицию спавна при первом создании.
///
public void Initialize(PlatformSpawnContext context)
{
ApplyContext(context);
}
///
/// Запоминает новую позицию спавна при рецикле платформы.
///
public void Recycle(PlatformSpawnContext context)
{
ApplyContext(context);
}
///
/// Возвращает платформу в базовую позицию.
///
public void ResetPlatform()
{
if (body != null)
{
body.position = (Vector2)basePosition;
return;
}
(cachedTransform != null ? cachedTransform : transform).position = basePosition;
}
///
/// Применяет контекст спавна и рассчитывает фазу движения.
///
private void ApplyContext(PlatformSpawnContext context)
{
RefreshMoveAxis();
basePosition = cachedTransform != null ? cachedTransform.position : transform.position;
phaseOffset = useSpawnIndexOffset ? context.SpawnIndex * 0.173f : 0f;
}
private void RefreshMoveAxis()
{
normalizedMoveAxis = localMoveAxis.sqrMagnitude > 0f ? localMoveAxis.normalized : Vector2.right;
angularSpeed = cycleDuration > 0f ? TwoPi / cycleDuration : 0f;
}
}
}