259 lines
10 KiB
C#
259 lines
10 KiB
C#
using System.Collections;
|
||
using UnityEngine;
|
||
|
||
namespace RR.Game2D.Entities.Platforms
|
||
{
|
||
public class VanishingPlatform : MonoBehaviour
|
||
{
|
||
[Header("Настройки исчезновения платформы")]
|
||
[SerializeField] private float vanishDuration = 0.5f;
|
||
[SerializeField] private float reappearDelay = 2f;
|
||
[SerializeField] private float reappearDuration = 0.5f;
|
||
[SerializeField, Min(0f)] private float vanishStartDelay = 1f;
|
||
|
||
private CompositeCollider2D _compositeCollider;
|
||
private Rigidbody2D _rigidbody;
|
||
private SpriteRenderer[] _spriteRenderers;
|
||
private Coroutine _vanishCoroutine;
|
||
private Coroutine _reappearCoroutine;
|
||
private Coroutine _delayedVanishCoroutine;
|
||
private Color[] _initialColors;
|
||
|
||
/// <summary>
|
||
/// Кэширует необходимые компоненты и предупреждает, если чего-то не хватает.
|
||
/// </summary>
|
||
private void Awake()
|
||
{
|
||
_compositeCollider = GetComponent<CompositeCollider2D>();
|
||
_rigidbody = GetComponent<Rigidbody2D>();
|
||
_spriteRenderers = GetComponentsInChildren<SpriteRenderer>();
|
||
|
||
if (_compositeCollider == null)
|
||
Debug.LogWarning($"[{nameof(VanishingPlatform)}] CompositeCollider2D не найден на {gameObject.name}.");
|
||
|
||
if (_rigidbody == null)
|
||
Debug.LogWarning($"[{nameof(VanishingPlatform)}] Rigidbody2D не найден на {gameObject.name}. CompositeCollider2D требует Rigidbody2D.");
|
||
|
||
if (_spriteRenderers == null || _spriteRenderers.Length == 0)
|
||
Debug.LogWarning($"[{nameof(VanishingPlatform)}] SpriteRenderer'ы не найдены на {gameObject.name} и его дочерних объектах.");
|
||
}
|
||
|
||
/// <summary>
|
||
/// Запускает отсрочку исчезновения при входе игрока на платформу.
|
||
/// </summary>
|
||
/// <param name="other">Коллизия, по которой определяем игрока.</param>
|
||
private void OnCollisionEnter2D(Collision2D other)
|
||
{
|
||
if (!other.gameObject.CompareTag("Player")) return;
|
||
|
||
if (_delayedVanishCoroutine != null)
|
||
{
|
||
StopCoroutine(_delayedVanishCoroutine);
|
||
_delayedVanishCoroutine = null;
|
||
}
|
||
|
||
// Если в процессе была корутина Reappear — её отменяем
|
||
if (_reappearCoroutine != null)
|
||
{
|
||
StopCoroutine(_reappearCoroutine);
|
||
_reappearCoroutine = null;
|
||
}
|
||
|
||
if (_vanishCoroutine != null)
|
||
StopCoroutine(_vanishCoroutine);
|
||
|
||
// _vanishCoroutine = StartCoroutine(Vanish());
|
||
_delayedVanishCoroutine = StartCoroutine(StartVanishWithDelay());
|
||
}
|
||
|
||
/// <summary>
|
||
/// Останавливает исчезновение и инициирует процесс появления, когда игрок уходит.
|
||
/// </summary>
|
||
/// <param name="other">Коллизия выхода игрока.</param>
|
||
private void OnCollisionExit2D(Collision2D other)
|
||
{
|
||
if (!other.gameObject.CompareTag("Player")) return;
|
||
|
||
if (_delayedVanishCoroutine != null)
|
||
{
|
||
StopCoroutine(_delayedVanishCoroutine);
|
||
_delayedVanishCoroutine = null;
|
||
}
|
||
|
||
// Если в процессе была корутина Vanish — её отменяем
|
||
if (_vanishCoroutine != null)
|
||
{
|
||
StopCoroutine(_vanishCoroutine);
|
||
_vanishCoroutine = null;
|
||
}
|
||
|
||
if (_reappearCoroutine != null)
|
||
StopCoroutine(_reappearCoroutine);
|
||
|
||
_reappearCoroutine = StartCoroutine(Reappear());
|
||
}
|
||
|
||
/// <summary>
|
||
/// Плавно уменьшает альфу спрайтов до нуля и отключает физику платформы.
|
||
/// </summary>
|
||
private IEnumerator Vanish()
|
||
{
|
||
if (_spriteRenderers == null || _spriteRenderers.Length == 0)
|
||
yield break; // нечего анимировать
|
||
|
||
// Сохраняем начальные цвета для всех рендереров (если ещё не сохранены)
|
||
if (_initialColors == null || _initialColors.Length != _spriteRenderers.Length)
|
||
{
|
||
_initialColors = new Color[_spriteRenderers.Length];
|
||
for (int i = 0; i < _spriteRenderers.Length; i++)
|
||
_initialColors[i] = _spriteRenderers[i].color;
|
||
}
|
||
|
||
// Запоминаем текущую альфу для каждого рендерера
|
||
float[] startAlphas = new float[_spriteRenderers.Length];
|
||
for (int i = 0; i < _spriteRenderers.Length; i++)
|
||
startAlphas[i] = _spriteRenderers[i].color.a;
|
||
|
||
float elapsed = 0f;
|
||
|
||
while (elapsed < vanishDuration)
|
||
{
|
||
elapsed += Time.deltaTime;
|
||
float t = vanishDuration > 0f ? Mathf.Clamp01(elapsed / vanishDuration) : 1f;
|
||
|
||
for (int i = 0; i < _spriteRenderers.Length; i++)
|
||
{
|
||
Color c = _initialColors[i];
|
||
float alpha = Mathf.Lerp(startAlphas[i], 0f, t);
|
||
_spriteRenderers[i].color = new Color(c.r, c.g, c.b, alpha);
|
||
}
|
||
|
||
yield return null;
|
||
}
|
||
|
||
// Принудительно установить 0 альфу
|
||
for (int i = 0; i < _spriteRenderers.Length; i++)
|
||
{
|
||
Color c = _initialColors[i];
|
||
_spriteRenderers[i].color = new Color(c.r, c.g, c.b, 0f);
|
||
}
|
||
|
||
if (_rigidbody)
|
||
_rigidbody.simulated = false; // отключаем Collider через Rigidbody2D
|
||
|
||
_vanishCoroutine = null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Плавно возвращает платформу и повторно включает физику после задержки.
|
||
/// </summary>
|
||
private IEnumerator Reappear()
|
||
{
|
||
if (_spriteRenderers == null || _spriteRenderers.Length == 0)
|
||
yield break; // нечего анимировать
|
||
|
||
// Убедимся, что у нас есть базовые цвета — если нет, прочитаем текущие
|
||
if (_initialColors == null || _initialColors.Length != _spriteRenderers.Length)
|
||
{
|
||
_initialColors = new Color[_spriteRenderers.Length];
|
||
for (int i = 0; i < _spriteRenderers.Length; i++)
|
||
_initialColors[i] = _spriteRenderers[i].color;
|
||
}
|
||
|
||
// Задержка перед появлением (как в предыдущей логике)
|
||
yield return new WaitForSeconds(reappearDelay);
|
||
|
||
// Запоминаем текущую альфу для каждого рендерера
|
||
float[] startAlphas = new float[_spriteRenderers.Length];
|
||
for (int i = 0; i < _spriteRenderers.Length; i++)
|
||
startAlphas[i] = _spriteRenderers[i].color.a;
|
||
|
||
float elapsed = 0f;
|
||
|
||
while (elapsed < reappearDuration)
|
||
{
|
||
elapsed += Time.deltaTime;
|
||
float t = reappearDuration > 0f ? Mathf.Clamp01(elapsed / reappearDuration) : 1f;
|
||
|
||
for (int i = 0; i < _spriteRenderers.Length; i++)
|
||
{
|
||
Color c = _initialColors[i];
|
||
float alpha = Mathf.Lerp(startAlphas[i], 1f, t);
|
||
_spriteRenderers[i].color = new Color(c.r, c.g, c.b, alpha);
|
||
}
|
||
|
||
yield return null;
|
||
}
|
||
|
||
// Принудительно установить полную непрозрачность
|
||
for (int i = 0; i < _spriteRenderers.Length; i++)
|
||
{
|
||
Color c = _initialColors[i];
|
||
_spriteRenderers[i].color = new Color(c.r, c.g, c.b, 1f);
|
||
}
|
||
|
||
if (_rigidbody)
|
||
_rigidbody.simulated = true; // возвращаем физику
|
||
|
||
_reappearCoroutine = null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Позволяет внешним системам сразу запустить исчезновение (без ожидания).
|
||
/// </summary>
|
||
public void TriggerVanish()
|
||
{
|
||
if (_delayedVanishCoroutine != null)
|
||
{
|
||
StopCoroutine(_delayedVanishCoroutine);
|
||
_delayedVanishCoroutine = null;
|
||
}
|
||
|
||
if (_reappearCoroutine != null)
|
||
{
|
||
StopCoroutine(_reappearCoroutine);
|
||
_reappearCoroutine = null;
|
||
}
|
||
|
||
if (_vanishCoroutine != null)
|
||
StopCoroutine(_vanishCoroutine);
|
||
|
||
_vanishCoroutine = StartCoroutine(Vanish());
|
||
}
|
||
|
||
/// <summary>
|
||
/// Позволяет внешним системам сразу запустить появление.
|
||
/// </summary>
|
||
public void TriggerReappear()
|
||
{
|
||
if (_delayedVanishCoroutine != null)
|
||
{
|
||
StopCoroutine(_delayedVanishCoroutine);
|
||
_delayedVanishCoroutine = null;
|
||
}
|
||
|
||
if (_vanishCoroutine != null)
|
||
{
|
||
StopCoroutine(_vanishCoroutine);
|
||
_vanishCoroutine = null;
|
||
}
|
||
|
||
if (_reappearCoroutine != null)
|
||
StopCoroutine(_reappearCoroutine);
|
||
|
||
_reappearCoroutine = StartCoroutine(Reappear());
|
||
}
|
||
|
||
/// <summary>
|
||
/// Ожидает заданную задержку перед фактическим запуском корутины Vanish.
|
||
/// </summary>
|
||
private IEnumerator StartVanishWithDelay()
|
||
{
|
||
if (vanishStartDelay > 0f)
|
||
yield return new WaitForSeconds(vanishStartDelay); // выдерживаем таймер ожидания
|
||
|
||
_vanishCoroutine = StartCoroutine(Vanish());
|
||
_delayedVanishCoroutine = null;
|
||
}
|
||
}
|
||
} |