Danro/Assets/Scripts/Animations/EnemyAnimationEvents.cs
Danil Iarosh 78d7679e2b
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
feat(prizes, ui): complete Mar 24-Apr 2 sprint ahead of schedule
- завершен спринт 24 марта - 2 апреля с опережением плана и закрытием задач раньше срока
- расширена и стабилизирована система призов:
  добавлены и доработаны QR-tier конфиги, новые типы и модели данных,
  сохранение `qrCodes` в `prizes.json`, fallback-логика и синхронизация
  через `PrizeSystemManager`, `PrizeDatabase` и `LevelPrizeConfig`
- переработан flow настройки QR-призов:
  добавлены `QRCodeSettingsModal` и связанный UI-код,
  разнесены короткий текст приза и полный текст сообщения,
  добавлены шаблоны форматирования, корректная подстановка текста
  в QR и в UI-модалках, а также сохранение конфигурации между запусками
- доработан flow суперприза и текстовых настроек:
  добавлены fallback-правила показа, корректная обработка пустых строк
  и строк из одних пробелов, обновлены binders и показ текста в меню
- реализована и обновлена отдельная настройка витрины:
  добавлена `PrizeStandSettingsModal`, обновлена навигация строк,
  логика выбора ячейки и порогов очков, циклический выбор ячеек,
  ускорение изменения значений и исправления для keyboard/gamepad UX
- доработана игровая модалка витрины `PrizeStandModal`:
  добавлен вывод очков игрока, форматируемый текст счета,
  улучшено отображение ячеек и связанная логика выбора приза
- исправлен подсчет очков и интеграция с prize flow:
  `ScoreSystem` переведен на событийное обновление текущего счета,
  добавлены `CurrentScore`, `CurrentScoreChanged` и корректный display score,
  витрина и связанные UI-элементы теперь получают актуальные очки,
  а не нулевые или несвоевременные preview-значения
- переработаны модальные окна и навигация UI:
  улучшены `Modal`, `ModalManager`, `UIRowPointer`, `RulesModal`,
  `QRCodeModal`, `PrizeStandModal`, `LevelPrizeSettingsModal` и др.,
  чтобы фокус, указатель и submit работали консистентно без мыши
- обновлен win/prize UI:
  доработаны `WinBannerController`, `GameEndUIController`,
  `MainMenu`, `QRCodeUIController`, `TopPanelTextController` и настройки UI,
  улучшены тексты баннеров, отображение призов и итогового счета
- обновлены сцены и ассеты под новый flow:
  `MainMenu`, `Level UI`, prefab'ы строк настроек и кнопок,
  глобальные префабы, шрифты TMP, иконки, recovery-данные и ресурсы UI
- добавлены вспомогательные UI-компоненты и служебные скрипты:
  `ButtonTextFocusColor`, `SelectableDescriptionTarget`, `QRTier`
  и другие изменения, поддерживающие новый конфигурируемый prize UI
2026-04-01 12:47:17 +03:00

99 lines
3.8 KiB
C#

using System.Collections;
using UnityEngine;
using RR.Game2D.Behaviour;
using RR.Game2D.Behaviour.ScriptableObjects;
using RR.Game2D.Core.Managers;
using UnityEngine.VFX;
namespace RR.Game2D.Animations
{
public class EnemyAnimationEvents : MonoBehaviour, CreatureAnimationEvents
{
[SerializeField] private VisualEffectAsset deathVFX;
[SerializeField] private Vector3 deathVFXOffset = Vector3.zero;
private SFXAsset _stepSounds;
private SFXAsset _hurtSounds;
private Vector3 _vfxSpawnPoint;
private bool _deathScoreRegistered;
private void Awake()
{
// Загружаем и кэшируем звуковые эффекты из контроллера врага
UpdateSFX();
Collider2D col = GetComponent<Collider2D>();
// Учитываем поворот объекта при вычислении смещения
Vector3 rotatedOffset = transform.rotation * deathVFXOffset;
_vfxSpawnPoint = (col ? col.bounds.center : transform.position) + rotatedOffset;
}
public void UpdateSFX()
{
// Кэшируем ссылки на звуковые эффекты из контроллера врага
EnemyController controller = GetComponent<EnemyController>();
_stepSounds = controller.sfxAsset.stepSounds;
_hurtSounds = controller.sfxAsset.hurtSounds;
}
public void OnDeath() {}
public void OnJump() {}
public void OnDeathBegin()
{
// Проигрываем звук получения урона
if (_hurtSounds && _hurtSounds.soundEffects.Length > 0)
GameManager.Instance.Audio.PlayRandomSfxAt(_hurtSounds.soundEffects, transform.position);
// Переводим врага на слой "No Collision"
gameObject.layer = LayerMask.NameToLayer("No Collision");
// Получаем компоненты
Rigidbody2D rb = GetComponent<Rigidbody2D>();
Collider2D col = GetComponent<Collider2D>();
EnemyController controller = GetComponent<EnemyController>();
EnemyFireScript fireScript = GetComponent<EnemyFireScript>();
// Отключаем скрипты и коллайдер
if (controller) controller.enabled = false;
if (fireScript) fireScript.enabled = false;
if (col)
{
// Учитываем поворот объекта при вычислении смещения
Vector3 rotatedOffset = transform.rotation * deathVFXOffset;
_vfxSpawnPoint = col.bounds.center + rotatedOffset;
col.enabled = false;
}
if (!rb) return;
// Останавливаем физику
rb.linearVelocity = Vector2.zero;
rb.bodyType = RigidbodyType2D.Kinematic;
}
public void OnDeathEnd()
{
if (!_deathScoreRegistered)
{
ScoreSystem.Instance?.RegisterEnemyKilled();
_deathScoreRegistered = true;
}
// Создаем визуальный эффект смерти
if (deathVFX) VFXPool.Instance.Spawn(deathVFX, _vfxSpawnPoint, 1f);
// Уничтожаем врага
Destroy(gameObject);
}
public void OnStep()
{
// Проигрываем звук шага
if (_stepSounds && _stepSounds.soundEffects.Length > 0)
GameManager.Instance.Audio.PlayRandomSfxAt(_stepSounds.soundEffects, transform.position);
}
}
}