using System.Collections; using System.Collections.Generic; using UnityEngine; public class TroposphereEffects : MonoBehaviour { [Header("Матеріали хмар")] public Material[] cloudMaterials; [Header("Дощ")] public GameObject rainPrefab; [Header("Хмари")] public int cloudGroupCount = 20; public int particlesPerCloud = 4; public float cloudGroupSpread = 0.4f; public float cloudMinSize = 0.8f; public float cloudMaxSize = 1.8f; public float cloudOrbitSpeed = 0.5f; [Header("Дощові хмари")] public int rainCloudGroupCount = 5; public float rainDuration = 15f; public float rainPause = 10f; private float cloudRadius; private Vector3 planetCenter; [Header("Туман")] public Material fogMaterial; private class RainCloud { public List puffs = new List(); public GameObject rainInstance; public GameObject fogInstance; public float timer; public bool isRaining; public bool isFogging; public Vector3 position; } private class CloudPuff { public Transform transform; public float orbitSpeed; public Vector3 orbitAxis; } private List cloudPuffs = new List(); private List rainClouds = new List(); private Transform cloudRoot; void Start() { planetCenter = this.transform.position; cloudRadius = this.transform.lossyScale.x * 0.5f * 0.95f; SpawnCloudGroups(); SpawnRainClouds(); } void SpawnCloudGroups() { cloudRoot = new GameObject("CloudParticles").transform; cloudRoot.parent = this.transform; cloudRoot.localPosition = Vector3.zero; for (int i = 0; i < cloudGroupCount; i++) { Vector3 groupCenter = planetCenter + Random.onUnitSphere * cloudRadius; Vector3 toCenter = (planetCenter - groupCenter).normalized; Vector3 axis = Quaternion.AngleAxis(Random.Range(-20f, 20f), Random.onUnitSphere) * Vector3.up; float speed = cloudOrbitSpeed * Random.Range(0.7f, 1.3f); for (int j = 0; j < particlesPerCloud; j++) { Vector3 pos = groupCenter + (Vector3)Random.insideUnitSphere * cloudGroupSpread; CloudPuff puff = CreateCloudPuff(cloudRoot, pos, toCenter, axis, speed, false, i); cloudPuffs.Add(puff); } } } GameObject CreateFog(Vector3 position) { GameObject fogObj = new GameObject("Fog"); fogObj.transform.parent = cloudRoot; fogObj.transform.position = position; ParticleSystem ps = fogObj.AddComponent(); var main = ps.main; main.loop = true; main.playOnAwake = true; main.maxParticles = 80; main.startLifetime = new ParticleSystem.MinMaxCurve(10f, 16f); main.startSpeed = new ParticleSystem.MinMaxCurve(0.03f, 0.08f); main.startSize = new ParticleSystem.MinMaxCurve(0.2f, 0.6f); main.startColor = new ParticleSystem.MinMaxGradient( new Color(0.88f, 0.92f, 0.95f, 0.18f), new Color(0.95f, 0.97f, 1f, 0.09f) ); main.startRotation = new ParticleSystem.MinMaxCurve(0f, 360f * Mathf.Deg2Rad); main.simulationSpace = ParticleSystemSimulationSpace.World; var emission = ps.emission; emission.rateOverTime = 8f; var shape = ps.shape; shape.enabled = true; shape.shapeType = ParticleSystemShapeType.Sphere; shape.radius = cloudGroupSpread * 2.5f; shape.radiusThickness = 1f; var velocityOverLifetime = ps.velocityOverLifetime; velocityOverLifetime.enabled = true; velocityOverLifetime.space = ParticleSystemSimulationSpace.World; Vector3 tangent = Vector3.Cross((planetCenter - position).normalized, Vector3.up).normalized; velocityOverLifetime.x = new ParticleSystem.MinMaxCurve(tangent.x * 0.08f - 0.04f, tangent.x * 0.08f + 0.04f); velocityOverLifetime.y = new ParticleSystem.MinMaxCurve(-0.01f, 0.01f); velocityOverLifetime.z = new ParticleSystem.MinMaxCurve(tangent.z * 0.08f - 0.04f, tangent.z * 0.08f + 0.04f); var sizeOverLifetime = ps.sizeOverLifetime; sizeOverLifetime.enabled = true; AnimationCurve curve = new AnimationCurve(); curve.AddKey(0f, 0f); curve.AddKey(0.15f, 1f); curve.AddKey(0.75f, 0.85f); curve.AddKey(1f, 0f); sizeOverLifetime.size = new ParticleSystem.MinMaxCurve(1f, curve); var colorOverLifetime = ps.colorOverLifetime; colorOverLifetime.enabled = true; Gradient gradient = new Gradient(); gradient.SetKeys( new GradientColorKey[] { new GradientColorKey(new Color(0.88f, 0.92f, 0.95f), 0f), new GradientColorKey(new Color(0.95f, 0.97f, 1f), 0.5f), new GradientColorKey(new Color(0.88f, 0.92f, 0.95f), 1f) }, new GradientAlphaKey[] { new GradientAlphaKey(0f, 0f), new GradientAlphaKey(0.18f, 0.2f), new GradientAlphaKey(0.12f, 0.7f), new GradientAlphaKey(0f, 1f) } ); colorOverLifetime.color = new ParticleSystem.MinMaxGradient(gradient); var rotationOverLifetime = ps.rotationOverLifetime; rotationOverLifetime.enabled = true; rotationOverLifetime.z = new ParticleSystem.MinMaxCurve(-0.2f, 0.2f); var renderer = ps.GetComponent(); renderer.renderMode = ParticleSystemRenderMode.Billboard; renderer.sortingFudge = -3f; if (fogMaterial != null) renderer.material = fogMaterial; ps.Play(); return fogObj; } void SpawnRainClouds() { for (int i = 0; i < rainCloudGroupCount; i++) { RainCloud rc = CreateRainCloud(); rainClouds.Add(rc); } } RainCloud CreateRainCloud() { RainCloud rc = new RainCloud(); rc.position = planetCenter + Random.onUnitSphere * cloudRadius; rc.timer = Random.Range(0f, rainDuration); rc.isRaining = true; Vector3 toCenter = (planetCenter - rc.position).normalized; Vector3 axis = Quaternion.AngleAxis(Random.Range(-20f, 20f), Random.onUnitSphere) * Vector3.up; float speed = cloudOrbitSpeed * Random.Range(0.6f, 1.0f); for (int j = 0; j < particlesPerCloud; j++) { Vector3 pos = rc.position + (Vector3)Random.insideUnitSphere * cloudGroupSpread; CloudPuff puff = CreateCloudPuff(cloudRoot, pos, toCenter, axis, speed, true, j); rc.puffs.Add(puff); cloudPuffs.Add(puff); } if (rainPrefab != null) { Vector3 dirToCenter = (planetCenter - rc.position).normalized; Vector3 rainPos = rc.position + dirToCenter * (cloudGroupSpread + 0.9f); rc.rainInstance = Instantiate(rainPrefab, rainPos, Quaternion.identity); rc.rainInstance.transform.parent = cloudRoot; rc.rainInstance.transform.localScale = Vector3.one * 0.5f; RainDirector director = rc.rainInstance.AddComponent(); director.planetCenter = planetCenter; } return rc; } CloudPuff CreateCloudPuff(Transform parent, Vector3 pos, Vector3 toCenter, Vector3 axis, float speed, bool dark, int texIndex) { ParticleSystem ps = new GameObject("CloudPuff").AddComponent(); ps.transform.parent = parent; ps.transform.position = pos; var main = ps.main; main.loop = false; main.playOnAwake = true; main.maxParticles = 1; main.startLifetime = 999f; main.startSpeed = 0f; main.startSize = Random.Range(cloudMinSize, cloudMaxSize); main.startColor = dark ? new Color(Random.Range(0.1f, 0.3f), Random.Range(0.1f, 0.3f), Random.Range(0.1f, 0.3f), Random.Range(0.7f, 0.9f)) : new Color(Random.Range(0.88f, 1f), Random.Range(0.88f, 1f), 1f, Random.Range(0.55f, 0.8f)); main.simulationSpace = ParticleSystemSimulationSpace.Local; var emission = ps.emission; emission.rateOverTime = 0f; emission.SetBursts(new ParticleSystem.Burst[] { new ParticleSystem.Burst(0f, 1) }); var shape = ps.shape; shape.enabled = false; var renderer = ps.GetComponent(); renderer.renderMode = ParticleSystemRenderMode.Billboard; renderer.sortingFudge = -10f; if (cloudMaterials != null && cloudMaterials.Length > 0) { renderer.material = cloudMaterials[texIndex % cloudMaterials.Length]; } else { Material mat = new Material(Shader.Find("Universal Render Pipeline/Particles/Unlit")); mat.SetFloat("_Surface", 1f); mat.SetFloat("_Blend", 0f); mat.EnableKeyword("_SURFACE_TYPE_TRANSPARENT"); mat.renderQueue = 3001; mat.SetColor("_BaseColor", main.startColor.color); renderer.material = mat; } ps.Play(); return new CloudPuff { transform = ps.transform, orbitSpeed = speed, orbitAxis = axis }; } void Update() { if (!Application.isPlaying) return; Quaternion globalRotation = Quaternion.AngleAxis(cloudOrbitSpeed * Time.deltaTime, Vector3.up); foreach (CloudPuff puff in cloudPuffs) { if (puff.transform == null) continue; puff.transform.position = planetCenter + globalRotation * (puff.transform.position - planetCenter); } for (int i = 0; i < rainClouds.Count; i++) { RainCloud rc = rainClouds[i]; rc.timer -= Time.deltaTime; if (rc.isRaining && rc.timer <= 0f) { if (rc.rainInstance != null) Destroy(rc.rainInstance); rc.isRaining = false; rc.isFogging = true; rc.timer = 20f; Vector3 fogPos = rc.position + (planetCenter - rc.position).normalized * cloudGroupSpread * 1.5f; rc.fogInstance = CreateFog(fogPos); } else if (rc.isFogging && rc.timer <= 0f) { if (rc.fogInstance != null) Destroy(rc.fogInstance); rc.isFogging = false; rc.timer = rainPause; foreach (CloudPuff puff in rc.puffs) { if (puff.transform != null) Destroy(puff.transform.gameObject); cloudPuffs.Remove(puff); } } else if (!rc.isRaining && !rc.isFogging && rc.timer <= 0f) { foreach (CloudPuff puff in rc.puffs) cloudPuffs.Remove(puff); rainClouds[i] = CreateRainCloud(); } if (rc.rainInstance != null) rc.rainInstance.transform.position = planetCenter + globalRotation * (rc.rainInstance.transform.position - planetCenter); if (rc.fogInstance != null) rc.fogInstance.transform.position = planetCenter + globalRotation * (rc.fogInstance.transform.position - planetCenter); } } void DestroyRainCloud(RainCloud rc) { if (rc.rainInstance != null) Destroy(rc.rainInstance); foreach (CloudPuff puff in rc.puffs) { if (puff.transform != null) Destroy(puff.transform.gameObject); } } public void SetRainEnabled(bool enabled) { foreach (RainCloud rc in rainClouds) { if (rc.rainInstance != null) rc.rainInstance.SetActive(enabled); } } public void SetCloudsEnabled(bool enabled) { if (cloudRoot != null) cloudRoot.gameObject.SetActive(enabled); } void Awake() { enabled = false; } }