initial commit
This commit is contained in:
29
Assets/Scripts/Rocket/DebrisPiece.cs
Normal file
29
Assets/Scripts/Rocket/DebrisPiece.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Rocket/DebrisPiece.cs.meta
Normal file
11
Assets/Scripts/Rocket/DebrisPiece.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 40e8c17f55516d449b2265de490b12ed
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
61
Assets/Scripts/Rocket/FuelSelector.cs
Normal file
61
Assets/Scripts/Rocket/FuelSelector.cs
Normal 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];
|
||||
}
|
||||
11
Assets/Scripts/Rocket/FuelSelector.cs.meta
Normal file
11
Assets/Scripts/Rocket/FuelSelector.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 712753361289423459f1e2e0403202d1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
330
Assets/Scripts/Rocket/PlanetSelector.cs
Normal file
330
Assets/Scripts/Rocket/PlanetSelector.cs
Normal 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];
|
||||
}
|
||||
11
Assets/Scripts/Rocket/PlanetSelector.cs.meta
Normal file
11
Assets/Scripts/Rocket/PlanetSelector.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 083c5b6135a7aea4c829d66d65103711
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
184
Assets/Scripts/Rocket/RocketCameraController.cs
Normal file
184
Assets/Scripts/Rocket/RocketCameraController.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Rocket/RocketCameraController.cs.meta
Normal file
11
Assets/Scripts/Rocket/RocketCameraController.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ccd867d9a0c9c204aaca5686da3fbdaa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
14
Assets/Scripts/Rocket/RocketCursor.cs
Normal file
14
Assets/Scripts/Rocket/RocketCursor.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Rocket/RocketCursor.cs.meta
Normal file
11
Assets/Scripts/Rocket/RocketCursor.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b442698049db8444aa5df37b90cfb0ef
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
490
Assets/Scripts/Rocket/RocketEffectsController.cs
Normal file
490
Assets/Scripts/Rocket/RocketEffectsController.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Rocket/RocketEffectsController.cs.meta
Normal file
11
Assets/Scripts/Rocket/RocketEffectsController.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 697f2cde5d094fa49a5ba3d3ba0e77e6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
191
Assets/Scripts/Rocket/RocketFlightCore.cs
Normal file
191
Assets/Scripts/Rocket/RocketFlightCore.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Rocket/RocketFlightCore.cs.meta
Normal file
11
Assets/Scripts/Rocket/RocketFlightCore.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eb2f502c8f8778d4986bebaf5e4fb5f0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
498
Assets/Scripts/Rocket/RocketLauncher.cs
Normal file
498
Assets/Scripts/Rocket/RocketLauncher.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Rocket/RocketLauncher.cs.meta
Normal file
11
Assets/Scripts/Rocket/RocketLauncher.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5449c60f157728f448e148f763d19eab
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
136
Assets/Scripts/Rocket/RocketMaterialSelector.cs
Normal file
136
Assets/Scripts/Rocket/RocketMaterialSelector.cs
Normal 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];
|
||||
}
|
||||
11
Assets/Scripts/Rocket/RocketMaterialSelector.cs.meta
Normal file
11
Assets/Scripts/Rocket/RocketMaterialSelector.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c78a6d2a1612c714b9c42010e4b912c7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user