using UnityEngine; namespace DanroJump.Vfx { /// /// Служба визуальных эффектов, программно создающая и настраивающая системы частиц Unity. /// Позволяет избежать зависимости от префабов в редакторе и обеспечивает высокую переносимость. /// public sealed class GameVfxService : IVfxService { public void SpawnJumpEffect(Vector3 position) { var go = new GameObject("VFX_Jump"); go.transform.position = position; var ps = go.AddComponent(); 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(); 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(); 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(); 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(); 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); } } }