Files
ScienceLab.FrictionForce/Assets/Scripts/Rocket/RocketEffectsController.cs
2026-05-29 18:30:19 +03:00

491 lines
20 KiB
C#
Raw Blame History

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class RocketEffectsController : MonoBehaviour
{
[Header("犁增妖孺")]
[SerializeField] private Transform rocketRoot;
[Header("Skybox <20> 前秀姪孼<E5A7AA>")]
[SerializeField] private Material skyboxMaterial;
[SerializeField] private Light sunLight;
[Header("UI")]
[SerializeField] private Image vignetteUI;
private ParticleSystem _atmParticles;
private ParticleSystem _starParticles;
private ParticleSystem _speedLines;
private ParticleSystem _cloudParticles;
private ParticleSystem _heatParticles;
private ParticleSystem _debrisParticles;
private ParticleSystem _layer1Particles;
private ParticleSystem _layer2Particles;
private ParticleSystem _layer3Particles;
private ParticleSystem _galaxyParticles;
private ParticleSystem _nebulaParticles;
private ParticleSystem _meteorParticles;
private ParticleSystem _cosmicDustParticles;
private Light _engineLight;
private Light _rocketSpotLight;
private Color _startSkyTint;
private float _startAtmThickness;
private float _startExposure;
private float _startSunIntensity;
private string _currentPlanet = "헌佾<ED978C>";
private float[] _starVelByFuel = { -120f, -180f, -260f, -350f, -500f };
private int _currentFuelLevel;
public void Initialize(RocketFlightCore core)
{
_core = core;
CreateAllParticles();
}
private float _enginePulse;
private bool _isActive;
private RocketFlightCore _core;
public void StartFlight(string planetName, int fuelLevel, float shakeMultiplier)
{
_currentPlanet = planetName;
_currentFuelLevel = fuelLevel;
_isActive = true;
_enginePulse = 0f;
if (skyboxMaterial != null)
{
_startSkyTint = skyboxMaterial.GetColor("_SkyTint");
_startAtmThickness = skyboxMaterial.GetFloat("_AtmosphereThickness");
_startExposure = skyboxMaterial.GetFloat("_Exposure");
}
_startSunIntensity = sunLight != null ? sunLight.intensity : 1f;
_atmParticles.Play();
_speedLines.Play();
StartCoroutine(AtmosphereLayerFlash(planetName));
if (IsLightningPlanet(planetName))
StartCoroutine(LightningEffect());
}
public void StopFlight()
{
_isActive = false;
StopAllParticles();
}
public void ResetEffects(PlanetData pd)
{
_isActive = false;
StopAllParticles();
if (_engineLight != null) _engineLight.intensity = 0f;
if (_rocketSpotLight != null) _rocketSpotLight.intensity = 0f;
if (vignetteUI != null) vignetteUI.color = new Color(0f, 0f, 0f, 0f);
if (skyboxMaterial != null)
{
skyboxMaterial.SetFloat("_AtmosphereThickness", pd.atmosphereThickness);
skyboxMaterial.SetFloat("_Exposure", pd.exposure);
skyboxMaterial.SetColor("_SkyTint", pd.skyTint);
skyboxMaterial.SetColor("_GroundColor", pd.groundColor);
}
RenderSettings.fog = pd.hasFog;
if (pd.hasFog)
{
RenderSettings.fogDensity = pd.fogDensity;
RenderSettings.fogColor = pd.fogColor;
}
if (sunLight != null) sunLight.intensity = pd.sunLightIntensity;
}
private void Update()
{
if (!_isActive || _core == null) return;
_enginePulse += Time.deltaTime * 18f;
float pulse = Mathf.Sin(_enginePulse) * 0.5f + 0.5f;
float speedNorm = _core.GetSpeedNormalized();
float inAtm = 1f - _core.GetAtmosphereProgress();
float inSpace = _core.GetSpaceProgress();
float animTime = _core.AnimTime;
float maxHeight = GetApproxMaxHeight();
float atmosphereHeight = maxHeight * 0.35f;
float currentHeight = _core.CurrentHeight;
UpdateEngineLight(pulse, speedNorm);
UpdateSpotLight(inSpace, pulse);
UpdateVignette(speedNorm, _core.FuelCutoff);
UpdateAtmosphereParticles(inAtm, animTime, speedNorm, pulse);
UpdateSpaceParticles(inSpace, speedNorm);
UpdateLayerParticles(currentHeight, atmosphereHeight, inAtm);
UpdateSkybox(inAtm, inSpace, animTime);
}
private void UpdateEngineLight(float pulse, float speedNorm)
{
if (_engineLight == null || _core.FuelCutoff) return;
_engineLight.intensity = Mathf.Lerp(3f, 8f, pulse) * Mathf.Clamp01(speedNorm + 0.3f);
_engineLight.color = Color.Lerp(new Color(1f, 0.4f, 0.05f), new Color(1f, 0.85f, 0.4f), pulse);
_engineLight.range = Mathf.Lerp(8f, 16f, pulse);
}
private void UpdateSpotLight(float inSpace, float pulse)
{
if (_rocketSpotLight == null) return;
_rocketSpotLight.intensity = Mathf.Lerp(0f, 4f, inSpace);
_rocketSpotLight.color = Color.Lerp(new Color(0.8f, 0.9f, 1f), new Color(1f, 1f, 0.9f), pulse * 0.3f);
}
private void UpdateVignette(float speedNorm, bool fuelCutoff)
{
if (vignetteUI == null) return;
float targetAlpha = fuelCutoff ? 0f : speedNorm * 0.45f;
Color c = vignetteUI.color;
vignetteUI.color = new Color(0f, 0f, 0f, Mathf.Lerp(c.a, targetAlpha, Time.deltaTime * 3f));
}
private void UpdateAtmosphereParticles(float inAtm, float animTime, float speedNorm, float pulse)
{
if (_atmParticles != null)
{
var ae = _atmParticles.emission;
ae.rateOverTime = inAtm * 110f;
}
if (_cloudParticles != null)
{
float cloudFactor = (animTime > 1.5f && animTime < 5f)
? Mathf.Sin((animTime - 1.5f) / 3.5f * Mathf.PI) * 35f : 0f;
var ce = _cloudParticles.emission;
ce.rateOverTime = cloudFactor * inAtm;
if (cloudFactor > 1f && !_cloudParticles.isPlaying) _cloudParticles.Play();
}
if (_heatParticles != null)
{
var he = _heatParticles.emission;
he.rateOverTime = speedNorm * inAtm * 60f;
if (speedNorm > 0.1f && !_heatParticles.isPlaying) _heatParticles.Play();
}
if (_debrisParticles != null)
{
var deb = _debrisParticles.emission;
deb.rateOverTime = speedNorm * inAtm * 20f;
if (speedNorm > 0.05f && !_debrisParticles.isPlaying) _debrisParticles.Play();
}
}
private void UpdateSpaceParticles(float inSpace, float speedNorm)
{
if (_starParticles != null)
{
float starVelTarget = _starVelByFuel[Mathf.Clamp(_currentFuelLevel, 0, 4)];
float starSpeed = Mathf.Lerp(starVelTarget * 0.5f, starVelTarget * 1.2f, speedNorm);
var sv = _starParticles.velocityOverLifetime;
sv.y = new ParticleSystem.MinMaxCurve(starSpeed, starSpeed);
var se = _starParticles.emission;
float starRate = inSpace * 250f + speedNorm * 100f;
se.rateOverTime = starRate;
if (starRate > 5f && !_starParticles.isPlaying) _starParticles.Play();
}
if (_speedLines != null)
{
float starVelTarget = _starVelByFuel[Mathf.Clamp(_currentFuelLevel, 0, 4)];
var spe = _speedLines.emission;
spe.rateOverTime = speedNorm * (100f + _currentFuelLevel * 40f);
var spv = _speedLines.velocityOverLifetime;
float spVal = starVelTarget * 2f * Mathf.Max(speedNorm, 0.4f);
spv.y = new ParticleSystem.MinMaxCurve(spVal, spVal);
}
ApplySpaceSky(_currentPlanet, inSpace);
}
private void UpdateLayerParticles(float currentHeight, float atmosphereHeight, float inAtm)
{
float layer1T = Mathf.Clamp01((currentHeight - atmosphereHeight * 0.1f) / (atmosphereHeight * 0.25f));
float layer1End = Mathf.Clamp01((currentHeight - atmosphereHeight * 0.3f) / (atmosphereHeight * 0.1f));
float layer1Factor = Mathf.Clamp01(layer1T - layer1End) * inAtm;
float layer2T = Mathf.Clamp01((currentHeight - atmosphereHeight * 0.4f) / (atmosphereHeight * 0.2f));
float layer2End = Mathf.Clamp01((currentHeight - atmosphereHeight * 0.65f) / (atmosphereHeight * 0.1f));
float layer2Factor = Mathf.Clamp01(layer2T - layer2End) * inAtm;
float layer3T = Mathf.Clamp01((currentHeight - atmosphereHeight * 0.7f) / (atmosphereHeight * 0.2f));
float layer3End = Mathf.Clamp01((currentHeight - atmosphereHeight * 0.95f) / (atmosphereHeight * 0.05f));
float layer3Factor = Mathf.Clamp01(layer3T - layer3End) * inAtm;
if (_layer1Particles != null)
{
var l1e = _layer1Particles.emission;
l1e.rateOverTime = layer1Factor * 25f;
if (layer1Factor > 0.05f && !_layer1Particles.isPlaying) _layer1Particles.Play();
}
if (_layer2Particles != null)
{
var l2e = _layer2Particles.emission;
l2e.rateOverTime = layer2Factor * 18f;
if (layer2Factor > 0.05f && !_layer2Particles.isPlaying) _layer2Particles.Play();
}
if (_layer3Particles != null)
{
var l3e = _layer3Particles.emission;
l3e.rateOverTime = layer3Factor * 12f;
if (layer3Factor > 0.05f && !_layer3Particles.isPlaying) _layer3Particles.Play();
}
}
private void UpdateSkybox(float inAtm, float inSpace, float animTime)
{
if (skyboxMaterial == null) return;
float atmProgress = _core.GetAtmosphereProgress();
float spaceProgress = _core.GetSpaceProgress();
float horizonT = Mathf.Clamp01(atmProgress * 1.4f);
float skyT = Mathf.Clamp01(atmProgress * 1.1f);
float spaceT = Mathf.Clamp01(spaceProgress * 1.5f);
float t = Mathf.Max(skyT, spaceT);
skyboxMaterial.SetFloat("_AtmosphereThickness", Mathf.Lerp(_startAtmThickness, 0f, horizonT));
skyboxMaterial.SetFloat("_Exposure", Mathf.Lerp(_startExposure, 0.25f, t));
skyboxMaterial.SetColor("_SkyTint", Color.Lerp(_startSkyTint, Color.black, t));
if (sunLight != null)
sunLight.intensity = Mathf.Lerp(_startSunIntensity, 0.08f, t);
DynamicGI.UpdateEnvironment();
}
private void ApplySpaceSky(string planetName, float spaceT)
{
if (spaceT < 0.01f) return;
Color galaxyTint = GetGalaxyTint(planetName);
float galaxyRate = spaceT * 150f;
if (_galaxyParticles != null)
{
var gm = _galaxyParticles.main;
gm.startColor = new ParticleSystem.MinMaxGradient(
new Color(galaxyTint.r, galaxyTint.g, galaxyTint.b, 0.9f),
new Color(galaxyTint.r * 0.6f, galaxyTint.g * 0.6f, galaxyTint.b * 0.6f, 0.4f));
var ge = _galaxyParticles.emission;
ge.rateOverTime = galaxyRate;
if (galaxyRate > 1f && !_galaxyParticles.isPlaying) _galaxyParticles.Play();
}
if (_cosmicDustParticles != null)
{
var de = _cosmicDustParticles.emission;
de.rateOverTime = spaceT * 60f;
if (spaceT * 60f > 1f && !_cosmicDustParticles.isPlaying) _cosmicDustParticles.Play();
}
}
private Color GetGalaxyTint(string planetName)
{
switch (planetName)
{
case "璥猝": return new Color(0.9f, 0.5f, 0.2f);
case "犬<>琢": return new Color(0.95f, 0.95f, 1f);
case "蛇놋儼": return new Color(1f, 0.7f, 0.3f);
case "쭤張調": return new Color(1f, 0.85f, 0.2f);
case "邏膣存": return new Color(1f, 0.95f, 0.6f);
case "竟簇債녜": return new Color(1f, 0.95f, 0.8f);
case "到陝": return new Color(0.3f, 1f, 0.9f);
case "袞綎艙": return new Color(0.2f, 0.3f, 1f);
case "拳寀佺": return new Color(0.6f, 0.5f, 0.9f);
default: return new Color(0.7f, 0.85f, 1f);
}
}
private bool IsLightningPlanet(string name)
{
return name == "쭤張調" || name == "蛇놋儼" || name == "袞綎艙";
}
private float GetApproxMaxHeight()
{
float[] heights = { 500f, 8000f, 50000f, 200000f, 800000f };
return heights[Mathf.Clamp(_currentFuelLevel, 0, 4)];
}
public void StopAllParticles()
{
ParticleSystem[] all = { _atmParticles, _starParticles, _speedLines, _cloudParticles,
_heatParticles, _debrisParticles, _layer1Particles, _layer2Particles, _layer3Particles,
_galaxyParticles, _nebulaParticles, _meteorParticles, _cosmicDustParticles };
foreach (var ps in all)
if (ps != null) ps.Stop();
}
public void PlaySpaceDriftParticles()
{
if (_starParticles != null)
{
_starParticles.Play();
var se = _starParticles.emission;
se.rateOverTime = 120f;
var sv = _starParticles.velocityOverLifetime;
sv.y = new ParticleSystem.MinMaxCurve(-80f, -80f);
}
}
private ParticleSystem MakeParticles(string goName, int maxP,
Color c1, Color c2, float sMin, float sMax,
float ltMin, float ltMax, float spMin, float spMax,
float radius, float velY)
{
GameObject go = new GameObject(goName);
go.transform.SetParent(rocketRoot);
go.transform.localPosition = Vector3.zero;
ParticleSystem ps = go.AddComponent<ParticleSystem>();
var m = ps.main;
m.startLifetime = new ParticleSystem.MinMaxCurve(ltMin, ltMax);
m.startSpeed = new ParticleSystem.MinMaxCurve(spMin, spMax);
m.startSize = new ParticleSystem.MinMaxCurve(sMin, sMax);
m.startColor = new ParticleSystem.MinMaxGradient(c1, c2);
m.maxParticles = maxP;
m.simulationSpace = ParticleSystemSimulationSpace.World;
var em = ps.emission;
em.rateOverTime = 0f;
var sh = ps.shape;
sh.shapeType = ParticleSystemShapeType.Sphere;
sh.radius = radius;
var v = ps.velocityOverLifetime;
v.enabled = true;
v.space = ParticleSystemSimulationSpace.World;
v.x = new ParticleSystem.MinMaxCurve(0f, 0f);
v.y = new ParticleSystem.MinMaxCurve(velY, velY);
v.z = new ParticleSystem.MinMaxCurve(0f, 0f);
ps.Stop();
return ps;
}
private void CreateAllParticles()
{
_atmParticles = MakeParticles("_Atm", 600, new Color(1f, 1f, 1f, 0.95f), new Color(0.8f, 0.9f, 1f, 0.7f), 0.06f, 0.35f, 0.3f, 0.9f, 15f, 35f, 5f, -70f);
_starParticles = MakeParticles("_Stars", 600, new Color(1f, 1f, 1f, 1f), new Color(0.6f, 0.8f, 1f, 0.8f), 0.02f, 0.14f, 0.3f, 1.2f, 30f, 80f, 12f, -200f);
_speedLines = MakeParticles("_Speed", 300, new Color(1f, 1f, 1f, 0.9f), new Color(0.4f, 0.7f, 1f, 0.4f), 0.006f, 0.025f, 0.08f, 0.22f, 50f, 100f, 1.5f, -220f);
_cloudParticles = MakeParticles("_Clouds", 100, new Color(1f, 1f, 1f, 1f), new Color(0.9f, 0.95f, 1f, 0.8f), 3f, 7f, 0.4f, 0.9f, 5f, 15f, 7f, -25f);
_heatParticles = MakeParticles("_Heat", 150, new Color(1f, 0.6f, 0.1f, 0.9f), new Color(1f, 0.3f, 0.05f, 0.3f), 0.04f, 0.25f, 0.15f, 0.5f, 2f, 8f, 1f, -10f);
_debrisParticles = MakeParticles("_Debris", 80, new Color(0.9f, 0.7f, 0.3f, 1f), new Color(0.5f, 0.5f, 0.5f, 0.6f), 0.03f, 0.12f, 0.3f, 0.8f, 5f, 20f, 1f, -12f);
_layer1Particles = MakeParticles("_Layer1", 60, new Color(1f, 1f, 1f, 1f), new Color(0.85f, 0.9f, 1f, 0.7f), 4f, 10f, 0.4f, 0.9f, 3f, 10f, 7f, -22f);
_layer2Particles = MakeParticles("_Layer2", 40, new Color(0.7f, 0.85f, 1f, 0.95f), new Color(0.55f, 0.7f, 1f, 0.6f), 2.5f, 7f, 0.3f, 0.7f, 2f, 8f, 8f, -16f);
_layer3Particles = MakeParticles("_Layer3", 30, new Color(0.3f, 0.4f, 0.8f, 0.9f), new Color(0.2f, 0.3f, 0.6f, 0.5f), 2f, 5f, 0.25f, 0.6f, 2f, 7f, 9f, -13f);
_galaxyParticles = MakeParticles("_Galaxy", 400, new Color(1f, 1f, 1f, 1f), new Color(0.5f, 0.6f, 1f, 0.5f), 0.04f, 0.18f, 1.5f, 4f, 10f, 40f, 18f, -60f);
_nebulaParticles = MakeParticles("_Nebula", 80, new Color(0.6f, 0.2f, 1f, 0.7f), new Color(1f, 0.3f, 0.1f, 0.3f), 1.5f, 5f, 1f, 3f, 2f, 8f, 15f, -20f);
_cosmicDustParticles = MakeParticles("_CosmicDust", 300, new Color(0.8f, 0.7f, 1f, 0.6f), new Color(0.4f, 0.3f, 0.8f, 0.2f), 0.008f, 0.035f, 0.5f, 2f, 5f, 20f, 25f, -30f);
_meteorParticles = MakeParticles("_Meteors", 60, new Color(1f, 0.9f, 0.6f, 1f), new Color(0.8f, 0.5f, 0.2f, 0.4f), 0.01f, 0.04f, 0.05f, 0.15f, 80f, 160f, 20f, -300f);
var mv = _meteorParticles.velocityOverLifetime;
mv.x = new ParticleSystem.MinMaxCurve(-80f, 80f);
mv.y = new ParticleSystem.MinMaxCurve(-300f, -100f);
GameObject elGO = new GameObject("_EngineLight");
elGO.transform.SetParent(rocketRoot);
elGO.transform.localPosition = Vector3.down * 1.5f;
_engineLight = elGO.AddComponent<Light>();
_engineLight.type = LightType.Point;
_engineLight.color = new Color(1f, 0.55f, 0.1f);
_engineLight.intensity = 0f;
_engineLight.range = 10f;
GameObject spotGO = new GameObject("_RocketSpotLight");
spotGO.transform.SetParent(rocketRoot);
spotGO.transform.localPosition = Vector3.up * 2f;
spotGO.transform.localRotation = Quaternion.Euler(90f, 0f, 0f);
_rocketSpotLight = spotGO.AddComponent<Light>();
_rocketSpotLight.type = LightType.Spot;
_rocketSpotLight.color = new Color(0.8f, 0.9f, 1f);
_rocketSpotLight.intensity = 0f;
_rocketSpotLight.range = 15f;
_rocketSpotLight.spotAngle = 80f;
}
private System.Collections.IEnumerator AtmosphereLayerFlash(string planetName)
{
yield return new WaitForSeconds(1.5f);
yield return StartCoroutine(DoFlash(GetLayerColor(planetName, 0), 0.12f));
yield return new WaitForSeconds(1.8f);
yield return StartCoroutine(DoFlash(GetLayerColor(planetName, 1), 0.15f));
yield return new WaitForSeconds(2f);
yield return StartCoroutine(DoFlash(GetLayerColor(planetName, 2), 0.25f));
}
private System.Collections.IEnumerator DoFlash(Color c, float duration)
{
if (vignetteUI == null) yield break;
float t = 0f;
while (t < duration)
{
t += Time.deltaTime;
float alpha = Mathf.Sin(t / duration * Mathf.PI) * c.a;
vignetteUI.color = new Color(c.r, c.g, c.b, alpha);
yield return null;
}
vignetteUI.color = new Color(0f, 0f, 0f, 0f);
}
private System.Collections.IEnumerator LightningEffect()
{
float timer = 0f;
while (_isActive)
{
timer += Time.deltaTime;
if (timer > Random.Range(0.3f, 1.2f))
{
timer = 0f;
if (vignetteUI != null)
{
vignetteUI.color = new Color(0.9f, 0.95f, 1f, 0.6f);
yield return new WaitForSeconds(0.05f);
vignetteUI.color = new Color(0f, 0f, 0f, 0f);
yield return new WaitForSeconds(0.04f);
vignetteUI.color = new Color(0.9f, 0.95f, 1f, 0.3f);
yield return new WaitForSeconds(0.03f);
vignetteUI.color = new Color(0f, 0f, 0f, 0f);
}
}
yield return null;
}
}
private Color GetLayerColor(string planetName, int layer)
{
switch (planetName)
{
case "헌佾<ED978C>": { Color[] c = { new Color(0.5f, 0.8f, 1f, 0.3f), new Color(0.3f, 0.5f, 1f, 0.4f), new Color(0.1f, 0.1f, 0.4f, 0.5f) }; return c[layer]; }
case "璥猝": { Color[] c = { new Color(0.9f, 0.5f, 0.2f, 0.3f), new Color(0.7f, 0.3f, 0.1f, 0.35f), new Color(0.5f, 0.1f, 0.05f, 0.4f) }; return c[layer]; }
case "쭤張調": { Color[] c = { new Color(1f, 0.8f, 0.1f, 0.5f), new Color(0.9f, 0.6f, 0.05f, 0.6f), new Color(0.7f, 0.4f, 0f, 0.7f) }; return c[layer]; }
case "蛇놋儼": { Color[] c = { new Color(1f, 0.6f, 0.2f, 0.4f), new Color(0.9f, 0.4f, 0.1f, 0.5f), new Color(0.7f, 0.2f, 0.05f, 0.6f) }; return c[layer]; }
case "袞綎艙": { Color[] c = { new Color(0.2f, 0.4f, 1f, 0.4f), new Color(0.1f, 0.2f, 0.9f, 0.5f), new Color(0.05f, 0.1f, 0.7f, 0.65f) }; return c[layer]; }
default: { Color[] c = { new Color(0.5f, 0.7f, 1f, 0.3f), new Color(0.3f, 0.5f, 0.9f, 0.4f), new Color(0.1f, 0.2f, 0.6f, 0.5f) }; return c[layer]; }
}
}
public struct PlanetData
{
public string name;
public float atmosphereThickness;
public float exposure;
public Color skyTint;
public Color groundColor;
public bool hasFog;
public float fogDensity;
public Color fogColor;
public float sunLightIntensity;
}
}