using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; public class TeleportManager : MonoBehaviour { public static TeleportManager Instance { get; private set; } [Header("Optional fade (CanvasGroup with RaycastBlock)")] public TeleportScreenFader screenFader; // drag a CanvasGroup-based fader (below) [Range(0f, 2f)] public float fadeDuration = 0.25f; // Prevent immediate re-triggering after arrival private readonly Dictionary _entityCooldownUntil = new(); private readonly Dictionary _entityLastPortalId = new(); private void Awake() { if (Instance != null && Instance != this) { Destroy(gameObject); return; } Instance = this; DontDestroyOnLoad(gameObject); } public bool CanUsePortal(GameObject entity, string portalId, float cooldownSeconds) { if (cooldownSeconds <= 0f) return true; var now = Time.time; if (_entityCooldownUntil.TryGetValue(entity, out float until) && now < until) return false; // If just came out of this portal pair, block one frame of re-trigger if (_entityLastPortalId.TryGetValue(entity, out string lastId) && lastId == portalId) return false; return true; } public void MarkUsed(GameObject entity, string portalId, float cooldownSeconds) { if (cooldownSeconds > 0f) _entityCooldownUntil[entity] = Time.time + cooldownSeconds; _entityLastPortalId[entity] = portalId; } /// /// Teleport entity to destination. Handles CharacterController, Rigidbody, and NavMeshAgent safely. /// public void Teleport(GameObject entity, Transform destination, bool matchRotation = true) { if (entity == null || destination == null) return; StartCoroutine(TeleportRoutine(entity, destination, matchRotation)); } private IEnumerator TeleportRoutine(GameObject entity, Transform destination, bool matchRotation) { // Fade out (optional) if (screenFader != null && fadeDuration > 0f) yield return screenFader.FadeTo(1f, fadeDuration); // Disable common movers safely var cc = entity.GetComponent(); var rb = entity.GetComponent(); var agent = entity.GetComponent(); bool ccWasEnabled = false; bool agentWasEnabled = false; if (cc != null) { ccWasEnabled = cc.enabled; cc.enabled = false; } if (agent != null) { agentWasEnabled = agent.enabled; agent.enabled = false; } if (rb != null) { rb.isKinematic = true; // pause physics for an instant rb.velocity = Vector3.zero; rb.angularVelocity = Vector3.zero; } // Move + rotate if (agent != null) { agent.Warp(destination.position); if (matchRotation) entity.transform.rotation = destination.rotation; } else { entity.transform.position = destination.position; if (matchRotation) entity.transform.rotation = destination.rotation; } // Small frame delay to settle yield return null; // Re-enable components if (rb != null) rb.isKinematic = false; if (cc != null) cc.enabled = ccWasEnabled; if (agent != null) agent.enabled = agentWasEnabled; // Fade in (optional) if (screenFader != null && fadeDuration > 0f) yield return screenFader.FadeTo(0f, fadeDuration); } }