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; /// /// Кэширует необходимые компоненты и предупреждает, если чего-то не хватает. /// private void Awake() { _compositeCollider = GetComponent(); _rigidbody = GetComponent(); _spriteRenderers = GetComponentsInChildren(); 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} и его дочерних объектах."); } /// /// Запускает отсрочку исчезновения при входе игрока на платформу. /// /// Коллизия, по которой определяем игрока. 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()); } /// /// Останавливает исчезновение и инициирует процесс появления, когда игрок уходит. /// /// Коллизия выхода игрока. 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()); } /// /// Плавно уменьшает альфу спрайтов до нуля и отключает физику платформы. /// 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; } /// /// Плавно возвращает платформу и повторно включает физику после задержки. /// 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; } /// /// Позволяет внешним системам сразу запустить исчезновение (без ожидания). /// 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()); } /// /// Позволяет внешним системам сразу запустить появление. /// 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()); } /// /// Ожидает заданную задержку перед фактическим запуском корутины Vanish. /// private IEnumerator StartVanishWithDelay() { if (vanishStartDelay > 0f) yield return new WaitForSeconds(vanishStartDelay); // выдерживаем таймер ожидания _vanishCoroutine = StartCoroutine(Vanish()); _delayedVanishCoroutine = null; } } }