using System.Collections; using System.Collections.Generic; using UnityEngine; public class MarsMesosphereEffects : MonoBehaviour { [Header("Пил")] public Material dustMaterial; public float planetRadius = 6.779f; public float mesosphereHeight = 3f; [Header("Метеорити")] public GameObject[] asteroidPrefabs; public GameObject explosionPrefab; public Material craterMaterial; public float spawnRadius = 80f; public float spawnInterval = 3f; [Range(0f, 1f)] public float mesosphereLevel = 1f; public float previousLevel = 1f; private ParticleSystem dustRingSystem; private List craters = new List(); private List dustDevils = new List(); private float spawnTimer = 0f; void Awake() { enabled = false; } public void InitState() { if (dustRingSystem != null) Destroy(dustRingSystem.gameObject); dustRingSystem = null; foreach (var c in craters) if (c != null) Destroy(c); craters.Clear(); foreach (var d in dustDevils) if (d != null) Destroy(d.gameObject); dustDevils.Clear(); mesosphereLevel = 1f; previousLevel = 1f; spawnTimer = 0f; CreateDustRing(); CreateDustDevils(); } void CreateDustRing() { GameObject obj = new GameObject("MarsDustRing"); obj.transform.parent = null; obj.transform.position = transform.position; dustRingSystem = obj.AddComponent(); var main = dustRingSystem.main; main.loop = true; main.playOnAwake = true; main.maxParticles = 8000; main.startLifetime = new ParticleSystem.MinMaxCurve(8f, 16f); main.startSpeed = new ParticleSystem.MinMaxCurve(1.5f, 4.0f); main.startSize = new ParticleSystem.MinMaxCurve(0.08f, 0.35f); main.startColor = new ParticleSystem.MinMaxGradient( new Color(0.85f, 0.45f, 0.15f, 0.5f), new Color(0.65f, 0.3f, 0.08f, 0.3f) ); main.simulationSpace = ParticleSystemSimulationSpace.World; main.gravityModifier = 0f; var emission = dustRingSystem.emission; emission.rateOverTime = 300f; var shape = dustRingSystem.shape; shape.enabled = true; shape.shapeType = ParticleSystemShapeType.Sphere; shape.radius = planetRadius + mesosphereHeight; shape.radiusThickness = 0.4f; var vel = dustRingSystem.velocityOverLifetime; vel.enabled = true; vel.space = ParticleSystemSimulationSpace.World; vel.x = new ParticleSystem.MinMaxCurve(-0.5f, 0.5f); vel.y = new ParticleSystem.MinMaxCurve(-0.3f, 0.3f); vel.z = new ParticleSystem.MinMaxCurve(-0.5f, 0.5f); vel.orbitalX = new ParticleSystem.MinMaxCurve(0f, 0f); vel.orbitalY = new ParticleSystem.MinMaxCurve(1.5f, 2.5f); vel.orbitalZ = new ParticleSystem.MinMaxCurve(0f, 0f); var sizeOverLifetime = dustRingSystem.sizeOverLifetime; sizeOverLifetime.enabled = true; AnimationCurve sizeCurve = new AnimationCurve( new Keyframe(0f, 0f), new Keyframe(0.1f, 1f), new Keyframe(0.8f, 0.8f), new Keyframe(1f, 0f) ); sizeOverLifetime.size = new ParticleSystem.MinMaxCurve(1f, sizeCurve); var colorOverLifetime = dustRingSystem.colorOverLifetime; colorOverLifetime.enabled = true; Gradient gradient = new Gradient(); gradient.SetKeys( new GradientColorKey[] { new GradientColorKey(new Color(0.85f, 0.45f, 0.15f), 0f), new GradientColorKey(new Color(0.65f, 0.3f, 0.08f), 0.5f), new GradientColorKey(new Color(0.45f, 0.2f, 0.05f), 1f) }, new GradientAlphaKey[] { new GradientAlphaKey(0f, 0f), new GradientAlphaKey(0.5f, 0.15f), new GradientAlphaKey(0.3f, 0.7f), new GradientAlphaKey(0f, 1f) } ); colorOverLifetime.color = new ParticleSystem.MinMaxGradient(gradient); var noise = dustRingSystem.noise; noise.enabled = true; noise.strength = 0.8f; noise.frequency = 0.4f; noise.scrollSpeed = 0.2f; noise.octaveCount = 2; var renderer = dustRingSystem.GetComponent(); renderer.renderMode = ParticleSystemRenderMode.Billboard; renderer.sortingFudge = 3f; if (dustMaterial != null) renderer.material = dustMaterial; dustRingSystem.Play(); } void CreateDustDevils() { int count = 7; for (int i = 0; i < count; i++) { Vector3 dir = Random.onUnitSphere; Vector3 pos = transform.position + dir * planetRadius; GameObject obj = new GameObject("DustDevil_" + i); obj.transform.parent = null; obj.transform.position = pos; obj.transform.up = dir; ParticleSystem ps = obj.AddComponent(); var main = ps.main; main.loop = true; main.playOnAwake = true; main.maxParticles = 500; main.startLifetime = new ParticleSystem.MinMaxCurve(3f, 6f); main.startSpeed = new ParticleSystem.MinMaxCurve(2f, 5f); main.startSize = new ParticleSystem.MinMaxCurve(0.12f, 0.4f); main.startColor = new ParticleSystem.MinMaxGradient( new Color(0.9f, 0.5f, 0.2f, 0.6f), new Color(0.7f, 0.35f, 0.1f, 0.4f) ); main.simulationSpace = ParticleSystemSimulationSpace.World; main.gravityModifier = 0f; var emission = ps.emission; emission.rateOverTime = 80f; var shape = ps.shape; shape.enabled = true; shape.shapeType = ParticleSystemShapeType.Cone; shape.angle = 25f; shape.radius = 0.6f; shape.radiusThickness = 0.5f; var vel = ps.velocityOverLifetime; vel.enabled = true; vel.space = ParticleSystemSimulationSpace.Local; vel.x = new ParticleSystem.MinMaxCurve(-1.0f, 1.0f); vel.y = new ParticleSystem.MinMaxCurve(2.0f, 5.0f); vel.z = new ParticleSystem.MinMaxCurve(-1.0f, 1.0f); vel.orbitalX = new ParticleSystem.MinMaxCurve(0f, 0f); vel.orbitalY = new ParticleSystem.MinMaxCurve(8f, 12f); vel.orbitalZ = new ParticleSystem.MinMaxCurve(0f, 0f); var sizeOverLifetime = ps.sizeOverLifetime; sizeOverLifetime.enabled = true; AnimationCurve sizeCurve = new AnimationCurve( new Keyframe(0f, 0.2f), new Keyframe(0.3f, 1f), new Keyframe(1f, 0f) ); sizeOverLifetime.size = new ParticleSystem.MinMaxCurve(1f, sizeCurve); var colorOverLifetime = ps.colorOverLifetime; colorOverLifetime.enabled = true; Gradient gradient = new Gradient(); gradient.SetKeys( new GradientColorKey[] { new GradientColorKey(new Color(0.9f, 0.5f, 0.2f), 0f), new GradientColorKey(new Color(0.7f, 0.35f, 0.1f), 0.5f), new GradientColorKey(new Color(0.5f, 0.25f, 0.08f), 1f) }, new GradientAlphaKey[] { new GradientAlphaKey(0.6f, 0f), new GradientAlphaKey(0.4f, 0.5f), new GradientAlphaKey(0f, 1f) } ); colorOverLifetime.color = new ParticleSystem.MinMaxGradient(gradient); var noise = ps.noise; noise.enabled = true; noise.strength = 0.7f; noise.frequency = 1.2f; noise.scrollSpeed = 0.6f; noise.octaveCount = 2; var renderer = ps.GetComponent(); renderer.renderMode = ParticleSystemRenderMode.Billboard; renderer.sortingFudge = 4f; if (dustMaterial != null) renderer.material = dustMaterial; ps.Play(); dustDevils.Add(ps); StartCoroutine(RotateDustDevil(obj.transform, dir)); } } IEnumerator RotateDustDevil(Transform devil, Vector3 surfaceNormal) { float orbitSpeed = Random.Range(3f, 8f); Vector3 orbitAxis = surfaceNormal; while (devil != null) { devil.RotateAround(transform.position, orbitAxis, orbitSpeed * Time.deltaTime); yield return null; } } void UpdateDustRing() { if (dustRingSystem == null) return; var emission = dustRingSystem.emission; var main = dustRingSystem.main; if (mesosphereLevel >= 0.7f) { float t = Mathf.InverseLerp(1f, 0.7f, mesosphereLevel); emission.rateOverTime = Mathf.Lerp(300f, 120f, t); main.startColor = new ParticleSystem.MinMaxGradient( new Color(0.85f, 0.45f, 0.15f, Mathf.Lerp(0.5f, 0.35f, t)), new Color(0.65f, 0.3f, 0.08f, Mathf.Lerp(0.3f, 0.2f, t)) ); } else if (mesosphereLevel >= 0.5f) { float t = Mathf.InverseLerp(0.7f, 0.5f, mesosphereLevel); emission.rateOverTime = Mathf.Lerp(120f, 50f, t); main.startColor = new ParticleSystem.MinMaxGradient( new Color(0.85f, 0.45f, 0.15f, Mathf.Lerp(0.35f, 0.15f, t)), new Color(0.65f, 0.3f, 0.08f, Mathf.Lerp(0.2f, 0.08f, t)) ); } else if (mesosphereLevel >= 0.3f) { float t = Mathf.InverseLerp(0.5f, 0.3f, mesosphereLevel); emission.rateOverTime = Mathf.Lerp(50f, 5f, t); main.startColor = new ParticleSystem.MinMaxGradient( new Color(0.85f, 0.45f, 0.15f, Mathf.Lerp(0.15f, 0.03f, t)), new Color(0.65f, 0.3f, 0.08f, Mathf.Lerp(0.08f, 0.01f, t)) ); } else { emission.rateOverTime = 0f; } } void UpdateDustDevils() { foreach (var ps in dustDevils) { if (ps == null) continue; var emission = ps.emission; emission.rateOverTime = mesosphereLevel >= 0.3f ? Mathf.Lerp(0f, 80f, mesosphereLevel) : 0f; } } void UpdateAsteroids() { if (mesosphereLevel >= 1f) return; if (mesosphereLevel <= 0f) return; spawnTimer += Time.deltaTime; float adjustedInterval; if (mesosphereLevel >= 0.7f) adjustedInterval = spawnInterval; else if (mesosphereLevel >= 0.5f) adjustedInterval = spawnInterval * 0.6f; else if (mesosphereLevel >= 0.3f) adjustedInterval = spawnInterval * 0.3f; else adjustedInterval = 0.5f; if (spawnTimer >= adjustedInterval) { spawnTimer = 0f; SpawnAsteroid(); } } void SpawnAsteroid() { if (asteroidPrefabs == null || asteroidPrefabs.Length == 0) return; Vector3 direction = Random.onUnitSphere; Vector3 spawnPos = transform.position + direction * spawnRadius; Vector3 flyDir = -direction; GameObject prefab = asteroidPrefabs[Random.Range(0, asteroidPrefabs.Length)]; GameObject asteroid = Instantiate(prefab, spawnPos, Random.rotation); asteroid.transform.localScale = Vector3.one * Random.Range(0.2f, 0.6f); StartCoroutine(MoveAsteroid(asteroid, flyDir)); } IEnumerator MoveAsteroid(GameObject asteroid, Vector3 flyDir) { float speed = Random.Range(4f, 8f); while (asteroid != null) { asteroid.transform.position += flyDir * speed * Time.deltaTime; asteroid.transform.Rotate(Vector3.one * 60f * Time.deltaTime); float distFromCenter = Vector3.Distance(asteroid.transform.position, transform.position); if (distFromCenter <= planetRadius + 0.2f) { Vector3 hitPos = transform.position + (-flyDir) * planetRadius; if (explosionPrefab != null) { GameObject exp = Instantiate(explosionPrefab, hitPos, Quaternion.identity); exp.transform.localScale = Vector3.one * Random.Range(0.2f, 0.5f); Destroy(exp, 3f); } SpawnCrater(hitPos, -flyDir); Destroy(asteroid); yield break; } if (distFromCenter > spawnRadius * 2f) { Destroy(asteroid); yield break; } yield return null; } } void SpawnCrater(Vector3 pos, Vector3 flyDir) { if (craterMaterial == null) return; Vector3 center = transform.position; Vector3 dirFromCenter = (pos - center).normalized; Vector3 surfacePos = center + dirFromCenter * (planetRadius + 0.02f); GameObject crater = GameObject.CreatePrimitive(PrimitiveType.Quad); crater.name = "Crater"; crater.transform.position = surfacePos; crater.transform.rotation = Quaternion.LookRotation(-dirFromCenter, Vector3.up); float size = Random.Range(0.3f, 0.8f); crater.transform.localScale = new Vector3(size, size, size); Destroy(crater.GetComponent()); Renderer r = crater.GetComponent(); r.material = craterMaterial; r.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; craters.Add(crater); } void Update() { if (!Application.isPlaying) return; if (mesosphereLevel >= 1f && previousLevel < 1f) InitState(); previousLevel = mesosphereLevel; UpdateDustRing(); UpdateDustDevils(); UpdateAsteroids(); } public void CleanUp() { if (dustRingSystem != null) Destroy(dustRingSystem.gameObject); dustRingSystem = null; foreach (var c in craters) if (c != null) Destroy(c); craters.Clear(); foreach (var d in dustDevils) if (d != null) Destroy(d.gameObject); dustDevils.Clear(); enabled = false; } }