266 lines
8.9 KiB
C#
266 lines
8.9 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
[System.Serializable] public class OrbitalPosition
|
|
{
|
|
public int m_AttachedRing;
|
|
public float m_DistanceFromCentre;
|
|
public float m_DistanceAlongRadius;
|
|
public float m_ObjectRadius = 0.1f;
|
|
public bool m_IsAttachedToRings = true;
|
|
|
|
public OrbitalPositionBehaviour m_Behaviour;
|
|
public readonly Transform m_Owner;
|
|
|
|
public float m_SpinSpeed = 1f;
|
|
|
|
public OrbitalPosition(GameObject owner)
|
|
{
|
|
m_AttachedRing = GlobalOrbitalPositionManager.LastRingID;
|
|
m_Owner = owner.transform;
|
|
}
|
|
|
|
public Vector3 TranslateToVec3() => new
|
|
(
|
|
x: m_DistanceFromCentre * Mathf.Cos(m_DistanceAlongRadius),
|
|
y: m_DistanceFromCentre * Mathf.Sin(m_DistanceAlongRadius)
|
|
);
|
|
}
|
|
|
|
public class Ring : MonoBehaviour
|
|
{
|
|
public int m_ID;
|
|
}
|
|
|
|
public class GlobalOrbitalPositionManager : MonoBehaviour
|
|
{
|
|
private static GlobalOrbitalPositionManager s_Instance;
|
|
public static GlobalOrbitalPositionManager Instance => s_Instance;
|
|
|
|
private readonly List<OrbitalPosition> m_ObjectInstances = new();
|
|
private readonly List<Ring> m_Rings = new();
|
|
private readonly Dictionary<int, float> m_Distances = new();
|
|
|
|
public static bool s_IsSimulationRunning = true;
|
|
|
|
private OrbitalPosition m_PlayerOrbitalPosition;
|
|
public static void SetPlayer(OrbitalPosition player) => s_Instance.m_PlayerOrbitalPosition = player;
|
|
|
|
public static bool AllowPlayerInput { get; private set; } = true;
|
|
|
|
private float m_TimeOfLastRingSpawn = float.NegativeInfinity;
|
|
|
|
private int m_LastGeneratedRing;
|
|
public static int LastRingID => s_Instance.m_LastGeneratedRing;
|
|
|
|
private const int CirclePoints = 100;
|
|
|
|
private float m_LocalDeltaTimeScale = 1f;
|
|
private float LocalDeltaTime => Time.deltaTime * m_LocalDeltaTimeScale;
|
|
|
|
private bool m_CurrentRingAllowsSpawning;
|
|
|
|
private Vector3[] m_PrecalculatedPositions;
|
|
|
|
public IEnumerator StartPlayerSpeedupModifier()
|
|
{
|
|
m_LocalDeltaTimeScale *= 2f;
|
|
|
|
yield return new WaitForSeconds(10f);
|
|
|
|
m_LocalDeltaTimeScale /= 2f;
|
|
}
|
|
|
|
[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];
|
|
|
|
for (int i = 0; i < s_Instance.m_PrecalculatedPositions.Length; i++)
|
|
{
|
|
s_Instance.m_PrecalculatedPositions[i] = new Vector3
|
|
(
|
|
x: Mathf.Cos(Mathf.Deg2Rad * (359f / CirclePoints * i)),
|
|
y: Mathf.Sin(Mathf.Deg2Rad * (359f / CirclePoints * i)),
|
|
z: 0
|
|
);
|
|
}
|
|
|
|
RestartSimulation();
|
|
}
|
|
|
|
private static IEnumerator RestartSimulationInternal()
|
|
{
|
|
s_IsSimulationRunning = false;
|
|
|
|
s_Instance.m_LocalDeltaTimeScale = 7f;
|
|
AllowPlayerInput = false;
|
|
for (int i = 0; i < 100; i++)
|
|
{
|
|
yield return new WaitForFixedUpdate();
|
|
|
|
if (PlayerController.IsPlayerAttached)
|
|
s_Instance.m_PlayerOrbitalPosition.m_AttachedRing = s_Instance.m_LastGeneratedRing;
|
|
}
|
|
|
|
PlayerController.AttachPlayer();
|
|
foreach (OrbitalPosition behaviour in s_Instance.m_ObjectInstances)
|
|
{
|
|
behaviour.m_Behaviour.OnSimulationRestart();
|
|
}
|
|
|
|
yield return new WaitForSeconds(1.3f);
|
|
AllowPlayerInput = true;
|
|
s_Instance.m_LocalDeltaTimeScale = 1f;
|
|
|
|
s_IsSimulationRunning = true;
|
|
}
|
|
|
|
public static void RestartSimulation() => s_Instance.StartCoroutine(RestartSimulationInternal());
|
|
|
|
private void Update()
|
|
{
|
|
if (Time.time - m_TimeOfLastRingSpawn > (GlobalOrbitalSettings.GapDistance / m_LocalDeltaTimeScale))
|
|
{
|
|
GameObject newRing = Instantiate(GlobalOrbitalSettings.RingPrefab);
|
|
newRing.transform.localScale = new Vector3(12f, 12f, 1);
|
|
|
|
Ring ring = newRing.AddComponent<Ring>();
|
|
ring.m_ID = m_LastGeneratedRing + 1;
|
|
m_Rings.Add(ring);
|
|
|
|
LineRenderer lineRenderer = newRing.GetComponentInChildren<LineRenderer>();
|
|
lineRenderer.loop = true;
|
|
lineRenderer.positionCount = CirclePoints;
|
|
lineRenderer.startWidth = 0.1f;
|
|
lineRenderer.endWidth = 0.1f;
|
|
lineRenderer.material = new Material(Shader.Find("Sprites/Default"));
|
|
|
|
m_LastGeneratedRing = ring.m_ID;
|
|
m_TimeOfLastRingSpawn = Time.time;
|
|
|
|
m_CurrentRingAllowsSpawning = Random.Range(0, 25) != 0;
|
|
if (!m_CurrentRingAllowsSpawning && AllowPlayerInput)
|
|
Instantiate(GlobalOrbitalSettings.ModifierPrefab);
|
|
}
|
|
|
|
List<Ring> toRemove = new();
|
|
m_Distances.Clear();
|
|
|
|
foreach (Ring ring in m_Rings)
|
|
{
|
|
float diff = LocalDeltaTime * GlobalOrbitalSettings.DistanceSpeed;
|
|
ring.transform.localScale -= new Vector3(diff, diff, 0f);
|
|
|
|
LineRenderer lineRenderer = ring.GetComponentInChildren<LineRenderer>();
|
|
for (int vert = 0; vert < CirclePoints; vert++)
|
|
{
|
|
lineRenderer.SetPosition(vert, new Vector3
|
|
(
|
|
x: m_PrecalculatedPositions[vert].x * ring.transform.localScale.x,
|
|
y: m_PrecalculatedPositions[vert].y * ring.transform.localScale.y,
|
|
z: 10
|
|
));
|
|
}
|
|
|
|
float lerp = (ring.transform.localScale.x - 0.5f) / 4f;
|
|
Color c = Color.Lerp(Color.black, Color.white, Mathf.Clamp01(lerp));
|
|
if (ring.transform.localScale.x < 0.5f)
|
|
{
|
|
if (s_IsSimulationRunning)
|
|
PlayerController.s_PlayerScore++;
|
|
|
|
toRemove.Add(ring);
|
|
}
|
|
|
|
lineRenderer.startColor = c;
|
|
lineRenderer.endColor = c;
|
|
|
|
m_Distances[ring.m_ID] = ring.transform.localScale.x;
|
|
}
|
|
|
|
foreach (Ring ring in toRemove)
|
|
{
|
|
m_Rings.Remove(ring);
|
|
Destroy(ring.gameObject);
|
|
}
|
|
|
|
foreach (OrbitalPosition orbitalPosition in m_ObjectInstances)
|
|
{
|
|
if (!orbitalPosition.m_IsAttachedToRings)
|
|
continue;
|
|
|
|
if (!m_Distances.ContainsKey(orbitalPosition.m_AttachedRing))
|
|
{
|
|
orbitalPosition.m_AttachedRing = m_LastGeneratedRing;
|
|
orbitalPosition.m_Behaviour.OnReachCentre();
|
|
}
|
|
|
|
float distance = m_Distances[orbitalPosition.m_AttachedRing];
|
|
orbitalPosition.m_DistanceFromCentre = distance;
|
|
orbitalPosition.m_DistanceAlongRadius = (orbitalPosition.m_DistanceAlongRadius + LocalDeltaTime * GlobalOrbitalSettings.RadiusSpeed * orbitalPosition.m_SpinSpeed) % (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);
|
|
}
|
|
}
|
|
|
|
if (Random.Range(0, 20) == 0 && AllowPlayerInput && m_CurrentRingAllowsSpawning)
|
|
Instantiate(GlobalOrbitalSettings.EnemyPrefab);
|
|
}
|
|
|
|
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
|
|
{
|
|
[SerializeField] protected OrbitalPosition m_OrbitalPosition;
|
|
|
|
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) { }
|
|
|
|
public virtual void OnSimulationRestart() { }
|
|
}
|