using SolarSystemUI;
using Unity.VisualScripting;
using UnityEngine;
using Utils;
namespace SolarSystem
{
public class PlanetController : MonoBehaviour
{
public GameObject StarPrefab;
public GameObject PlanetaryRingsPrefab;
public GameObject AxialTiltMarkerPrefab;
public GameObject SpinDirectionMarkerPrefab;
public bool ReverseOrbitDirection;
// LIGHT DEBUGGING
public GameObject LightMarkerPrefab;
private GameObject _lightMarker;
// LIGHT DEBUGGING
private float _elapsedTime;
private GameObject _planetaryRings;
private GameObject _axialTiltMarker;
private GameObject _spinDirectionMarker;
private UI_DebugMarkers _uiDebugMarkers;
private PlanetInfo _planetInfo;
private Rigidbody _rigidBody;
private Light _planetLight;
private float _distanceFromPlanet;
private MaterialPropertyBlock _materialPropertyBlock;
private Vector3 _startingPosition;
private Vector3 _orbitCenter;
private float _orbitRadius;
private static readonly int _innerRadius = Shader.PropertyToID("_InnerRadius");
private static readonly int _ringColor = Shader.PropertyToID("_RingColor");
private static readonly int BaseMap = Shader.PropertyToID("_BaseMap");
private static readonly int MainTexture = Shader.PropertyToID("_MainTexture");
public void Start()
{
_planetInfo = GetComponent<PlanetInfo>();
_rigidBody = GetComponent<Rigidbody>();
_uiDebugMarkers = GameObject.Find("UI_DebugMarkers").GetComponent<UI_DebugMarkers>();
_materialPropertyBlock = new MaterialPropertyBlock();
AssignMaterialProperties();
SetGOStartingPositionRotation();
SetGOScale();
_distanceFromPlanet = transform.localScale.x + 2f;
SetGOAxialTiltMarker();
SetGOSpinDirectionMarker();
//TrySetGOPlanetaryRings();
_orbitCenter = StarPrefab.transform.position;
_orbitRadius = Vector3.Distance(transform.position, _orbitCenter);
// Calculate initial elapsed time based on the starting position (for orbit)
float initialAngle = Mathf.Atan2(transform.position.z - _orbitCenter.z, transform.position.x - _orbitCenter.x);
_elapsedTime = initialAngle / Mathf.Deg2Rad / (360.0f / _planetInfo.OrbitalPeriod);
SetGOInitialComps();
// Instantiate and set up the light marker
if (LightMarkerPrefab != null)
{
_lightMarker = Instantiate(LightMarkerPrefab);
}
}
public void Update()
{
ToggleMarkerVisibility();
}
private void FixedUpdate()
{
CalculatePlanetaryLightPosition();
// Update the light marker position
if (_lightMarker is not null && _planetLight is not null)
{
_lightMarker.transform.position = _planetLight.transform.position;
}
if (GameSpeedController.Instance is null) return;
OrbitAroundStar();
RotateAroundOwnAxis();
}
private void AssignMaterialProperties()
{
switch (_planetInfo.PlanetType)
{
case "RockyPlanet":
{
Texture2D[] texturesRP = Resources.LoadAll<Texture2D>("Textures/RockyPlanet");
if (texturesRP.Length == 0)
{
Debug.LogWarning("No textures found in `Resources/Textures/RockyPlanet`");
return;
}
Texture2D randomTexture = texturesRP[Random.Range(0, texturesRP.Length)];
_materialPropertyBlock.SetTexture(BaseMap, randomTexture);
GetComponent<MeshRenderer>().SetPropertyBlock(_materialPropertyBlock);
break;
}
case "GasGiant":
{
Texture2D[] texturesGG = Resources.LoadAll<Texture2D>("Textures/GasGiant");
if (texturesGG.Length == 0)
{
Debug.LogWarning("No textures found in `Resources/Textures/GasGiant`");
return;
}
Texture2D randomTexture = texturesGG[Random.Range(0, texturesGG.Length)];
_materialPropertyBlock.SetTexture(MainTexture, randomTexture);
GetComponent<MeshRenderer>().SetPropertyBlock(_materialPropertyBlock);
break;
}
}
}
private void SetGOInitialComps()
{
if (_rigidBody is null) return;
_rigidBody.mass = _planetInfo.Mass;
_rigidBody.constraints = RigidbodyConstraints.FreezePositionY;
_rigidBody.useGravity = false;
if (_planetInfo == null) return;
_planetLight = transform.AddComponent<Light>();
_planetLight.cullingMask = 1 << LayerMask.NameToLayer(_planetInfo.LayerName);
_planetLight.type = LightType.Directional;
_planetLight.color = Color.white;
_planetLight.intensity = 1f;
}
private void SetGOScale()
{
if (transform.parent == null) return;
Vector3 desiredWorldScale = new (_planetInfo.GO_Radius, _planetInfo.GO_Radius, _planetInfo.GO_Radius);
Vector3 parentScale = transform.parent.localScale;
transform.localScale = new Vector3(
desiredWorldScale.x / parentScale.x,
desiredWorldScale.y / parentScale.y,
desiredWorldScale.z / parentScale.z
);
}
private void SetGOStartingPositionRotation()
{
float radius = _planetInfo.Index;
float angle = Random.Range(0f, Mathf.PI * 2);
float xComponent = Mathf.Cos(angle) * radius;
float zComponent = Mathf.Sin(angle) * radius;
_startingPosition = new Vector3(xComponent, 0f, zComponent);
transform.position = _startingPosition;
transform.rotation = Quaternion.Euler(0, 0, _planetInfo.AxialTilt);
}
private void SetGOAxialTiltMarker()
{
_axialTiltMarker = Instantiate(AxialTiltMarkerPrefab, transform.position, Quaternion.identity);
_axialTiltMarker.transform.parent = transform;
_axialTiltMarker.transform.localPosition = Vector3.zero;
_axialTiltMarker.transform.localScale = new Vector3(1.0f, 1.0f, 0.0f);
_axialTiltMarker.transform.localRotation = Quaternion.Euler(-_planetInfo.AxialTilt, 0f, 0f);
}
private void SetGOSpinDirectionMarker()
{
_spinDirectionMarker = Instantiate(SpinDirectionMarkerPrefab, transform.position, Quaternion.identity);
_spinDirectionMarker.transform.parent = transform;
_spinDirectionMarker.transform.localPosition = Vector3.zero;
_spinDirectionMarker.transform.localScale = new Vector3(1.0f, 1.0f, 0.0f);
_spinDirectionMarker.transform.localRotation = Quaternion.Euler(0f, 0f, 0f);
}
private void TrySetGOPlanetaryRings() // TODO: FIX THIS SHIT
{
if (!_planetInfo.HasRings) return;
_planetaryRings = Instantiate(PlanetaryRingsPrefab, transform.position, Quaternion.identity);
_planetaryRings.transform.parent = transform;
_planetaryRings.transform.localPosition = Vector3.zero;
float minInner = _planetInfo.Info_Radius + 3f;
float maxInner = _planetInfo.Info_Radius + 7.5f;
_planetInfo.InnerRingRadius = Mathf.InverseLerp(minInner, maxInner, _planetInfo.InnerRingRadius);
_planetInfo.InnerRingRadius = Mathf.Clamp(_planetInfo.InnerRingRadius, 0.1f, 0.4f);
_planetaryRings.transform.localScale = new Vector3(_planetInfo.OuterRingRadius, 0f, _planetInfo.OuterRingRadius);
_planetaryRings.transform.localRotation = _planetaryRings.transform.parent.localRotation;
_planetaryRings.transform.GetComponent<MeshRenderer>().material.SetFloat(_innerRadius, _planetInfo.InnerRingRadius);
_planetaryRings.transform.GetComponent<MeshRenderer>().material.SetColor(_ringColor, TryGenerateRandomRingsColor());
}
private static Color TryGenerateRandomRingsColor()
{
float r = Random.Range(0.8f, 1.0f);
float g = Random.Range(0.7f, 0.74f);
float b = Random.Range(0.53f, 0.57f);
return new Color(r, g, b);
}
private void RotateAroundOwnAxis()
{
transform.Rotate(Vector3.up, Time.fixedDeltaTime * GameSpeedController.Instance.CurSpeed);
}
private void OrbitAroundStar()
{
_elapsedTime += Time.fixedDeltaTime * GameSpeedController.Instance.CurSpeed;
float angle = (_elapsedTime * (ReverseOrbitDirection ? -1 : 1) * 360.0f / ((_planetInfo.OrbitalPeriod / ConstantsUtil.EARTH_YEAR) / 0.01f));
float radians = angle * Mathf.Deg2Rad;
Vector3 newPos = new(
_orbitCenter.x + Mathf.Cos(radians) * _orbitRadius,
_orbitCenter.y,
_orbitCenter.z + Mathf.Sin(radians) * _orbitRadius
);
transform.position = newPos;
}
private void CalculatePlanetaryLightPosition()
{
Vector3 directionToStar = (StarPrefab.transform.position - transform.position).normalized;
_planetLight.transform.position = transform.position + directionToStar * _distanceFromPlanet;
_planetLight.transform.LookAt(transform);
}
private void ToggleMarkerVisibility()
{
if (_uiDebugMarkers is null) return;
_axialTiltMarker?.SetActive(_uiDebugMarkers.ShowAxialTiltMarkers);
_spinDirectionMarker?.SetActive(_uiDebugMarkers.ShowSpinDirectionMarkers);
}
}
}