using System; using System.Collections.Generic; using UnityEngine; public class OrbitalPosition { public Int64 pRing = 0; public float DistanceFromCentre = 0; public float RadiusDistance = 0; public Transform owner = null; public OrbitalPosition(GameObject _owner) { pRing = GlobalOrbitalPositionManager.LastRingID; owner = _owner.transform; } public Vector3 TranslateToVec3() => new ( x: DistanceFromCentre * Mathf.Cos(RadiusDistance), y: DistanceFromCentre * Mathf.Sin(RadiusDistance) ); } public class Ring : MonoBehaviour { public Int64 ID; } public class GlobalOrbitalPositionManager : MonoBehaviour { static GlobalOrbitalPositionManager s_Instance = null; private readonly List m_ObjectInstances = new(); private readonly List m_Rings = new(); private readonly Dictionary m_Distances = new(); private float m_TimeOfLastRingSpawn = float.NegativeInfinity; private Int64 m_LastGeneratedRing = 0; public static Int64 LastRingID => s_Instance.m_LastGeneratedRing; public static float GetDistanceOf(Int64 rowID) => s_Instance.m_Distances[rowID]; Vector3[] m_PrecalculatedPositions; [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] private static void OnApplicationStart() { GameObject manager = new("GLOBAL ORBITAL MANAGER"); DontDestroyOnLoad(manager); s_Instance = manager.AddComponent(); s_Instance.m_PrecalculatedPositions = new Vector3[365]; for (int i = 0; i < 365; i++) { s_Instance.m_PrecalculatedPositions[i] = new Vector3 ( x: Mathf.Cos(Mathf.Deg2Rad * i), y: Mathf.Sin(Mathf.Deg2Rad * i), z: 0 ); } } public void Update() { if (Time.time - m_TimeOfLastRingSpawn > GlobalOrbitalSettings.GapDistance) { GameObject newRing = Instantiate(GlobalOrbitalSettings.RingPrefab); newRing.transform.localScale = new Vector3(10f, 10f, 1); Ring ring = newRing.AddComponent(); ring.ID = m_LastGeneratedRing + 1; m_Rings.Add(ring); LineRenderer renderer = newRing.GetComponentInChildren(); renderer.positionCount = 365; renderer.startWidth = 0.1f; renderer.endWidth = 0.1f; renderer.material = new(Shader.Find("Sprites/Default")); renderer.startColor = Color.white; renderer.endColor = Color.white; m_LastGeneratedRing = ring.ID; m_TimeOfLastRingSpawn = Time.time; } List toRemove = new(); int index = 0; m_Distances.Clear(); foreach (Ring ring in m_Rings) { float diff = Time.deltaTime * GlobalOrbitalSettings.DistanceSpeed; ring.transform.localScale -= new Vector3(diff, diff, 0f); LineRenderer renderer = ring.GetComponentInChildren(); for (int vert = 0; vert < 365; vert++) { renderer.SetPosition(vert, m_PrecalculatedPositions[vert] * ring.transform.localScale.x); } if (ring.transform.localScale.x < 0) { toRemove.Add(ring); } m_Distances[ring.ID] = ring.transform.localScale.x; index++; } foreach (Ring ring in toRemove) { m_Rings.Remove(ring); Destroy(ring.gameObject); } foreach (OrbitalPosition orbitalPosition in m_ObjectInstances) { if (!m_Distances.ContainsKey(orbitalPosition.pRing)) orbitalPosition.pRing = m_LastGeneratedRing; float distance = m_Distances[orbitalPosition.pRing]; orbitalPosition.DistanceFromCentre = distance; orbitalPosition.RadiusDistance = (orbitalPosition.RadiusDistance + (Time.deltaTime * GlobalOrbitalSettings.RadiusSpeed)) % (Mathf.PI * 2); orbitalPosition.owner.position = orbitalPosition.TranslateToVec3(); } } public static void RegisterOrbitalPositionInstance(OrbitalPosition newInstance) => s_Instance.m_ObjectInstances.Add(newInstance); public static void UnregisterOrbitalPositionInstance(OrbitalPosition removedInstance) => s_Instance.m_ObjectInstances.Remove(removedInstance); } public abstract class OrbitalPositionBehaviour : MonoBehaviour { protected OrbitalPosition m_OrbitalPosition = null; private void Start() { m_OrbitalPosition = new OrbitalPosition(gameObject); GlobalOrbitalPositionManager.RegisterOrbitalPositionInstance(m_OrbitalPosition); OnStart(); } private void OnDestroy() => GlobalOrbitalPositionManager.UnregisterOrbitalPositionInstance(m_OrbitalPosition); public abstract void OnStart(); }