105 lines
3.6 KiB
C#

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<GameObject, float> _entityCooldownUntil = new();
private readonly Dictionary<GameObject, string> _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;
}
/// <summary>
/// Teleport entity to destination. Handles CharacterController, Rigidbody, and NavMeshAgent safely.
/// </summary>
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<CharacterController>();
var rb = entity.GetComponent<Rigidbody>();
var agent = entity.GetComponent<NavMeshAgent>();
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);
}
}