Files
Carrasco/Assets/PauseForMenuesChotos.cs
2025-10-20 22:47:12 -03:00

246 lines
7.9 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Pausa robusta para overlays/menús (tutorial, modales, etc).
/// - timeScale = 0 mientras haya overlays activos (ref-count).
/// - Desactiva todos los spawners (DynamicSpawnerSystem, *Spawner*, etc) y luego los restaura.
/// - Anti-backlog + anti-parpadeo: cualquier avión instanciado durante la pausa se
/// deshabilita visualmente en el mismo frame y luego se destruye.
/// </summary>
[DisallowMultipleComponent]
[DefaultExecutionOrder(10000)]
public class PauseForMenuesChotos : MonoBehaviour
{
// -------- estado global (entre múltiples overlays) --------
private static int s_activeTokens = 0;
private struct SpawnerSnapshot
{
public Behaviour behaviour;
public bool wasEnabled;
public GameObject go;
public bool goWasActive;
}
private static readonly List<SpawnerSnapshot> s_spawnerSnapshots = new List<SpawnerSnapshot>();
private static bool s_spawnersDisabled = false;
// Conjunto de aviones que ya existían al entrar en pausa (no se tocan)
private static readonly HashSet<int> s_knownPlaneIds = new HashSet<int>();
// Único dueño de la patrulla anti-parpadeo
private static PauseForMenuesChotos s_cullOwner = null;
private Coroutine _cullCo;
// -------- por-instancia --------
private bool _weHoldToken = false;
private bool _prevAudioPause = false;
private void OnEnable()
{
s_activeTokens++;
_weHoldToken = true;
_prevAudioPause = AudioListener.pause;
AudioListener.pause = true;
ForceTimeScaleZero();
var gm = GameManager.Instance;
if (gm != null && !gm.isPausedByGameOver && !gm.IsWin())
gm.isPaused = true;
// Primer overlay que entra → apagar spawners y capturar baseline de aviones
if (!s_spawnersDisabled)
{
DisableAllSpawners();
s_spawnersDisabled = true;
// Baseline: registrar aviones existentes
s_knownPlaneIds.Clear();
var planesNow = FindObjectsOfType<PlaneController>(true);
for (int i = 0; i < planesNow.Length; i++)
if (planesNow[i]) s_knownPlaneIds.Add(planesNow[i].GetInstanceID());
}
// Arrancar patrulla por frame sólo si no hay otra en curso
if (s_cullOwner == null)
{
s_cullOwner = this;
_cullCo = StartCoroutine(CoCullNewSpawnsEveryFrame());
}
}
private void LateUpdate()
{
if (s_activeTokens > 0)
ForceTimeScaleZero(); // por si alguien tocó el timeScale
}
private void OnDisable()
{
if (_weHoldToken)
{
s_activeTokens = Mathf.Max(0, s_activeTokens - 1);
_weHoldToken = false;
}
AudioListener.pause = _prevAudioPause;
// Si aún quedan overlays activos, no restauramos
if (s_activeTokens > 0) return;
// Detener patrulla si éramos dueños
if (s_cullOwner == this)
{
if (_cullCo != null) StopCoroutine(_cullCo);
_cullCo = null;
s_cullOwner = null;
}
// Restaurar spawners
if (s_spawnersDisabled)
{
RestoreAllSpawners();
s_spawnersDisabled = false;
}
s_knownPlaneIds.Clear();
var gm = GameManager.Instance;
if (gm != null)
{
if (gm.isPausedByGameOver || gm.IsWin() || gm.isPaused)
return;
}
Time.timeScale = 1f;
}
// =========================================================
// Spawners: snapshot + disable + restore
// =========================================================
private void DisableAllSpawners()
{
s_spawnerSnapshots.Clear();
var allBehaviours = FindObjectsOfType<MonoBehaviour>(true);
foreach (var mb in allBehaviours)
{
if (!mb) continue;
var tn = mb.GetType().Name;
// Todo lo que suene a "Spawner" o el sistema dinámico explícito
if (tn == "DynamicSpawnerSystem" || tn.Contains("Spawner") || tn.Contains("Spawn"))
{
SnapshotAndDisable(mb);
}
}
#if UNITY_EDITOR
Debug.Log($"[PauseForMenuesChotos] Spawners desactivados: {s_spawnerSnapshots.Count} componentes.");
#endif
}
private void SnapshotAndDisable(MonoBehaviour mb)
{
var go = mb.gameObject;
s_spawnerSnapshots.Add(new SpawnerSnapshot
{
behaviour = mb,
wasEnabled = mb.enabled,
go = go,
goWasActive = go.activeSelf
});
// Desactivar GO (corta Updates/Coroutines/Invoke) y además el enabled
if (go.activeSelf) go.SetActive(false);
if (mb.enabled) mb.enabled = false;
}
private void RestoreAllSpawners()
{
for (int i = 0; i < s_spawnerSnapshots.Count; i++)
{
var s = s_spawnerSnapshots[i];
if (!s.behaviour) continue;
if (s.go) s.go.SetActive(s.goWasActive);
s.behaviour.enabled = s.wasEnabled;
}
s_spawnerSnapshots.Clear();
#if UNITY_EDITOR
Debug.Log("[PauseForMenuesChotos] Spawners restaurados.");
#endif
}
// =========================================================
// Anti-parpadeo: patrulla *cada frame* y apaga renderers antes de destruir
// =========================================================
private IEnumerator CoCullNewSpawnsEveryFrame()
{
// Primera pasada inmediata (mismo frame) sin esperar
while (s_activeTokens > 0)
{
ForceTimeScaleZero();
var planes = FindObjectsOfType<PlaneController>(true);
for (int i = 0; i < planes.Length; i++)
{
var p = planes[i];
if (!p) continue;
int id = p.GetInstanceID();
if (s_knownPlaneIds.Contains(id)) continue; // ya existía antes de pausar
// ---- NUEVO DURANTE PAUSA → ocultar y destruir ----
// Apagar renderers/colliders YA (evita que se dibuje ni 1 frame)
try
{
var rends = p.GetComponentsInChildren<Renderer>(true);
for (int r = 0; r < rends.Length; r++) if (rends[r]) rends[r].enabled = false;
var cols = p.GetComponentsInChildren<Collider2D>(true);
for (int c = 0; c < cols.Length; c++) if (cols[c]) cols[c].enabled = false;
var rb = p.GetComponent<Rigidbody2D>();
if (rb) { rb.simulated = false; rb.linearVelocity = Vector2.zero; rb.angularVelocity = 0f; }
// Opcional: ocultar también cualquier LineRenderer/Trail
var lrs = p.GetComponentsInChildren<LineRenderer>(true);
for (int l = 0; l < lrs.Length; l++) if (lrs[l]) lrs[l].enabled = false;
var trs = p.GetComponentsInChildren<TrailRenderer>(true);
for (int t = 0; t < trs.Length; t++) if (trs[t]) trs[t].emitting = false;
}
catch { /* seguro */ }
#if UNITY_EDITOR
Debug.Log($"[PauseForMenuesChotos] Cull avión nuevo durante pausa: {p.name}");
#endif
#if UNITY_EDITOR
if (!Application.isPlaying) DestroyImmediate(p.gameObject);
else
#endif
Destroy(p.gameObject);
// No lo agregamos al baseline (ya está marcado para destruir)
}
// Esperamos al siguiente frame (realtime) para seguir patrullando
yield return null; // cada frame
}
}
// =========================================================
// Utilidades
// =========================================================
private static void ForceTimeScaleZero()
{
if (Time.timeScale != 0f) Time.timeScale = 0f;
}
}