- Оптимизировано закрытие COM-системы: вызов ReadLine вынесен из-под блокировки во избежание зависания главного потока Unity Editor при выходе из игры или выгрузке сцены. - Реализован контур безопасности: доступ к меню настроек теперь заблокирован за вводом PIN-кода "1234" с использованием существующего экранного модального ввода ServiceTextInputModalWindow. - Создана и интегрирована централизованная служба визуальных эффектов IVfxService / GameVfxService. Программно генерируются и воспроизводятся эффекты частиц для автопрыжка, сбора монет и гибели персонажа.
198 lines
8.8 KiB
C#
198 lines
8.8 KiB
C#
using UnityEngine;
|
||
|
||
namespace DanroJump.Vfx
|
||
{
|
||
/// <summary>
|
||
/// Служба визуальных эффектов, программно создающая и настраивающая системы частиц Unity.
|
||
/// Позволяет избежать зависимости от префабов в редакторе и обеспечивает высокую переносимость.
|
||
/// </summary>
|
||
public sealed class GameVfxService : IVfxService
|
||
{
|
||
public void SpawnJumpEffect(Vector3 position)
|
||
{
|
||
var go = new GameObject("VFX_Jump");
|
||
go.transform.position = position;
|
||
var ps = go.AddComponent<ParticleSystem>();
|
||
|
||
var main = ps.main;
|
||
main.startColor = new Color(0.9f, 0.9f, 0.9f, 0.5f);
|
||
main.startSize = new ParticleSystem.MinMaxCurve(0.08f, 0.22f);
|
||
main.startSpeed = new ParticleSystem.MinMaxCurve(1.5f, 3.5f);
|
||
main.startLifetime = new ParticleSystem.MinMaxCurve(0.2f, 0.45f);
|
||
main.duration = 0.25f;
|
||
main.loop = false;
|
||
main.gravityModifier = 0.6f;
|
||
|
||
var shape = ps.shape;
|
||
shape.shapeType = ParticleSystemShapeType.Cone;
|
||
shape.angle = 35f;
|
||
shape.radius = 0.15f;
|
||
shape.rotation = new Vector3(90f, 0f, 0f); // Направление вниз под ноги
|
||
|
||
var emission = ps.emission;
|
||
emission.rateOverTime = 0;
|
||
emission.SetBursts(new ParticleSystem.Burst[] { new ParticleSystem.Burst(0f, 12) });
|
||
|
||
var colorOverLifetime = ps.colorOverLifetime;
|
||
colorOverLifetime.enabled = true;
|
||
var gradient = new Gradient();
|
||
gradient.SetKeys(
|
||
new GradientColorKey[] { new GradientColorKey(Color.white, 0f), new GradientColorKey(Color.white, 1f) },
|
||
new GradientAlphaKey[] { new GradientAlphaKey(0.6f, 0f), new GradientAlphaKey(0f, 1f) }
|
||
);
|
||
colorOverLifetime.color = gradient;
|
||
|
||
ps.Play();
|
||
Object.Destroy(go, main.duration + main.startLifetime.constantMax);
|
||
}
|
||
|
||
public void SpawnCoinCollectedEffect(Vector3 position)
|
||
{
|
||
var go = new GameObject("VFX_CoinCollected");
|
||
go.transform.position = position;
|
||
var ps = go.AddComponent<ParticleSystem>();
|
||
|
||
var main = ps.main;
|
||
main.startColor = new Color(1.0f, 0.85f, 0.0f, 0.9f); // Золотой цвет
|
||
main.startSize = new ParticleSystem.MinMaxCurve(0.1f, 0.25f);
|
||
main.startSpeed = new ParticleSystem.MinMaxCurve(2f, 4f);
|
||
main.startLifetime = new ParticleSystem.MinMaxCurve(0.3f, 0.6f);
|
||
main.duration = 0.3f;
|
||
main.loop = false;
|
||
main.gravityModifier = -0.2f; // Легкий подъем вверх
|
||
|
||
var shape = ps.shape;
|
||
shape.shapeType = ParticleSystemShapeType.Sphere;
|
||
shape.radius = 0.1f;
|
||
|
||
var emission = ps.emission;
|
||
emission.rateOverTime = 0;
|
||
emission.SetBursts(new ParticleSystem.Burst[] { new ParticleSystem.Burst(0f, 18) });
|
||
|
||
var colorOverLifetime = ps.colorOverLifetime;
|
||
colorOverLifetime.enabled = true;
|
||
var gradient = new Gradient();
|
||
gradient.SetKeys(
|
||
new GradientColorKey[] { new GradientColorKey(new Color(1f, 0.9f, 0.2f), 0f), new GradientColorKey(new Color(1f, 0.5f, 0f), 1f) },
|
||
new GradientAlphaKey[] { new GradientAlphaKey(0.9f, 0f), new GradientAlphaKey(0f, 1f) }
|
||
);
|
||
colorOverLifetime.color = gradient;
|
||
|
||
ps.Play();
|
||
Object.Destroy(go, main.duration + main.startLifetime.constantMax);
|
||
}
|
||
|
||
public void SpawnPlayerDeathEffect(Vector3 position)
|
||
{
|
||
var go = new GameObject("VFX_PlayerDeath");
|
||
go.transform.position = position;
|
||
var ps = go.AddComponent<ParticleSystem>();
|
||
|
||
var main = ps.main;
|
||
main.startColor = new Color(0.8f, 0.1f, 0.1f, 0.8f); // Красный / серый взрыв
|
||
main.startSize = new ParticleSystem.MinMaxCurve(0.15f, 0.35f);
|
||
main.startSpeed = new ParticleSystem.MinMaxCurve(3f, 7f);
|
||
main.startLifetime = new ParticleSystem.MinMaxCurve(0.4f, 0.8f);
|
||
main.duration = 0.5f;
|
||
main.loop = false;
|
||
main.gravityModifier = 0.8f;
|
||
|
||
var shape = ps.shape;
|
||
shape.shapeType = ParticleSystemShapeType.Sphere;
|
||
shape.radius = 0.25f;
|
||
|
||
var emission = ps.emission;
|
||
emission.rateOverTime = 0;
|
||
emission.SetBursts(new ParticleSystem.Burst[] { new ParticleSystem.Burst(0f, 35) });
|
||
|
||
var colorOverLifetime = ps.colorOverLifetime;
|
||
colorOverLifetime.enabled = true;
|
||
var gradient = new Gradient();
|
||
gradient.SetKeys(
|
||
new GradientColorKey[] { new GradientColorKey(new Color(0.9f, 0.2f, 0.2f), 0f), new GradientColorKey(new Color(0.3f, 0.3f, 0.3f), 1f) },
|
||
new GradientAlphaKey[] { new GradientAlphaKey(0.9f, 0f), new GradientAlphaKey(0f, 1f) }
|
||
);
|
||
colorOverLifetime.color = gradient;
|
||
|
||
ps.Play();
|
||
Object.Destroy(go, main.duration + main.startLifetime.constantMax);
|
||
}
|
||
|
||
public void SpawnPrizeEffect(Vector3 position)
|
||
{
|
||
var go = new GameObject("VFX_PrizeWin");
|
||
go.transform.position = position;
|
||
var ps = go.AddComponent<ParticleSystem>();
|
||
|
||
var main = ps.main;
|
||
main.startColor = Color.white; // Конфетти будут разных цветов
|
||
main.startSize = new ParticleSystem.MinMaxCurve(0.12f, 0.28f);
|
||
main.startSpeed = new ParticleSystem.MinMaxCurve(4f, 8f);
|
||
main.startLifetime = new ParticleSystem.MinMaxCurve(0.6f, 1.2f);
|
||
main.duration = 0.8f;
|
||
main.loop = false;
|
||
main.gravityModifier = 0.4f;
|
||
|
||
var shape = ps.shape;
|
||
shape.shapeType = ParticleSystemShapeType.Hemisphere; // Разлет вверх полусферой
|
||
shape.radius = 0.3f;
|
||
shape.rotation = new Vector3(-90f, 0f, 0f); // Поворот вверх
|
||
|
||
var emission = ps.emission;
|
||
emission.rateOverTime = 0;
|
||
emission.SetBursts(new ParticleSystem.Burst[] { new ParticleSystem.Burst(0f, 50) });
|
||
|
||
// Добавим смену цветов
|
||
var colorBySpeed = ps.colorBySpeed; // Используем градиент для создания разноцветных конфетти
|
||
var colorOverLifetime = ps.colorOverLifetime;
|
||
colorOverLifetime.enabled = true;
|
||
|
||
// Настроим случайный цвет при рождении через градиент с множеством ключей или Random Between Two Colors
|
||
main.startColor = new ParticleSystem.MinMaxGradient(
|
||
new Color(0.2f, 0.6f, 1.0f), // Голубой
|
||
new Color(1.0f, 0.2f, 0.6f) // Розовый
|
||
);
|
||
|
||
ps.Play();
|
||
Object.Destroy(go, main.duration + main.startLifetime.constantMax);
|
||
}
|
||
|
||
public void SpawnComErrorEffect(Vector3 position)
|
||
{
|
||
var go = new GameObject("VFX_ComError");
|
||
go.transform.position = position;
|
||
var ps = go.AddComponent<ParticleSystem>();
|
||
|
||
var main = ps.main;
|
||
main.startColor = new Color(1.0f, 0.3f, 0.0f, 0.9f); // Оранжевые тревожные искры
|
||
main.startSize = new ParticleSystem.MinMaxCurve(0.06f, 0.18f);
|
||
main.startSpeed = new ParticleSystem.MinMaxCurve(3f, 6f);
|
||
main.startLifetime = new ParticleSystem.MinMaxCurve(0.25f, 0.5f);
|
||
main.duration = 0.4f;
|
||
main.loop = false;
|
||
main.gravityModifier = 0.3f;
|
||
|
||
var shape = ps.shape;
|
||
shape.shapeType = ParticleSystemShapeType.Cone;
|
||
shape.angle = 60f;
|
||
shape.radius = 0.1f;
|
||
|
||
var emission = ps.emission;
|
||
emission.rateOverTime = 0;
|
||
emission.SetBursts(new ParticleSystem.Burst[] { new ParticleSystem.Burst(0f, 20) });
|
||
|
||
var colorOverLifetime = ps.colorOverLifetime;
|
||
colorOverLifetime.enabled = true;
|
||
var gradient = new Gradient();
|
||
gradient.SetKeys(
|
||
new GradientColorKey[] { new GradientColorKey(new Color(1f, 0.5f, 0f), 0f), new GradientColorKey(new Color(0.8f, 0.1f, 0f), 1f) },
|
||
new GradientAlphaKey[] { new GradientAlphaKey(0.9f, 0f), new GradientAlphaKey(0f, 1f) }
|
||
);
|
||
colorOverLifetime.color = gradient;
|
||
|
||
ps.Play();
|
||
Object.Destroy(go, main.duration + main.startLifetime.constantMax);
|
||
}
|
||
}
|
||
}
|