Files
U10-MobileGame/Assets/Scripts/OrbitalPosition.cs
2025-11-20 11:32:52 +00:00

199 lines
6.5 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
public class OrbitalPosition
{
public int m_AttachedRing;
public float m_DistanceFromCentre;
public float m_RadiusDistance;
public float m_ObjectRadius = 0.1f;
public OrbitalPositionBehaviour m_Behaviour;
public readonly Transform m_Owner;
public int m_SpinSpeed = 1;
public OrbitalPosition(GameObject owner)
{
m_AttachedRing = GlobalOrbitalPositionManager.LastRingID;
m_Owner = owner.transform;
}
public Vector3 TranslateToVec3() => new
(
x: m_DistanceFromCentre * Mathf.Cos(m_RadiusDistance),
y: m_DistanceFromCentre * Mathf.Sin(m_RadiusDistance)
);
}
public class Ring : MonoBehaviour
{
public int ID;
}
public class GlobalOrbitalPositionManager : MonoBehaviour
{
static GlobalOrbitalPositionManager s_Instance = null;
private readonly List<OrbitalPosition> m_ObjectInstances = new();
private readonly List<Ring> m_Rings = new();
private readonly Dictionary<Int64, float> m_Distances = new();
private OrbitalPosition m_PlayerOrbitalPosition;
public static void SetPlayer(OrbitalPosition player) => s_Instance.m_PlayerOrbitalPosition = player;
private float m_TimeOfLastRingSpawn = float.NegativeInfinity;
private int m_LastGeneratedRing = 0;
public static int LastRingID => s_Instance.m_LastGeneratedRing;
public static float GetDistanceOf(int rowID) => s_Instance.m_Distances[rowID];
private const int CirclePoints = 360;
Vector3[] m_PrecalculatedPositions;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] private static void OnApplicationStart()
{
GameObject manager = new("GLOBAL ORBITAL MANAGER");
DontDestroyOnLoad(manager);
s_Instance = manager.AddComponent<GlobalOrbitalPositionManager>();
s_Instance.m_PrecalculatedPositions = new Vector3[CirclePoints + 1];
for (int i = 0; i < CirclePoints; i++)
{
s_Instance.m_PrecalculatedPositions[i] = new Vector3
(
x: Mathf.Cos(Mathf.Deg2Rad * i),
y: Mathf.Sin(Mathf.Deg2Rad * i),
z: 0
);
}
s_Instance.m_PrecalculatedPositions[CirclePoints] = s_Instance.m_PrecalculatedPositions[0];
}
private 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>();
ring.ID = m_LastGeneratedRing + 1;
m_Rings.Add(ring);
LineRenderer lineRenderer = newRing.GetComponentInChildren<LineRenderer>();
lineRenderer.positionCount = CirclePoints + 1;
lineRenderer.startWidth = 0.1f;
lineRenderer.endWidth = 0.1f;
lineRenderer.material = new Material(Shader.Find("Sprites/Default"));
m_LastGeneratedRing = ring.ID;
m_TimeOfLastRingSpawn = Time.time;
}
List<Ring> 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 lineRenderer = ring.GetComponentInChildren<LineRenderer>();
for (int vert = 0; vert < CirclePoints + 1; vert++)
{
lineRenderer.SetPosition(vert, m_PrecalculatedPositions[vert] * ring.transform.localScale.x);
}
float opacity = (ring.transform.localScale.x - 0.5f) / 4f;
opacity = Mathf.Clamp(opacity, 0, 0.5f);
if (ring.transform.localScale.x < 0.5f)
toRemove.Add(ring);
Color c = Color.white;
c.a = opacity;
lineRenderer.startColor = c;
lineRenderer.endColor = c;
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.m_AttachedRing))
{
orbitalPosition.m_Behaviour.OnReachCentre();
orbitalPosition.m_AttachedRing = m_LastGeneratedRing;
}
float distance = m_Distances[orbitalPosition.m_AttachedRing];
orbitalPosition.m_DistanceFromCentre = distance;
orbitalPosition.m_RadiusDistance = (orbitalPosition.m_RadiusDistance + (Time.deltaTime * GlobalOrbitalSettings.RadiusSpeed)) % (Mathf.PI * 2);
orbitalPosition.m_Owner.position = orbitalPosition.TranslateToVec3();
}
}
private void FixedUpdate()
{
foreach (OrbitalPosition orbital in m_ObjectInstances)
{
if (orbital == m_PlayerOrbitalPosition)
continue;
Vector2 a = orbital.TranslateToVec3();
Vector2 b = m_PlayerOrbitalPosition.TranslateToVec3();
float distance = (a - b).magnitude;
float radii = orbital.m_ObjectRadius + m_PlayerOrbitalPosition.m_ObjectRadius;
if (distance < radii)
{
orbital.m_Behaviour.OnCollision(m_PlayerOrbitalPosition.m_Behaviour);
m_PlayerOrbitalPosition.m_Behaviour.OnCollision(orbital.m_Behaviour);
}
}
}
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)
{
m_Behaviour = this
};
GlobalOrbitalPositionManager.RegisterOrbitalPositionInstance(m_OrbitalPosition);
OnStart();
}
private void OnDestroy() =>
GlobalOrbitalPositionManager.UnregisterOrbitalPositionInstance(m_OrbitalPosition);
protected virtual void OnStart() { }
public virtual void OnReachCentre() { }
public virtual void OnCollision(OrbitalPositionBehaviour other) { }
}