Danro/Assets/Scripts/Behaviour/LevelFinish.cs
Danil Iarosh e8000ffdca
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
feat(vfx, ui, com): add custom vfx, polish ui and update backlight protocol
- Интегрирована система кастомных визуальных эффектов (VFX):
  - Добавлена новая утилита MvpVFXUtility и настройки MvpVFXSpawnSettings для спавна эффектов.
  - Реализован пул эффектов VFXPool с поддержкой отслеживания версий спавна, сброса оверрайдов и анимации масштаба по времени.
  - Добавлены эффекты прыжка и приземления в PlayerAnimationEvents.
  - Интегрирован эффект DeathVignetteController для плавного затемнения экрана при смерти игрока.
  - Добавлены частицы stompImpactVFX при уничтожении врагов прыжком сверху (EnemyController).
  - Реализован эффект конфетти finishVFX при успешном завершении уровня (LevelFinish).
  - Интегрированы эффекты искр при сборе монеток, кристаллов и других собираемых предметов (Collectible, EnvironmentalCollectibleBase).
- Улучшен и визуально доработан пользовательский интерфейс (UI):
  - Добавлен скрипт QRCodeTierHighlight для цветовой подсветки QR-кодов в зависимости от тира приза.
  - Реализована пульсация блока приза в баннере победы (WinBannerController).
  - Обновлено обозначение валюты в BalanceDisplay с "₽" на "руб.".
  - Добавлены новые префабы, сцены, ассеты тайлсетов и шейдеров для настройки визуального стиля.
- Обновлён протокол и инициализация подсветки COM-платы:
  - Изменен префикс команд подсветки с 85/86 на 8550, а диапазон эффектов обновлен с 40...52 на 10...22 (LightController, LightMode, LightCycleDurations).
  - Исправлена хардкод-команда сброса подсветки при инициализации в ComDeviceClient с устаревшей 8600 на новую 8550 для предотвращения рассинхронизации буфера обмена платы.
2026-07-07 16:52:05 +03:00

183 lines
6.8 KiB
C#
Raw Permalink 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 UnityEngine;
using RR.Common.Managers;
using RR.Common.Prizes;
using RR.Game2D.Core.Managers;
using RR.Game2D.FX;
using UnityEngine.VFX;
namespace RR.Game2D.Behaviour
{
/// <summary>
/// Компонент финиша уровня с возможностью выдачи приза.
/// Устанавливается на объект с триггером и тегом "Finish".
/// </summary>
[RequireComponent(typeof(Collider2D))]
public class LevelFinish : MonoBehaviour
{
[Header("Настройки приза")]
[Tooltip("Включить выдачу приза при завершении уровня")]
[SerializeField] private bool enablePrizeOnFinish = true;
[Tooltip("Задержка перед выдачей приза (в секундах)")]
[SerializeField] private float prizeDelay = 0.5f;
[Header("FX")]
[SerializeField] private VisualEffectAsset finishVFX;
[SerializeField] private string finishVFXResourcePath = "VFX/MVP_Confetti_VFX";
[SerializeField] private float finishVFXLifetime = 2f;
[Header("Отладка")]
[SerializeField] private bool debugMode;
private bool _prizeGiven;
private bool _waitingForPrize;
private void OnTriggerEnter2D(Collider2D collision)
{
// Проверяем, что это игрок
if (!collision.CompareTag("Player")) return;
MvpVFXUtility.Spawn(finishVFX, finishVFXResourcePath, transform.position, finishVFXLifetime);
if (GameManager.Instance != null && GameManager.Instance.IsCurrentLevelFinal())
{
GameManager.Instance.SetPendingWinGameTime(GameManager.Instance.GetCurrentGameTime());
}
if (enablePrizeOnFinish && !_prizeGiven && HasPrizeForCurrentLevel())
{
// Есть приз — выдаём и ждём результата, потом переходим
TryGivePrize();
}
else
{
// Приза нет или он отключён — переходим сразу
GameManager.Instance.NextLevel();
}
}
/// <summary>
/// Проверяет, назначен ли приз для текущего уровня.
/// </summary>
private bool HasPrizeForCurrentLevel()
{
var psm = PrizeSystemManager.Instance;
if (psm == null || psm.Database == null) return false;
string level = $"{GameManager.Instance.World}-{GameManager.Instance.Stage}";
LevelPrizeConfig config = psm.Database.GetConfig(level);
return config.type != PrizeType.None;
}
/// <summary>
/// Пытается выдать приз игроку, если выполнены все условия.
/// </summary>
private void TryGivePrize()
{
// Проверка, что приз еще не был выдан
if (_prizeGiven)
{
if (debugMode)
Debug.Log("[LevelFinish] Приз уже был выдан на этом финише.");
return;
}
// Проверка, включена ли выдача призов в этом компоненте
if (!enablePrizeOnFinish)
{
if (debugMode)
Debug.Log("[LevelFinish] Выдача призов отключена в компоненте.");
return;
}
_prizeGiven = true;
_waitingForPrize = true;
// Подписываемся на результат выдачи приза
var psm = PrizeSystemManager.Instance;
if (psm != null)
psm.OnAnyPrizeResult += OnPrizeFinished;
if (prizeDelay > 0)
{
Invoke(nameof(GivePrize), prizeDelay);
}
else
{
GivePrize();
}
}
/// <summary>
/// Вызывается после завершения выдачи приза (успешно или нет).
/// </summary>
private void OnPrizeFinished(PrizeType type, bool success)
{
if (!_waitingForPrize) return;
_waitingForPrize = false;
var psm = PrizeSystemManager.Instance;
if (psm != null)
psm.OnAnyPrizeResult -= OnPrizeFinished;
if (debugMode)
Debug.Log($"[LevelFinish] Приз «{type}» завершён (успех: {success}). Переход на следующий уровень.");
GameManager.Instance.NextLevel();
}
/// <summary>
/// Выдает приз через PrizeSystemManager — тип приза берётся из JSON-базы для текущего уровня.
/// </summary>
private void GivePrize()
{
if (debugMode)
Debug.Log("[LevelFinish] Выдаю приз игроку!");
if (PrizeSystemManager.Instance != null)
PrizeSystemManager.Instance.GivePrizeForCurrentLevel();
else
{
if (debugMode)
Debug.LogWarning("[LevelFinish] PrizeSystemManager не найден.");
// Если менеджер не найден — переходим сразу
_waitingForPrize = false;
GameManager.Instance.NextLevel();
}
}
/// <summary>
/// Сбрасывает состояние выдачи приза (для повторного использования).
/// </summary>
public void ResetPrize()
{
_prizeGiven = false;
_waitingForPrize = false;
}
private void OnDestroy()
{
if (_waitingForPrize)
{
var psm = PrizeSystemManager.Instance;
if (psm != null)
psm.OnAnyPrizeResult -= OnPrizeFinished;
}
}
#if UNITY_EDITOR
private void OnDrawGizmos()
{
// Визуализация зоны финиша в редакторе
Collider2D col = GetComponent<Collider2D>();
if (col != null)
{
Gizmos.color = enablePrizeOnFinish ? Color.green : Color.yellow;
Gizmos.DrawWireCube(col.bounds.center, col.bounds.size);
}
}
#endif
}
}