- добавил частицы при смерти игрока - Временно включил функцию выбора уровня
173 lines
7.4 KiB
C#
173 lines
7.4 KiB
C#
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using UnityEngine.VFX;
|
||
|
||
namespace RR.Game2D.Behaviour
|
||
{
|
||
/// <summary>
|
||
/// Пул объектов визуальных эффектов для переиспользования VFX и оптимизации производительности.
|
||
/// </summary>
|
||
public class VFXPool : MonoBehaviour
|
||
{
|
||
public static VFXPool Instance { get; private set; }
|
||
|
||
[SerializeField] private int poolSize = 32;
|
||
[SerializeField] private float defaultLifetime = 2f; // время жизни эффекта по умолчанию (сек)
|
||
|
||
private Queue<GameObject> _pool;
|
||
|
||
private void Awake()
|
||
{
|
||
// ---- Singleton ----
|
||
if (Instance != null && Instance != this)
|
||
{
|
||
Destroy(gameObject);
|
||
return;
|
||
}
|
||
|
||
Instance = this;
|
||
// -------------------
|
||
|
||
// Инициализируем очередь для хранения свободных VFX объектов
|
||
_pool = new Queue<GameObject>();
|
||
|
||
// Предварительно создаем VFX объекты для пула
|
||
for (int i = 0; i < poolSize; i++)
|
||
{
|
||
GameObject vfxGameObject = new GameObject($"VFX_{i}");
|
||
vfxGameObject.AddComponent<VisualEffect>();
|
||
// Созданные объекты сразу не активны в пуле
|
||
vfxGameObject.SetActive(false);
|
||
vfxGameObject.transform.SetParent(transform);
|
||
_pool.Enqueue(vfxGameObject);
|
||
}
|
||
}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
// Если уничтожается текущий активный экземпляр, сбрасываем ссылку
|
||
if (Instance == this)
|
||
{
|
||
Instance = null;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Получить VFX объект из пула (без автоматического запуска)
|
||
/// </summary>
|
||
/// <param name="vfxAsset">Ассет визуального эффекта для применения</param>
|
||
/// <returns>GameObject с компонентом VisualEffect или null, если не удалось получить</returns>
|
||
private GameObject Get(VisualEffectAsset vfxAsset)
|
||
{
|
||
GameObject vfxInstance;
|
||
|
||
// Проверяем, есть ли свободные объекты в пуле
|
||
if (_pool.Count > 0)
|
||
{
|
||
vfxInstance = _pool.Dequeue();
|
||
vfxInstance.SetActive(true);
|
||
|
||
VisualEffect currentVFX = vfxInstance.GetComponent<VisualEffect>();
|
||
// Если текущий ассет не совпадает с запрашиваемым, заменяем его и реинициализируем
|
||
if (currentVFX.visualEffectAsset != vfxAsset)
|
||
{
|
||
currentVFX.Stop();
|
||
currentVFX.visualEffectAsset = vfxAsset;
|
||
currentVFX.Reinit();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// Пул пуст, создаем новый VFX объект
|
||
vfxInstance = new GameObject($"VFX_{_pool.Count}");
|
||
VisualEffect vfx = vfxInstance.AddComponent<VisualEffect>();
|
||
vfx.visualEffectAsset = vfxAsset;
|
||
vfxInstance.transform.SetParent(transform);
|
||
vfxInstance.SetActive(true);
|
||
}
|
||
|
||
// Сбрасываем поворот
|
||
if (vfxInstance)
|
||
{
|
||
vfxInstance.transform.rotation = Quaternion.identity;
|
||
}
|
||
|
||
return vfxInstance;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Воспроизвести VFX из пула и автоматически вернуть его позже.
|
||
/// </summary>
|
||
/// <param name="vfxAsset">Ассет визуального эффекта</param>
|
||
/// <param name="position">Позиция для эффекта</param>
|
||
/// <param name="lifetime">Время жизни эффекта в секундах (если null — будет использовано defaultLifetime)</param>
|
||
public GameObject Spawn(VisualEffectAsset vfxAsset, Vector3 position, float? lifetime = null)
|
||
{
|
||
float life = lifetime ?? defaultLifetime;
|
||
GameObject vfxInstance = Get(vfxAsset);
|
||
if (vfxInstance == null) return null;
|
||
|
||
vfxInstance.transform.position = position;
|
||
|
||
VisualEffect visualEffect = vfxInstance.GetComponent<VisualEffect>();
|
||
// Удостоверимся, что эффект корректно инициализирован и запущен
|
||
visualEffect.Reinit();
|
||
visualEffect.Play();
|
||
|
||
// Запускаем корутину, которая вернёт объект в пул после окончания времени жизни
|
||
StartCoroutine(ReturnAfterCoroutine(vfxInstance, life));
|
||
|
||
return vfxInstance;
|
||
}
|
||
|
||
public GameObject Spawn(VisualEffectAsset vfxAsset, Transform newParentTransform, float? lifetime = null)
|
||
{
|
||
GameObject vfxInstance = Spawn(vfxAsset, newParentTransform.position, lifetime);
|
||
vfxInstance.transform.SetParent(newParentTransform);
|
||
|
||
return vfxInstance;
|
||
}
|
||
|
||
private IEnumerator ReturnAfterCoroutine(GameObject vfxInstance, float seconds)
|
||
{
|
||
// Ждём указанное время. Можно заменить на более точный механизм при наличии событий от VFXGraph.
|
||
yield return new WaitForSeconds(seconds);
|
||
|
||
// Перед возвратом уверенно останавливаем эффект
|
||
VisualEffect visualEffect = vfxInstance.GetComponent<VisualEffect>();
|
||
if (visualEffect) visualEffect.Stop();
|
||
|
||
// Возвращаем в пул
|
||
Return(vfxInstance);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Вернуть VFX объект обратно в пул для повторного использования
|
||
/// </summary>
|
||
/// <param name="vfxInstance">VFX объект для возврата в пул</param>
|
||
private void Return(GameObject vfxInstance)
|
||
{
|
||
if (vfxInstance == null) return;
|
||
|
||
// Явно устанавливаем родителем пул, чтобы избежать захламления сцены
|
||
vfxInstance.transform.SetParent(this.transform);
|
||
|
||
VisualEffect visualEffect = vfxInstance.GetComponent<VisualEffect>();
|
||
if (visualEffect) visualEffect.Stop();
|
||
|
||
// Если пул не переполнен, деактивируем и кладём в очередь
|
||
if (_pool.Count < poolSize)
|
||
{
|
||
vfxInstance.SetActive(false);
|
||
_pool.Enqueue(vfxInstance);
|
||
}
|
||
else
|
||
{
|
||
// Пул переполнен, уничтожаем объект
|
||
Debug.Log("VFX Pool is full, destroying returned VFX instance.");
|
||
Destroy(vfxInstance);
|
||
}
|
||
}
|
||
}
|
||
} |