menues fix

This commit is contained in:
2025-10-20 22:47:12 -03:00
parent b4f085a313
commit 6cbd4aaab9
2 changed files with 224 additions and 51 deletions
+220 -44
View File
@@ -1,70 +1,246 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Pausa segura para overlays/menús (tutorial incluido).
/// - Si existe GameManager, marca isPaused = true y deja que él ponga timeScale=0.
/// - Si no existe GameManager, hace fallback a pausar con Time.timeScale = 0.
/// - Al desactivar el GO, restaura el estado.
/// Recomendado: que el Canvas tenga un Graphic (Image) con raycastTarget=true para bloquear clicks a la escena.
/// 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
{
private bool _weChangedPause = false;
private float _prevTimeScale = 1f;
private bool _prevAudioPause = false;
// -------- 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()
{
// Si hay GameManager, usamos su flag isPaused (él se encarga del timeScale en Update).
var gm = GameManager.Instance;
if (gm != null)
{
// Evita interferir si el juego está en game over o win.
if (!gm.isPausedByGameOver && !gm.IsWin())
{
gm.isPaused = true; // GameManager.Update pondrá Time.timeScale = 0f
_weChangedPause = true;
}
else
{
// En estados especiales, no tocamos flags del GM. Igual bloqueamos el audio.
_prevAudioPause = AudioListener.pause;
AudioListener.pause = true;
}
}
else
{
// Fallback si no hay GameManager en escena.
_prevTimeScale = Time.timeScale;
_prevAudioPause = AudioListener.pause;
s_activeTokens++;
_weHoldToken = true;
Time.timeScale = 0f;
AudioListener.pause = true;
_weChangedPause = 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 (_weChangedPause && gm.isPaused && !gm.isPausedByGameOver && !gm.IsWin())
gm.isPaused = false; // GameManager.Update restaurará timeScale=1
// Siempre devolvemos el audio a su estado previo si lo tocamos
AudioListener.pause = _prevAudioPause;
if (gm.isPausedByGameOver || gm.IsWin() || gm.isPaused)
return;
}
else
Time.timeScale = 1f;
}
// =========================================================
// Spawners: snapshot + disable + restore
// =========================================================
private void DisableAllSpawners()
{
s_spawnerSnapshots.Clear();
var allBehaviours = FindObjectsOfType<MonoBehaviour>(true);
foreach (var mb in allBehaviours)
{
if (_weChangedPause)
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"))
{
Time.timeScale = (_prevTimeScale <= 0f) ? 1f : _prevTimeScale;
AudioListener.pause = _prevAudioPause;
SnapshotAndDisable(mb);
}
}
_weChangedPause = false;
#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;
}
}
+4 -7
View File
@@ -2439,10 +2439,10 @@ RectTransform:
m_Children: []
m_Father: {fileID: 800283092}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 8.262}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: -211, y: 27}
m_SizeDelta: {x: 628.3042, y: 235.614}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: -211, y: 60.74022}
m_SizeDelta: {x: -651.6958, y: -844.386}
m_Pivot: {x: 0.5, y: 0.46875906}
--- !u!114 &601115176
MonoBehaviour:
@@ -7464,9 +7464,6 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: d4032d7acb4a649fb9806dd8c433325d, type: 3}
m_Name:
m_EditorClassIdentifier:
requestEmail: 0
requestIdToken: 1
requestServerAuthCode: 1
--- !u!4 &1770338342
Transform:
m_ObjectHideFlags: 0