initial commit

This commit is contained in:
2026-05-29 18:30:19 +03:00
commit feebd5afa5
1068 changed files with 222390 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DebrisPiece : MonoBehaviour
{
private Rigidbody _rb;
private void Awake()
{
_rb = GetComponent<Rigidbody>();
if (_rb == null)
_rb = gameObject.AddComponent<Rigidbody>();
}
public void Launch(Vector3 explosionPos, float force, Material material)
{
if (material != null)
{
MeshRenderer mr = GetComponent<MeshRenderer>();
if (mr != null) mr.sharedMaterial = material;
}
_rb.AddExplosionForce(force, explosionPos, 20f, 3f, ForceMode.Impulse);
_rb.AddTorque(Random.insideUnitSphere * force * 0.8f, ForceMode.Impulse);
Destroy(gameObject, Random.Range(3f, 7f));
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 40e8c17f55516d449b2265de490b12ed
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,61 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class FuelSelector : MonoBehaviour
{
[SerializeField] private TextMeshProUGUI fuelNameText;
[SerializeField] private Button leftButton;
[SerializeField] private Button rightButton;
[SerializeField] private Transform flame1;
[SerializeField] private Transform flame2;
[SerializeField] private Transform flame3;
private int _currentIndex = 0;
private readonly string[] _names = { "10%", "25%", "50%", "75%", "100%" };
private readonly float[] _maxHeights = { 500f, 8000f, 50000f, 200000f, 800000f };
private readonly Vector3[] _scales =
{
new Vector3(0.4f, 0.12f, 0.4f),
new Vector3(0.65f, 0.20f, 0.65f),
new Vector3(0.90f, 0.30f, 0.90f),
new Vector3(1.15f, 0.40f, 1.15f),
new Vector3(1.40f, 0.52f, 1.40f)
};
private void Start()
{
if (leftButton != null) leftButton.onClick.AddListener(PrevFuel);
if (rightButton != null) rightButton.onClick.AddListener(NextFuel);
ApplyFuel(0);
}
private void ApplyFuel(int index)
{
if (fuelNameText != null) fuelNameText.text = _names[index];
if (flame1 != null) flame1.localScale = _scales[index];
if (flame2 != null) flame2.localScale = _scales[index];
if (flame3 != null) flame3.localScale = _scales[index];
if (leftButton != null) leftButton.interactable = index > 0;
if (rightButton != null) rightButton.interactable = index < _names.Length - 1;
}
private void NextFuel()
{
if (_currentIndex < _names.Length - 1) { _currentIndex++; ApplyFuel(_currentIndex); }
}
private void PrevFuel()
{
if (_currentIndex > 0) { _currentIndex--; ApplyFuel(_currentIndex); }
}
public int GetFuelLevel() => _currentIndex;
public float GetMaxHeight() => _maxHeights[_currentIndex];
public string GetFuelName() => _names[_currentIndex];
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 712753361289423459f1e2e0403202d1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,330 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class PlanetSelector : MonoBehaviour
{
[SerializeField] private Material skyboxMaterial;
[SerializeField] private TextMeshProUGUI planetNameText;
[SerializeField] private Button leftButton;
[SerializeField] private Button rightButton;
[SerializeField] private Light sunLight;
[SerializeField] private ParticleSystem atmosphereParticles;
[SerializeField] private ParticleSystem starsParticles;
private int _currentIndex = 0;
private Coroutine _transitionCoroutine;
private PlanetData[] _planets;
public struct PlanetData
{
public string name;
public float gravity;
public float atmosphereDensity;
public Color skyTint;
public Color groundColor;
public float atmosphereThickness;
public float sunSize;
public float exposure;
public Color sunLightColor;
public float sunLightIntensity;
public bool hasFog;
public float fogDensity;
public Color fogColor;
public Color atmosParticleColor;
public float atmosParticleRate;
public Color starsColor;
public float starsRate;
public float starsSize;
}
private static Color H(string hex)
{
ColorUtility.TryParseHtmlString(hex, out Color c);
return c;
}
private void Awake()
{
_planets = new PlanetData[]
{
new PlanetData {
name = "헌佾<ED978C>",
gravity = 9.8f, atmosphereDensity = 1.0f,
skyTint = H("#3A7BD5"),
groundColor = H("#1A3A0A"),
atmosphereThickness = 1.0f, sunSize = 0.04f, exposure = 1.3f,
sunLightColor = H("#FFF8DC"),
sunLightIntensity = 1.2f,
hasFog = true, fogDensity = 0.0008f,
fogColor = H("#B0CCEE"),
atmosParticleColor = new Color(0.70f, 0.85f, 1.0f, 0.45f),
atmosParticleRate = 80f,
starsColor = new Color(0.95f, 0.97f, 1.0f, 0.55f),
starsRate = 60f, starsSize = 0.035f
},
new PlanetData {
name = "璥猝",
gravity = 3.7f, atmosphereDensity = 0.01f,
skyTint = H("#C99A72"),
groundColor = H("#6B3A1A"),
atmosphereThickness = 0.12f, sunSize = 0.028f, exposure = 0.90f,
sunLightColor = H("#FFD4A0"),
sunLightIntensity = 0.95f,
hasFog = true, fogDensity = 0.003f,
fogColor = H("#D4A87A"),
atmosParticleColor = new Color(0.78f, 0.55f, 0.32f, 0.65f),
atmosParticleRate = 120f,
starsColor = new Color(1.0f, 0.90f, 0.75f, 0.40f),
starsRate = 30f, starsSize = 0.025f
},
new PlanetData {
name = "犬<>琢",
gravity = 1.6f, atmosphereDensity = 0f,
skyTint = H("#000008"),
groundColor = H("#323030"),
atmosphereThickness = 0f, sunSize = 0.042f, exposure = 1.7f,
sunLightColor = H("#FFFFFF"),
sunLightIntensity = 1.9f,
hasFog = false, fogDensity = 0f, fogColor = Color.black,
atmosParticleColor = new Color(0f, 0f, 0f, 0f),
atmosParticleRate = 0f,
starsColor = new Color(1.0f, 1.0f, 1.0f, 1.0f),
starsRate = 580f, starsSize = 0.065f
},
new PlanetData {
name = "쭤張調",
gravity = 8.87f, atmosphereDensity = 90f,
skyTint = H("#D4922A"),
groundColor = H("#6B3A08"),
atmosphereThickness = 3.2f, sunSize = 0.09f, exposure = 1.0f,
sunLightColor = H("#FF9B20"),
sunLightIntensity = 1.1f,
hasFog = true, fogDensity = 0.008f,
fogColor = H("#C8842A"),
atmosParticleColor = new Color(0.90f, 0.65f, 0.20f, 0.75f),
atmosParticleRate = 200f,
starsColor = new Color(1.0f, 0.85f, 0.50f, 0.05f),
starsRate = 2f, starsSize = 0.015f
},
new PlanetData {
name = "蛇놋儼",
gravity = 24.8f, atmosphereDensity = 50f,
skyTint = H("#5A7A9E"),
groundColor = H("#7A5535"),
atmosphereThickness = 2.5f, sunSize = 0.016f, exposure = 0.80f,
sunLightColor = H("#E8C080"),
sunLightIntensity = 0.85f,
hasFog = true, fogDensity = 0.005f,
fogColor = H("#8A7050"),
atmosParticleColor = new Color(0.75f, 0.60f, 0.35f, 0.60f),
atmosParticleRate = 180f,
starsColor = new Color(0.90f, 0.88f, 0.75f, 0.15f),
starsRate = 10f, starsSize = 0.016f
},
new PlanetData {
name = "邏膣存",
gravity = 10.4f, atmosphereDensity = 20f,
skyTint = H("#DFC87A"),
groundColor = H("#A08540"),
atmosphereThickness = 1.8f, sunSize = 0.014f, exposure = 0.85f,
sunLightColor = H("#FFF0C0"),
sunLightIntensity = 0.90f,
hasFog = true, fogDensity = 0.002f,
fogColor = H("#D4BC70"),
atmosParticleColor = new Color(0.90f, 0.80f, 0.50f, 0.50f),
atmosParticleRate = 100f,
starsColor = new Color(1.0f, 0.97f, 0.82f, 0.20f),
starsRate = 15f, starsSize = 0.020f
},
new PlanetData {
name = "竟簇債녜",
gravity = 3.7f, atmosphereDensity = 0f,
skyTint = H("#050404"),
groundColor = H("#4A4038"),
atmosphereThickness = 0f, sunSize = 0.12f, exposure = 2.4f,
sunLightColor = H("#FFFCF0"),
sunLightIntensity = 2.4f,
hasFog = false, fogDensity = 0f, fogColor = Color.black,
atmosParticleColor = new Color(0f, 0f, 0f, 0f),
atmosParticleRate = 0f,
starsColor = new Color(1.0f, 1.0f, 0.97f, 0.92f),
starsRate = 500f, starsSize = 0.058f
},
new PlanetData {
name = "到陝",
gravity = 8.7f, atmosphereDensity = 5f,
skyTint = H("#72E0DC"),
groundColor = H("#2A9090"),
atmosphereThickness = 1.2f, sunSize = 0.010f, exposure = 1.0f,
sunLightColor = H("#A0F0F8"),
sunLightIntensity = 0.95f,
hasFog = true, fogDensity = 0.0015f,
fogColor = H("#60D0D0"),
atmosParticleColor = new Color(0.42f, 0.88f, 0.86f, 0.55f),
atmosParticleRate = 90f,
starsColor = new Color(0.70f, 0.95f, 1.0f, 0.50f),
starsRate = 100f, starsSize = 0.038f
},
new PlanetData {
name = "袞綎艙",
gravity = 11.2f, atmosphereDensity = 8f,
skyTint = H("#1535C8"),
groundColor = H("#080F50"),
atmosphereThickness = 1.5f, sunSize = 0.007f, exposure = 0.80f,
sunLightColor = H("#6080FF"),
sunLightIntensity = 0.75f,
hasFog = true, fogDensity = 0.003f,
fogColor = H("#1828A0"),
atmosParticleColor = new Color(0.18f, 0.28f, 1.0f, 0.60f),
atmosParticleRate = 130f,
starsColor = new Color(0.70f, 0.80f, 1.0f, 0.48f),
starsRate = 75f, starsSize = 0.036f
},
new PlanetData {
name = "拳寀佺",
gravity = 0.62f, atmosphereDensity = 0.001f,
skyTint = H("#0A0318"),
groundColor = H("#504870"),
atmosphereThickness = 0.03f, sunSize = 0.005f, exposure = 0.50f,
sunLightColor = H("#A090E0"),
sunLightIntensity = 0.45f,
hasFog = false, fogDensity = 0f, fogColor = Color.black,
atmosParticleColor = new Color(0.50f, 0.40f, 0.70f, 0.08f),
atmosParticleRate = 0f,
starsColor = new Color(0.88f, 0.82f, 1.0f, 0.92f),
starsRate = 650f, starsSize = 0.072f
}
};
}
private void Start()
{
if (leftButton != null) leftButton.onClick.AddListener(PrevPlanet);
if (rightButton != null) rightButton.onClick.AddListener(NextPlanet);
if (starsParticles != null)
{
var shape = starsParticles.shape;
shape.shapeType = ParticleSystemShapeType.Hemisphere;
shape.radius = 80f;
}
ApplyPlanet(0);
}
private void ApplyPlanet(int index)
{
if (_transitionCoroutine != null)
StopCoroutine(_transitionCoroutine);
_transitionCoroutine = StartCoroutine(TransitionToPlanet(_planets[index]));
if (planetNameText != null)
planetNameText.text = _planets[index].name;
if (leftButton != null) leftButton.interactable = index > 0;
if (rightButton != null) rightButton.interactable = index < _planets.Length - 1;
}
private IEnumerator TransitionToPlanet(PlanetData p)
{
float t = 0f;
float duration = 1.8f;
Color startSkyTint = skyboxMaterial.GetColor("_SkyTint");
Color startGroundColor = skyboxMaterial.GetColor("_GroundColor");
float startAtmosphere = skyboxMaterial.GetFloat("_AtmosphereThickness");
float startSunSize = skyboxMaterial.GetFloat("_SunSize");
float startExposure = skyboxMaterial.GetFloat("_Exposure");
Color startFogColor = RenderSettings.fogColor;
float startFogDensity = RenderSettings.fogDensity;
Color startLightColor = sunLight != null ? sunLight.color : Color.white;
float startLightIntensity = sunLight != null ? sunLight.intensity : 1f;
while (t < 1f)
{
t += Time.deltaTime / duration;
float s = Mathf.SmoothStep(0f, 1f, t);
if (skyboxMaterial != null)
{
skyboxMaterial.SetColor("_SkyTint", Color.Lerp(startSkyTint, p.skyTint, s));
skyboxMaterial.SetColor("_GroundColor", Color.Lerp(startGroundColor, p.groundColor, s));
skyboxMaterial.SetFloat("_AtmosphereThickness", Mathf.Lerp(startAtmosphere, p.atmosphereThickness, s));
skyboxMaterial.SetFloat("_SunSize", Mathf.Lerp(startSunSize, p.sunSize, s));
skyboxMaterial.SetFloat("_Exposure", Mathf.Lerp(startExposure, p.exposure, s));
}
RenderSettings.fog = p.hasFog;
if (p.hasFog)
{
RenderSettings.fogMode = FogMode.Exponential;
RenderSettings.fogColor = Color.Lerp(startFogColor, p.fogColor, s);
RenderSettings.fogDensity = Mathf.Lerp(startFogDensity, p.fogDensity, s);
}
if (sunLight != null)
{
sunLight.color = Color.Lerp(startLightColor, p.sunLightColor, s);
sunLight.intensity = Mathf.Lerp(startLightIntensity, p.sunLightIntensity, s);
}
DynamicGI.UpdateEnvironment();
yield return null;
}
if (atmosphereParticles != null)
{
var main = atmosphereParticles.main;
main.startColor = p.atmosParticleColor;
var emission = atmosphereParticles.emission;
emission.rateOverTime = p.atmosParticleRate;
if (p.atmosParticleRate > 0f && !atmosphereParticles.isPlaying)
atmosphereParticles.Play();
else if (p.atmosParticleRate == 0f)
atmosphereParticles.Stop();
}
if (starsParticles != null)
{
var main = starsParticles.main;
main.startColor = p.starsColor;
main.startSize = new ParticleSystem.MinMaxCurve(p.starsSize * 0.5f, p.starsSize);
var emission = starsParticles.emission;
emission.rateOverTime = p.starsRate;
if (p.starsRate > 0f && !starsParticles.isPlaying)
starsParticles.Play();
else if (p.starsRate == 0f)
starsParticles.Stop();
}
}
private void NextPlanet()
{
if (_currentIndex < _planets.Length - 1)
{
_currentIndex++;
ApplyPlanet(_currentIndex);
}
}
private void PrevPlanet()
{
if (_currentIndex > 0)
{
_currentIndex--;
ApplyPlanet(_currentIndex);
}
}
public void RestoreCurrentPlanet()
{
if (_transitionCoroutine != null)
StopCoroutine(_transitionCoroutine);
_transitionCoroutine = StartCoroutine(TransitionToPlanet(_planets[_currentIndex]));
}
public PlanetData GetCurrentPlanet() => _planets[_currentIndex];
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 083c5b6135a7aea4c829d66d65103711
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,184 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine;
public class RocketCameraController : MonoBehaviour
{
[Header("Êàìåðà")]
[SerializeField] private Camera mainCamera;
[SerializeField] private Transform rocketRoot;
[SerializeField] private float baseFOV = 60f;
private Vector3 _cameraStartPos;
private Quaternion _cameraStartRot;
private Vector3 _rocketStartPos;
private Vector3 _camVelocity = Vector3.zero;
private bool _isActive;
private RocketFlightCore _core;
private float _flightTimer;
private float _swayTime;
private float _currentShake;
private float _targetFOV;
public void Initialize(RocketFlightCore core)
{
_core = core;
_cameraStartPos = mainCamera.transform.position;
_cameraStartRot = mainCamera.transform.rotation;
_rocketStartPos = rocketRoot != null ? rocketRoot.position : Vector3.zero;
baseFOV = mainCamera.fieldOfView;
_targetFOV = baseFOV;
}
public void StartFlight()
{
_isActive = true;
_flightTimer = 0f;
_swayTime = 0f;
_camVelocity = Vector3.zero;
_currentShake = 0f;
}
public void StopFlight()
{
_isActive = false;
}
public void ResetCamera()
{
_isActive = false;
_flightTimer = 0f;
_camVelocity = Vector3.zero;
_currentShake = 0f;
mainCamera.transform.position = _cameraStartPos;
mainCamera.transform.rotation = _cameraStartRot;
mainCamera.fieldOfView = baseFOV;
}
public void TriggerSonicBoom()
{
StartCoroutine(SonicBoomShake());
}
public void SwitchToSpaceDrift() { }
public void StartIgnitionShake(float shakeMultiplier)
{
StartCoroutine(IgnitionShake(shakeMultiplier));
}
private void Update()
{
if (!_isActive || _core == null || mainCamera == null) return;
_flightTimer += Time.deltaTime;
_swayTime += Time.deltaTime;
UpdateCameraFollow();
UpdateFOV();
UpdateCameraRotation();
}
private void UpdateCameraFollow()
{
float rocketVisualY = rocketRoot.position.y - _rocketStartPos.y;
float speedNorm = _core.GetSpeedNormalized();
float spaceProgress = _core.GetSpaceProgress();
float swayX = Mathf.Sin(_swayTime * 13.7f) * speedNorm * 0.06f;
float swayY = Mathf.Sin(_swayTime * 9.3f) * speedNorm * 0.03f;
float smoothTime = _core.FuelCutoff
? 0.4f
: Mathf.Lerp(0.04f, 0.12f, spaceProgress);
Vector3 target = _cameraStartPos
+ Vector3.up * rocketVisualY
+ new Vector3(swayX, swayY, 0f);
mainCamera.transform.position = Vector3.SmoothDamp(
mainCamera.transform.position,
target,
ref _camVelocity,
smoothTime);
if (_currentShake > 0f)
{
_currentShake = Mathf.Lerp(_currentShake, 0f, Time.deltaTime * 3f);
mainCamera.transform.position += new Vector3(
Random.Range(-_currentShake, _currentShake),
Random.Range(-_currentShake * 0.5f, _currentShake * 0.5f),
0f);
}
}
private void UpdateFOV()
{
float speedNorm = _core.GetSpeedNormalized();
float spaceProgress = _core.GetSpaceProgress();
if (_core.FuelCutoff)
{
_targetFOV = Mathf.Lerp(_targetFOV, baseFOV, Time.deltaTime * 1.5f);
}
else if (spaceProgress > 0.1f)
{
_targetFOV = Mathf.Lerp(baseFOV + speedNorm * 15f, baseFOV + 22f, Mathf.Clamp01(spaceProgress * 2f));
}
else
{
_targetFOV = baseFOV + speedNorm * 20f;
}
mainCamera.fieldOfView = Mathf.Lerp(mainCamera.fieldOfView, _targetFOV, Time.deltaTime * 5f);
}
private void UpdateCameraRotation()
{
float speedNorm = _core.GetSpeedNormalized();
float spaceProgress = _core.GetSpaceProgress();
float roll = Mathf.Sin(_swayTime * 5f) * speedNorm * 0.6f;
float tiltForward = spaceProgress > 0.3f
? Mathf.Lerp(0f, 4f, (spaceProgress - 0.3f) / 0.7f)
: 0f;
mainCamera.transform.rotation = Quaternion.Slerp(
mainCamera.transform.rotation,
_cameraStartRot * Quaternion.Euler(tiltForward, 0f, roll),
Time.deltaTime * 2f);
}
private IEnumerator IgnitionShake(float shakeMultiplier)
{
float elapsed = 0f;
float duration = 2.0f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
float progress = elapsed / duration;
float power = progress < 0.15f
? Mathf.Lerp(0f, 0.5f * shakeMultiplier, progress / 0.15f)
: Mathf.Lerp(0.5f * shakeMultiplier, 0.02f * shakeMultiplier, (progress - 0.15f) / 0.85f);
_currentShake = power;
yield return null;
}
_currentShake = 0f;
}
private IEnumerator SonicBoomShake()
{
float elapsed = 0f;
float duration = 0.6f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
_currentShake = Mathf.Lerp(0.4f, 0f, elapsed / duration);
yield return null;
}
_currentShake = 0f;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ccd867d9a0c9c204aaca5686da3fbdaa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,14 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RocketCursor : MonoBehaviour
{
[SerializeField] private Texture2D cursorTexture;
private void Start()
{
if (cursorTexture != null)
Cursor.SetCursor(cursorTexture, Vector2.zero, CursorMode.Auto);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b442698049db8444aa5df37b90cfb0ef
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,490 @@
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;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 697f2cde5d094fa49a5ba3d3ba0e77e6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,191 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RocketFlightCore : MonoBehaviour
{
public enum FlightPhase
{
Idle, Ignition, LaunchPad, LowerAtmosphere, UpperAtmosphere, KarmanLine, Space, DeepSpace, Exploded, Landed
}
public FlightPhase Phase { get; private set; } = FlightPhase.Idle;
public float CurrentHeight { get; private set; }
public float Velocity { get; private set; }
public float MaxHeightReached { get; private set; }
public float AnimTime { get; private set; }
public bool FuelCutoff { get; private set; }
public bool RocketEscaped { get; private set; }
public bool IsActive { get; private set; }
public float TotalFuel { get; private set; }
public float RemainingFuel { get; private set; }
private float _gravity;
private float _atmDensity;
private float _materialDrag;
private float _thrust;
private float _animSpeed;
private float _fuelBurnRate;
private bool _willExplode;
private float _explodeDelay;
private float _explodeTimer;
private float _fuelCutoffTime;
private float _escapeVelocity;
public void Initialize() { }
public void StartFlight(float fuelAmount, float gravity, float atmDensity, float materialDrag, bool willExplode, float explodeDelay)
{
_gravity = gravity;
_atmDensity = atmDensity;
_materialDrag = materialDrag;
_willExplode = willExplode;
_explodeDelay = explodeDelay;
_thrust = Mathf.Max(10f, 200f - atmDensity * 1.5f - materialDrag * 30f);
_fuelBurnRate = 1f;
TotalFuel = fuelAmount;
RemainingFuel = fuelAmount;
_escapeVelocity = Mathf.Sqrt(2f * gravity * 6371000f) * 0.0001f;
float simFuelDuration = fuelAmount / _fuelBurnRate;
_animSpeed = simFuelDuration / 18f;
CurrentHeight = 0f;
Velocity = 0f;
MaxHeightReached = 0f;
AnimTime = 0f;
FuelCutoff = false;
RocketEscaped = false;
IsActive = true;
_explodeTimer = 0f;
_fuelCutoffTime = 0f;
Phase = FlightPhase.Ignition;
}
public void ResetFlight()
{
CurrentHeight = 0f;
Velocity = 0f;
MaxHeightReached = 0f;
AnimTime = 0f;
FuelCutoff = false;
RocketEscaped = false;
IsActive = false;
RemainingFuel = 0f;
Phase = FlightPhase.Idle;
}
public bool UpdateFlight(float deltaTime, out bool shouldExplode, out bool flightFinished)
{
shouldExplode = false;
flightFinished = false;
if (!IsActive) return false;
AnimTime += deltaTime;
float dt = deltaTime * _animSpeed;
if (_willExplode)
{
_explodeTimer += deltaTime;
if (_explodeTimer >= _explodeDelay)
{
shouldExplode = true;
Phase = FlightPhase.Exploded;
IsActive = false;
return true;
}
}
bool hasFuel = RemainingFuel > 0f;
float currentThrust = 0f;
if (hasFuel && !FuelCutoff)
{
currentThrust = _thrust;
RemainingFuel = Mathf.Max(0f, RemainingFuel - _fuelBurnRate * dt);
if (RemainingFuel <= 0f)
{
FuelCutoff = true;
_fuelCutoffTime = AnimTime;
}
}
float atmFactor = Mathf.Exp(-CurrentHeight * 0.00001f);
float drag = _atmDensity * atmFactor * Velocity * Velocity * _materialDrag * 0.0001f;
drag = Mathf.Sign(Velocity) * drag;
Velocity += (currentThrust - _gravity - drag) * dt;
CurrentHeight = Mathf.Max(0f, CurrentHeight + Velocity * dt);
if (CurrentHeight > MaxHeightReached) MaxHeightReached = CurrentHeight;
if (FuelCutoff && Velocity > _escapeVelocity * 0.5f)
RocketEscaped = true;
UpdatePhase();
if (AnimTime >= 25f || (FuelCutoff && CurrentHeight <= 0f && Velocity < 0f))
{
if (FuelCutoff && CurrentHeight <= 0f && Velocity < 0f)
{
shouldExplode = true;
Phase = FlightPhase.Exploded;
}
else
{
flightFinished = true;
}
IsActive = false;
return true;
}
return false;
}
private void UpdatePhase()
{
if (AnimTime < 0.5f)
Phase = FlightPhase.Ignition;
else if (CurrentHeight < 1000f)
Phase = FlightPhase.LaunchPad;
else if (CurrentHeight < 30000f)
Phase = FlightPhase.LowerAtmosphere;
else if (CurrentHeight < 80000f)
Phase = FlightPhase.UpperAtmosphere;
else if (CurrentHeight < 100000f)
Phase = FlightPhase.KarmanLine;
else if (CurrentHeight < 400000f)
Phase = FlightPhase.Space;
else
Phase = FlightPhase.DeepSpace;
}
public float GetAtmosphereProgress()
{
return Mathf.Clamp01(CurrentHeight / 100000f);
}
public float GetSpaceProgress()
{
return Mathf.Clamp01((CurrentHeight - 100000f) / 300000f);
}
public float GetSpeedNormalized()
{
return Mathf.Clamp01(Mathf.Abs(Velocity) / 150f);
}
public float GetFuelProgress()
{
return TotalFuel > 0f ? 1f - (RemainingFuel / TotalFuel) : 1f;
}
public float GetFuelCutoffTime()
{
return FuelCutoff ? AnimTime - _fuelCutoffTime : 0f;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: eb2f502c8f8778d4986bebaf5e4fb5f0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,498 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class RocketLauncher : MonoBehaviour
{
[Header("Ðàêåòà")]
[SerializeField] private Transform rocketRoot;
[SerializeField] private Transform[] flameParts;
[SerializeField] private Button launchButton;
[SerializeField] private GameObject materialPanel;
[SerializeField] private GameObject infoPanel;
[SerializeField] private TextMeshProUGUI infoPanelText;
[Header("Âèáóõè")]
[SerializeField] private GameObject explosionBig;
[SerializeField] private GameObject explosionMedium;
[SerializeField] private GameObject explosionSmall;
[SerializeField] private GameObject debrisPrefab;
[Header("Ñåëåêòîðè")]
[SerializeField] private RocketMaterialSelector materialSelector;
[SerializeField] private PlanetSelector planetSelector;
[SerializeField] private FuelSelector fuelSelector;
[Header("ϳäñèñòåìè")]
[SerializeField] private RocketFlightCore flightCore;
[SerializeField] private RocketCameraController cameraController;
[SerializeField] private RocketEffectsController effectsController;
private bool _isLaunched = false;
private bool _sonicBoomDone = false;
private Vector3 _rocketStartPos;
private Quaternion _rocketStartRot;
private static readonly HashSet<string> _explodeOnLaunch = new HashSet<string>
{ "Ïàï³ð", "Ñí³æîê", "Àâîêàäî", "˳÷³", "Ãóìîâà êà÷å÷êà", "˳ä", "Ñêëî", "Ñêëÿíà áàíêà", "Áëîêíîò", "Ïëàñòèêîâà äîøêà",
"Öåãëà", "Ãðàí³ò", "Ìàðìóð", "×àâóí", "Ãóìà", "Ïëàñòèê" };
private static readonly HashSet<string> _explodeSoon = new HashSet<string>
{ "Äåðåâî", "Àñôàëüò", "Çîëîòî", "Äåðåâ'ÿíà äîøêà", "Êàì³ííÿ ç ìîõîì" };
private static readonly HashSet<string> _planetExplode = new HashSet<string>
{ "Âåíåðà", "Þï³òåð" };
private static readonly Dictionary<string, string> _materialExplosionReason = new Dictionary<string, string>
{
{ "Ïàï³ð", "Ïàï³ð ñïàëàõóº ïðè +233C. Äâèãóíè ðîçæàðþþòüñÿ äî 3000C -- ïàï³ð ïåðåòâîðèâñÿ íà ïîï³ë ùå íà ñòàðò³." },
{ "Ñí³æîê", "Ñí³ã òàíå ïðè 0C. Ïîëóì'ÿ äâèãóíà ìèòòºâî ïåðåòâîðèëî êîðïóñ íà ïàðó ùå äî â³äðèâó â³ä ïîâåðõí³." },
{ "Àâîêàäî", "Îðãàí³÷í³ ìàòåð³àëè íå âèòðèìóþòü òåìïåðàòóðè ñòàðòó. Àâîêàäî çàéíÿëîñÿ ùå äî ï³äéîìó." },
{ "˳÷³", "Ì'ÿêà îðãàí³êà íå çäàòíà âèòðèìàòè òèñê ³ òåìïåðàòóðó íàâ³òü íèæíüîãî øàðó àòìîñôåðè." },
{ "Ãóìîâà êà÷å÷êà", "Ãóìà ðîçïëàâëÿºòüñÿ ïðè +300C. ³ä òÿãè äâèãóí³â âîíà ðîçòåêëàñü ùå íà ñòàðò³." },
{ "˳ä", "˳ä òàíå ïðè 0C. Ïîëóì'ÿ äâèãóí³â ïåðåòâîðèëî êîðïóñ íà âîäó ùå äî â³äðèâó â³ä çåìë³." },
{ "Ñêëî", "Ñêëî êðèõêå ³ íå âèòðèìóº â³áðàö³¿ ïðè ñòàðò³. Òåðì³÷íèé óäàð ðîçòð³ñêóº êîðïóñ ìèòòºâî." },
{ "Äåðåâî", "Äåðåâî çàéìàºòüñÿ ïðè +300C. Àåðîäèíàì³÷íå íàãð³âàííÿ ïåðåòâîðþº êîðïóñ íà ôàêåë âæå íà âèñîò³ 10 êì." },
{ "Àñôàëüò", "Àñôàëüò ðîçì'ÿêøóºòüñÿ ïðè +60C. ³ä òåðòÿ ç ïîâ³òðÿì â³í âòðà÷ຠôîðìó ³ ðàêåòà ðóéíóºòüñÿ." },
{ "Çîëîòî", "Çîëîòî ïëàâèòüñÿ ïðè +1064C. Àåðîäèíàì³÷íå íàãð³âàííÿ äîñÿãຠöüîãî ïîðîãó -- êîðïóñ äåôîðìóâàâñÿ." },
{ "Öåãëà", "Öåãëà âàæèòü 1800 êã/ì3 -- â 4 ðàçè âàæ÷à çà àëþì³í³é. Äâèãóí ô³çè÷íî íå ï³äíÿâ êîíñòðóêö³þ. Çðóéíóâàëàñü â³ä â³áðàö³¿ íà ñòàðò³." },
{ "Ãðàí³ò", "Ãðàí³ò âàæèòü 2700 êã/ì3 -- íàéâàæ÷èé ìàòåð³àë â ñïèñêó. Æîäåí ³ñíóþ÷èé äâèãóí íå ï³äí³ìå ðàêåòó ç òàêèì êîðïóñîì." },
{ "Ìàðìóð", "Ìàðìóð âàæèòü 2700 êã/ì3 ³ êðèõêèé. Ðîçñèïàâñÿ â³ä â³áðàö³¿ äâèãóí³â ùå äî â³äðèâó â³ä çåìë³." },
{ "×àâóí", "×àâóí âàæèòü 7200 êã/ì3 -- â 2.5 ðàçè âàæ÷èé çà ñòàëü. Êîíñòðóêö³ÿ ðîçëàìàëàñü â³ä âëàñíî¿ âàãè ïðè çàïóñêó äâèãóí³â." },
{ "Ãóìà", "Ãóìà ïëàâèòüñÿ ïðè +300C. Äâèãóíè äàþòü +3000C -- êîðïóñ ðîçò³êñÿ ùå äî ñòàðòó." },
{ "Ïëàñòèê", "Ïëàñòèê ïëàâèòüñÿ ïðè +150-300C ³ çàíàäòî ñëàáêèé äëÿ òèñêó ïðè çàïóñêó. Äåôîðìóâàâñÿ ³ çðóéíóâàâñÿ íà ñòàðò³." },
};
private static readonly Dictionary<string, string> _planetFacts = new Dictionary<string, string>
{
{ "Çåìëÿ", "Àòìîñôåðà ñÿãຠ100 êì (ë³í³ÿ Êàðìàíà). Òèñê íà ïîâåðõí³ 1 àòì, òåìïåðàòóðà ïàäຠäî -56C íà âèñîò³ 11 êì." },
{ "Ìàðñ", "Àòìîñôåðà â 100 ðàç³â ð³äê³øà çà çåìíó. Áåç ñêàôàíäðà êðîâ çàêèï³ëà á ìèòòºâî. Ãðàâ³òàö³ÿ 3.7 ì/ñ2." },
{ "̳ñÿöü", "Áåç àòìîñôåðè òåìïåðàòóðà â³ä +127C âäåíü äî -173C âíî÷³. Ãðàâ³òàö³ÿ 1.6 ì/ñ2 -- â 6 ðàç³â ìåíøå çåìíî¿." },
{ "Þï³òåð", "Âåëèêèé ×åðâîíèé Ïëÿì -- øòîðì ùî òðèâຠïîíàä 350 ðîê³â. Ãðàâ³òàö³ÿ 24.8 ì/ñ2 -- ó 2.5 ðàçè á³ëüøå çåìíî¿." },
{ "Âåíåðà", "Îáåðòàºòüñÿ ó çâîðîòíèé á³ê. Õìàðè ç ñ³ð÷àíî¿ êèñëîòè. Òèñê 92 àòì -- ÿê íà ãëèáèí³ 900 ì îêåàíó." },
{ "Ñàòóðí", "ʳëüöÿ çàâòîâøêè ëèøå 20 ìåòð³â àëå çàâøèðøêè 282000 êì. ³òðè äî 1800 êì/ãîä." },
{ "Ìåðêóð³é", "гê 88 äí³â àëå äåíü äîâøèé çà ð³ê -- 176 çåìíèõ ä³á. Ãðàâ³òàö³ÿ 3.7 ì/ñ2 ÿê íà Ìàðñ³." },
{ "Óðàí", "Îáåðòàºòüñÿ ëåæà÷è íà áîö³ -- â³ñü íàõèëåíà íà 98 ãðàäóñ³â. Ãðàâ³òàö³ÿ 8.7 ì/ñ2." },
{ "Íåïòóí", "Íàéñèëüí³ø³ â³òðè â Ñîíÿ÷í³é ñèñòåì³ -- 2100 êì/ãîä. Ãðàâ³òàö³ÿ 11.2 ì/ñ2." },
{ "Ïëóòîí", "Ñåðöå Ïëóòîíà -- ð³âíèíà Òîìáî ç ëüîäîâèê³â àçîòó. Ãðàâ³òàö³ÿ ëèøå 0.62 ì/ñ2." }
};
private static readonly Dictionary<string, string> _planetExplosionReason = new Dictionary<string, string>
{
{ "Âåíåðà", "Âåíåðà âáèâຠïîòð³éíî: òèñê 92 àòì ðîçäàâëþº êîðïóñ, +465C ïëàâèòü ìåòàëè, õìàðè ñ³ð÷àíî¿ êèñëîòè ðîç'¿äàþòü ðåøòó." },
{ "Þï³òåð", "Þï³òåð íå ìຠïîâåðõí³ -- ðàêåòà òîíå â àòìîñôåð³. Íà ãëèáèí³ 1000 êì òèñê ïåðåâèùóº 100000 àòì." }
};
private static readonly Dictionary<string, float> _fuelAmounts = new Dictionary<string, float>
{
{ "10%", 10f },
{ "25%", 25f },
{ "50%", 50f },
{ "75%", 75f },
{ "100%", 100f }
};
private void Start()
{
if (launchButton != null) launchButton.onClick.AddListener(Launch);
_rocketStartPos = rocketRoot.position;
_rocketStartRot = rocketRoot.rotation;
if (infoPanel != null) infoPanel.SetActive(false);
flightCore.Initialize();
cameraController.Initialize(flightCore);
effectsController.Initialize(flightCore);
}
private void Update()
{
if (!_isLaunched || flightCore == null) return;
bool shouldExplode, flightFinished;
flightCore.UpdateFlight(Time.deltaTime, out shouldExplode, out flightFinished);
UpdateRocketTransform();
if (!_sonicBoomDone && flightCore.AnimTime >= 3.5f && flightCore.GetAtmosphereProgress() < 0.7f)
{
_sonicBoomDone = true;
cameraController.TriggerSonicBoom();
}
if (flightCore.FuelCutoff)
SetFlamesActive(false);
if (shouldExplode) { Explode(); return; }
if (flightFinished)
{
effectsController.StopFlight();
cameraController.StopFlight();
if (flightCore.RocketEscaped)
StartCoroutine(SpaceDriftAndInfo());
else
StartCoroutine(ShowInfoAndReset());
}
}
private void UpdateRocketTransform()
{
float visualH = flightCore.CurrentHeight * Mathf.Lerp(0.00005f, 0.00015f, Mathf.Clamp01(flightCore.AnimTime / 8f));
rocketRoot.position = _rocketStartPos + Vector3.up * visualH;
if (!flightCore.FuelCutoff)
{
float tilt = Mathf.Clamp(flightCore.Velocity * 0.002f, -12f, 15f);
rocketRoot.rotation = Quaternion.Lerp(rocketRoot.rotation,
_rocketStartRot * Quaternion.Euler(-tilt, 0f, 0f), Time.deltaTime * 4f);
}
else
{
float cutoffTime = flightCore.GetFuelCutoffTime();
float gentleTilt = Mathf.Lerp(0f, 6f, Mathf.Clamp01(cutoffTime / 8f));
float gentleRoll = Mathf.Sin(cutoffTime * 0.3f) * 2f;
rocketRoot.rotation = Quaternion.Slerp(rocketRoot.rotation,
_rocketStartRot * Quaternion.Euler(gentleTilt, 0f, gentleRoll), Time.deltaTime * 0.3f);
}
}
private void Launch()
{
if (_isLaunched) return;
_isLaunched = true;
_sonicBoomDone = false;
if (materialPanel != null) materialPanel.SetActive(false);
var mat = materialSelector.GetCurrentMaterial();
var pd = planetSelector.GetCurrentPlanet();
string matName = mat.name;
string planet = pd.name;
bool willExplode = _explodeOnLaunch.Contains(matName) || _explodeSoon.Contains(matName) || _planetExplode.Contains(planet);
float explodeDelay = _explodeOnLaunch.Contains(matName) ? 0.7f : (_explodeSoon.Contains(matName) ? 4.0f : 5.0f);
if (!willExplode) explodeDelay = 0f;
string fuelName = fuelSelector.GetFuelName();
float fuelAmount = _fuelAmounts.ContainsKey(fuelName) ? _fuelAmounts[fuelName] : 50f;
float shakeMultiplier = GetShakeMultiplier(planet);
flightCore.StartFlight(
fuelAmount,
pd.gravity,
pd.atmosphereDensity,
mat.dragCoefficient,
willExplode,
explodeDelay);
cameraController.StartFlight();
cameraController.StartIgnitionShake(shakeMultiplier);
effectsController.StartFlight(planet, fuelSelector.GetFuelLevel(), shakeMultiplier);
}
private static readonly Dictionary<string, string> _materialFacts = new Dictionary<string, string>
{
{ "Âóãëåöåâå âîëîêíî", "Ñàìå ç íüîãî ðîáëÿòü êîðïóñè Falcon 9 òà Starship. Ëåãêå ³ ì³öíå -- ³äåàë äëÿ ðàêåò." },
{ "Òèòàí", "NASA âèêîðèñòîâóº òèòàí äëÿ êîðïóñ³â äâèãóí³â. Âèòðèìóº äî +1650C." },
{ "Ïîë³ðîâàíà ñòàëü", "Starship â³ä SpaceX çðîáëåíèé ç³ ñòàë³. Ìàñê îáðàâ ñòàëü áî âîíà äåøåâà ³ ì³öíà." },
{ "Àëþì³í³é", "Apollo ³ Saturn V ìàëè àëþì³í³ºâ³ êîðïóñè. Ëåãêèé àëå ïëàâèòüñÿ ïðè +660C." },
{ "Êåðàì³êà", "Space Shuttle ìàâ 24000 êåðàì³÷íèõ ïëèòîê äëÿ çàõèñòó â³ä æàðó ïðè ïîñàäö³ (+1600C)." },
{ "Ñòàëü", "Á³ëüø³ñòü ðàäÿíñüêèõ ðàêåò Ñîþç çðîáëåí³ ç³ ñòàë³. Âàæêà àëå íàä³éíà." },
{ "̳äü", "̳äü âèêîðèñòîâóþòü ó ñîïëàõ äâèãóí³â -- âîíà äîáðå â³äâîäèòü æàð â³ä çãîðÿííÿ." },
{ "Ïëàñòèê", "Ïëàñòèê çàíàäòî ëåãêèé ³ ñëàáêèé. Ðåàëüí³ ðàêåòè íå ìàþòü ïëàñòèêîâèõ êîðïóñ³â." },
{ "Ñêëî", "Ñêëî êðèõêå ïðè â³áðàö³¿ ñòàðòó. Âèêîðèñòîâóºòüñÿ ò³ëüêè ó â³êíàõ êàá³í àñòðîíàâò³â." },
{ "×àâóí", "×àâóí ó 3 ðàçè âàæ÷èé çà àëþì³í³é. Æîäíà ðåàëüíà ðàêåòà íå çðîáëåíà ç ÷àâóíó." },
{ "Ìàðìóð", "Ìàðìóð êðèõêèé ³ âàæêèé. Ó êîñìîíàâòèö³ íå âèêîðèñòîâóºòüñÿ âçàãàë³." },
{ "Ãðàí³ò", "Ãðàí³ò ó 4 ðàçè âàæ÷èé çà àëþì³í³é. Ðàêåòà ç ãðàí³òó íå çëåòèòü ç Çåìë³." },
{ "Öåãëà", "Öåãëà âàæêà ³ êðèõêà. Ìàêñèìóì ùî ìîæå -- ê³ëüêà ìåòð³â âãîðó äî âèáóõó." },
{ "Ãóìà", "Ãóìà ïëàâèòüñÿ ïðè +300C. Äâèãóíè äàþòü +3000C -- íå âèòðèìຠíàâ³òü ñåêóíäè." },
};
private float GetRealHeightKm(string planetName, string matName, int fuelLevel)
{
float[] baseFuelHeights = { 15f, 100f, 408f, 36000f, 384000f };
float baseKm = baseFuelHeights[Mathf.Clamp(fuelLevel, 0, 4)];
float planetMult = GetPlanetMultiplier(planetName);
float matMult = GetMaterialMultiplier(matName);
return baseKm * planetMult * matMult;
}
private float GetPlanetMultiplier(string planet)
{
switch (planet)
{
case "̳ñÿöü": return 6.0f;
case "Ïëóòîí": return 15.0f;
case "Ìàðñ": return 2.5f;
case "Ìåðêóð³é": return 2.5f;
case "Óðàí": return 1.1f;
case "Çåìëÿ": return 1.0f;
case "Ñàòóðí": return 0.9f;
case "Íåïòóí": return 0.85f;
case "Âåíåðà": return 0.3f;
case "Þï³òåð": return 0.1f;
default: return 1.0f;
}
}
private float GetMaterialMultiplier(string mat)
{
switch (mat)
{
case "Âóãëåöåâå âîëîêíî": return 1.0f;
case "Òèòàí": return 0.95f;
case "Ïîë³ðîâàíà ñòàëü": return 0.9f;
case "Àëþì³í³é": return 0.88f;
case "Êåðàì³êà": return 0.75f;
case "Ñòàëü": return 0.7f;
case "̳äü": return 0.6f;
case "Ïëàñòèê": return 0.55f;
case "Ñêëî": return 0.5f;
case "×àâóí": return 0.15f;
case "Ìàðìóð": return 0.45f;
case "Ãðàí³ò": return 0.35f;
case "Öåãëà": return 0.25f;
case "Ãóìà": return 0.2f;
default: return 0.5f;
}
}
private string FormatRealHeight(float km)
{
if (km < 1f) return (km * 1000f).ToString("F0") + " ì";
if (km < 1000f) return km.ToString("F0") + " êì";
if (km < 1000000f) return (km / 1000f).ToString("F1") + " òèñ. êì";
return (km / 1000000f).ToString("F2") + " ìëí. êì";
}
private string GetHeightContext(float km)
{
if (km < 12f) return "Öå âèñîòà ïîëüîòó ïàñàæèðñüêîãî ë³òàêà.";
if (km < 50f) return "Ñòðàòîñôåðà. Âèùå õìàð àëå ùå íå êîñìîñ.";
if (km < 100f) return "Ìàéæå ë³í³ÿ Êàðìàíà -- îô³ö³éíà ìåæà êîñìîñó (100 êì).";
if (km < 408f) return "Îô³ö³éíî â êîñìîñ³! ßê âèñîòà ïîëüîòó Space Shuttle.";
if (km < 36000f) return "Îðá³òà ÌÊÑ àáî âèùå. Òè ñïðàâæí³é àñòðîíàâò!";
if (km < 384000f) return "Ãåîñòàö³îíàðíà îðá³òà -- òóò âèñÿòü ñóïóòíèêè GPS ³ òåëåáà÷åííÿ.";
return "³äñòàíü ÿê äî ̳ñÿöÿ àáî äàë³. ̳æïëàíåòíèé ïðîñò³ð!";
}
private string GetRealFlightTime(float km)
{
float speedKmH = 28000f;
float hours = km / speedKmH;
if (hours < 0.017f) return (hours * 3600f).ToString("F0") + " ñåêóíä";
if (hours < 1f) return (hours * 60f).ToString("F0") + " õâèëèí";
if (hours < 24f) return hours.ToString("F1") + " ãîäèí";
if (hours < 720f) return (hours / 24f).ToString("F1") + " ä³á";
if (hours < 8760f) return (hours / 720f).ToString("F1") + " ì³ñÿö³â";
return (hours / 8760f).ToString("F1") + " ðîê³â";
}
private float GetShakeMultiplier(string planet)
{
switch (planet)
{
case "Þï³òåð": return 2.5f;
case "Âåíåðà": return 1.8f;
case "Íåïòóí": return 2.0f;
case "Ñàòóðí": return 1.2f;
case "Çåìëÿ": return 1.0f;
case "Óðàí": return 0.8f;
case "Ìàðñ": return 0.6f;
case "Ìåðêóð³é": return 0.4f;
case "̳ñÿöü": return 0.3f;
case "Ïëóòîí": return 0.2f;
default: return 1.0f;
}
}
private void Explode()
{
effectsController.StopFlight();
cameraController.StopFlight();
Vector3 pos = rocketRoot.position;
MeshRenderer[] meshes = rocketRoot.GetComponentsInChildren<MeshRenderer>();
Vector3 meshCenter = pos;
if (meshes.Length > 0)
{
meshCenter = Vector3.zero;
foreach (var mr in meshes) meshCenter += mr.bounds.center;
meshCenter /= meshes.Length;
}
if (explosionBig != null)
{
var big = Instantiate(explosionBig, meshCenter, Quaternion.identity);
big.transform.localScale = Vector3.one * 5f;
RemoveMissingScripts(big);
}
if (explosionMedium != null)
{
for (int i = 0; i < 3; i++)
{
var med = Instantiate(explosionMedium,
meshCenter + new Vector3(Random.Range(-1.2f, 1.2f), Random.Range(-0.5f, 0.8f), 0f),
Quaternion.identity);
med.transform.localScale = Vector3.one * 3f;
RemoveMissingScripts(med);
}
}
if (explosionSmall != null)
{
for (int i = 0; i < 6; i++)
{
var sm = Instantiate(explosionSmall,
meshCenter + new Vector3(Random.Range(-2f, 2f), Random.Range(-1f, 2f), Random.Range(-1f, 1f)),
Quaternion.identity);
sm.transform.localScale = Vector3.one * 2.2f;
RemoveMissingScripts(sm);
}
}
if (debrisPrefab != null)
{
var debris = Instantiate(debrisPrefab, meshCenter, Quaternion.identity);
debris.SetActive(true);
foreach (var piece in debris.GetComponentsInChildren<DebrisPiece>())
{
piece.transform.position = meshCenter + Random.insideUnitSphere * 0.8f;
piece.Launch(meshCenter, Random.Range(15f, 30f), materialSelector.GetCurrentMaterial().material);
}
}
SetFlamesActive(false);
rocketRoot.gameObject.SetActive(false);
StartCoroutine(ShowInfoAndReset());
}
private void RemoveMissingScripts(GameObject obj)
{
foreach (var b in obj.GetComponentsInChildren<MonoBehaviour>())
if (b == null) DestroyImmediate(b);
}
private IEnumerator SpaceDriftAndInfo()
{
cameraController.SwitchToSpaceDrift();
effectsController.PlaySpaceDriftParticles();
float driftTime = 0f;
float driftAngle = 0f;
Vector3 driftCenter = rocketRoot.position;
while (driftTime < 3f)
{
driftTime += Time.deltaTime;
driftAngle += Time.deltaTime * 15f;
rocketRoot.position = driftCenter + new Vector3(
Mathf.Sin(driftAngle * Mathf.Deg2Rad) * 0.3f,
Mathf.Cos(driftAngle * Mathf.Deg2Rad * 0.5f) * 0.15f, 0f);
rocketRoot.rotation = Quaternion.Lerp(rocketRoot.rotation,
_rocketStartRot * Quaternion.Euler(25f, driftAngle * 0.3f, 10f), Time.deltaTime * 0.5f);
yield return null;
}
SetFlamesActive(false);
yield return new WaitForSeconds(1.5f);
rocketRoot.gameObject.SetActive(false);
effectsController.StopAllParticles();
StartCoroutine(ShowInfoAndReset());
}
private IEnumerator ShowInfoAndReset()
{
yield return new WaitForSeconds(1.5f);
int fuelLevel = fuelSelector.GetFuelLevel();
string planetName = planetSelector.GetCurrentPlanet().name;
string matName = materialSelector.GetCurrentMaterial().name;
bool exploded = _explodeOnLaunch.Contains(matName) || _explodeSoon.Contains(matName) || _planetExplode.Contains(planetName);
float realKm = GetRealHeightKm(planetName, matName, fuelLevel);
string realHeightStr = FormatRealHeight(realKm);
string heightContext = GetHeightContext(realKm);
string info;
if (exploded)
{
string reason = _planetExplode.Contains(planetName)
? (_planetExplosionReason.ContainsKey(planetName) ? _planetExplosionReason[planetName] : "Ïëàíåòà çíèùèëà ðàêåòó.")
: (_materialExplosionReason.ContainsKey(matName) ? _materialExplosionReason[matName] : "Ìàòåð³àë íå âèòðèìàâ íàâàíòàæåíü ïîëüîòó.");
string planetInfo = _planetFacts.ContainsKey(planetName) ? _planetFacts[planetName] : "";
info = "ÐÅÇÓËÜÒÀÒ ÏÎËÜÎÒÓ\n\n"
+ "Ìàòåð³àë: " + matName + "\nÏëàíåòà: " + planetName + "\n"
+ "Ïàëüíå: " + fuelSelector.GetFuelName() + "\n\n"
+ "ÏÐÈ×ÈÍÀ ÊÀÒÀÑÒÐÎÔÈ:\n" + reason + "\n\n"
+ "ÏÐÎ ÏËÀÍÅÒÓ:\n" + planetInfo;
}
else
{
string escapeNote = flightCore.RocketEscaped
? "Ðàêåòà äîñÿãëà äðóãî¿ êîñì³÷íî¿ øâèäêîñò³!\n\n" : "";
string planetInfo = _planetFacts.ContainsKey(planetName) ? _planetFacts[planetName] : "";
string matFact = _materialFacts.ContainsKey(matName) ? _materialFacts[matName] : "";
string flightTime = GetRealFlightTime(realKm);
info = "ÐÅÇÓËÜÒÀÒ ÏÎËÜÎÒÓ\n\n"
+ "Ìàòåð³àë: " + matName + "\n"
+ "Ïëàíåòà: " + planetName + "\n"
+ "Ïàëüíå: " + fuelSelector.GetFuelName() + "\n\n"
+ escapeNote
+ "Ó ÐÅÀËÜÍÎÑÒ² ÒÀÊÀ ÐÀÊÅÒÀ ÇËÅÒ²ËÀ Á ÍÀ:\n"
+ realHeightStr + "\n"
+ heightContext + "\n"
+ "×àñ ïîëüîòó: " + flightTime + "\n\n"
+ "ÔÀÊÒ ÏÐÎ ÌÀÒÅвÀË:\n" + matFact + "\n\n"
+ "ÏÐÎ ÏËÀÍÅÒÓ:\n" + planetInfo + "\n\n"
+ "Ö²ÊÀÂÎ: Äî ̳ñÿöÿ 3 äîáè. Äî Íåïòóíà 12 ðîê³â!";
}
if (infoPanelText != null) infoPanelText.text = info;
if (infoPanel != null) infoPanel.SetActive(true);
yield return new WaitForSeconds(18f);
ResetAll();
}
private void ResetAll()
{
_isLaunched = false;
_sonicBoomDone = false;
GameObject[] allObjects = GameObject.FindObjectsOfType<GameObject>();
foreach (var obj in allObjects)
{
if (obj != null && obj.name.Contains("(Clone)"))
Destroy(obj);
}
flightCore.ResetFlight();
cameraController.ResetCamera();
rocketRoot.position = _rocketStartPos;
rocketRoot.rotation = _rocketStartRot;
rocketRoot.gameObject.SetActive(true);
SetFlamesActive(true);
var pd = planetSelector.GetCurrentPlanet();
effectsController.ResetEffects(new RocketEffectsController.PlanetData
{
atmosphereThickness = pd.atmosphereThickness,
exposure = pd.exposure,
skyTint = pd.skyTint,
groundColor = pd.groundColor,
hasFog = pd.hasFog,
fogDensity = pd.fogDensity,
fogColor = pd.fogColor,
sunLightIntensity = pd.sunLightIntensity
});
planetSelector.RestoreCurrentPlanet();
if (infoPanel != null) infoPanel.SetActive(false);
if (materialPanel != null) materialPanel.SetActive(true);
}
private void SetFlamesActive(bool active)
{
foreach (var flame in flameParts)
if (flame != null) flame.gameObject.SetActive(active);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5449c60f157728f448e148f763d19eab
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,136 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class RocketMaterialSelector : MonoBehaviour
{
[SerializeField] private Renderer _cylinderMain;
[SerializeField] private Renderer _cylinder005;
[SerializeField] private Renderer _cylinder015;
[SerializeField] private TextMeshProUGUI _materialNameText;
[SerializeField] private Button _leftButton;
[SerializeField] private Button _rightButton;
private int _currentIndex = 0;
public struct RocketMaterial
{
public string name;
public Material material;
public float dragCoefficient;
public bool explodes;
public string explodeReason;
}
private List<RocketMaterial> _materials = new();
[Header("Матеріали")]
[SerializeField] private Material _matCarbonFiber;
[SerializeField] private Material _matTitanium;
[SerializeField] private Material _matSteelPolished;
[SerializeField] private Material _matAluminium;
[SerializeField] private Material _matCeramic;
[SerializeField] private Material _matSteel;
[SerializeField] private Material _matCopper;
[SerializeField] private Material _matCastIron;
[SerializeField] private Material _matGlass;
[SerializeField] private Material _matPlastic;
[SerializeField] private Material _matMarble;
[SerializeField] private Material _matGold;
[SerializeField] private Material _matWood;
[SerializeField] private Material _matRubber;
[SerializeField] private Material _matBrick;
[SerializeField] private Material _matAsphalt;
[SerializeField] private Material _matGranite;
[SerializeField] private Material _matIce;
[SerializeField] private Material _matSnow;
[SerializeField] private Material _matAvocado;
[SerializeField] private Material _matDuck;
[SerializeField] private Material _matLychee;
[SerializeField] private Material _matPaper;
private void Start()
{
BuildMaterialList();
if (_leftButton != null) _leftButton.onClick.AddListener(PrevMaterial);
if (_rightButton != null) _rightButton.onClick.AddListener(NextMaterial);
ShowMaterial(0);
}
private void BuildMaterialList()
{
_materials.Add(new RocketMaterial { name = "Вуглецеве волокно", material = _matCarbonFiber, dragCoefficient = 0.05f, explodes = false });
_materials.Add(new RocketMaterial { name = "Титан", material = _matTitanium, dragCoefficient = 0.08f, explodes = false });
_materials.Add(new RocketMaterial { name = "Полірована сталь", material = _matSteelPolished, dragCoefficient = 0.12f, explodes = false });
_materials.Add(new RocketMaterial { name = "Алюміній", material = _matAluminium, dragCoefficient = 0.15f, explodes = false });
_materials.Add(new RocketMaterial { name = "Кераміка", material = _matCeramic, dragCoefficient = 0.18f, explodes = false });
_materials.Add(new RocketMaterial { name = "Сталь", material = _matSteel, dragCoefficient = 0.25f, explodes = false });
_materials.Add(new RocketMaterial { name = "Мідь", material = _matCopper, dragCoefficient = 0.30f, explodes = false });
_materials.Add(new RocketMaterial { name = "Чавун", material = _matCastIron, dragCoefficient = 0.38f, explodes = false });
_materials.Add(new RocketMaterial { name = "Скло", material = _matGlass, dragCoefficient = 0.20f, explodes = false });
_materials.Add(new RocketMaterial { name = "Пластик", material = _matPlastic, dragCoefficient = 0.22f, explodes = false });
_materials.Add(new RocketMaterial { name = "Мармур", material = _matMarble, dragCoefficient = 0.42f, explodes = false });
_materials.Add(new RocketMaterial { name = "Золото", material = _matGold, dragCoefficient = 0.35f, explodes = true, explodeReason = "Золото надто важке - ракета падає одразу! 💥" });
_materials.Add(new RocketMaterial { name = "Дерево", material = _matWood, dragCoefficient = 0.55f, explodes = true, explodeReason = "Дерево займається від тертя об повітря!" });
_materials.Add(new RocketMaterial { name = "Гума", material = _matRubber, dragCoefficient = 0.70f, explodes = false });
_materials.Add(new RocketMaterial { name = "Цегла", material = _matBrick, dragCoefficient = 0.75f, explodes = false });
_materials.Add(new RocketMaterial { name = "Асфальт", material = _matAsphalt, dragCoefficient = 0.72f, explodes = true, explodeReason = "Асфальт плавиться і ракета розпадається!" });
_materials.Add(new RocketMaterial { name = "Граніт", material = _matGranite, dragCoefficient = 0.65f, explodes = false });
_materials.Add(new RocketMaterial { name = "Лід", material = _matIce, dragCoefficient = 0.10f, explodes = true, explodeReason = "Лід миттєво тане і ракета вибухає!" });
_materials.Add(new RocketMaterial { name = "Сніжок", material = _matSnow, dragCoefficient = 0.95f, explodes = true, explodeReason = "Сніжок випаровується на старті!" });
_materials.Add(new RocketMaterial { name = "Авокадо", material = _matAvocado, dragCoefficient = 0.85f, explodes = true, explodeReason = "Авокадо згорає за 3 секунди! 🥑💥" });
_materials.Add(new RocketMaterial { name = "Гумова качечка", material = _matDuck, dragCoefficient = 0.98f, explodes = true, explodeReason = "Качечка розплавилась! 🦆💥" });
_materials.Add(new RocketMaterial { name = "Лічі", material = _matLychee, dragCoefficient = 0.88f, explodes = true, explodeReason = "Лічі згоріло в атмосфері! 💥" });
_materials.Add(new RocketMaterial { name = "Папір", material = _matPaper, dragCoefficient = 0.99f, explodes = true, explodeReason = "Папір миттєво згорів! 📄🔥" });
}
private void ShowMaterial(int index)
{
var mat = _materials[index];
if (_materialNameText != null)
_materialNameText.text = mat.name;
if (mat.material != null)
{
if (_cylinderMain != null) _cylinderMain.materials = SetElement0(mat.material, _cylinderMain.materials);
if (_cylinder005 != null) _cylinder005.materials = SetElement0(mat.material, _cylinder005.materials);
if (_cylinder015 != null) _cylinder015.materials = SetElement0(mat.material, _cylinder015.materials);
}
if (_leftButton != null) _leftButton.interactable = index > 0;
if (_rightButton != null) _rightButton.interactable = index < _materials.Count - 1;
}
private Material[] SetElement0(Material newMat, Material[] current)
{
Material[] updated = new Material[current.Length];
for (int i = 0; i < current.Length; i++)
updated[i] = current[i];
updated[0] = newMat;
return updated;
}
private void NextMaterial()
{
if (_currentIndex < _materials.Count - 1)
{
_currentIndex++;
ShowMaterial(_currentIndex);
}
}
private void PrevMaterial()
{
if (_currentIndex > 0)
{
_currentIndex--;
ShowMaterial(_currentIndex);
}
}
public RocketMaterial GetCurrentMaterial() => _materials[_currentIndex];
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c78a6d2a1612c714b9c42010e4b912c7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: