358 lines
12 KiB
C#
358 lines
12 KiB
C#
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<CloudPuff> puffs = new List<CloudPuff>();
|
|
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<CloudPuff> cloudPuffs = new List<CloudPuff>();
|
|
private List<RainCloud> rainClouds = new List<RainCloud>();
|
|
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<ParticleSystem>();
|
|
|
|
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<ParticleSystemRenderer>();
|
|
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<RainDirector>();
|
|
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<ParticleSystem>();
|
|
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<ParticleSystemRenderer>();
|
|
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;
|
|
}
|
|
}
|