using System; using System.Collections.Generic; using UnityEngine; namespace Escape_Room_Engine.Portal { [RequireComponent(typeof(Collider))] public class Portal : MonoBehaviour { public static readonly Matrix4x4 HalfRotation = Matrix4x4.Rotate(Quaternion.Euler(0, 180, 0)); /// /// The portal that is connected with this one. /// public Portal linkedPortal; /// /// The camera that will draw the view for this portal. /// public PortalCamera portalCamera; private readonly List _closePortalDrivers = new(); private void Awake() { // check whether the other portal is set up if (!linkedPortal || linkedPortal.linkedPortal != this) throw new Exception("Other portal not set up correctly."); // check whether the collider is set up correctly if (!GetComponent().isTrigger) throw new Exception("Collider must be a trigger."); } private void FixedUpdate() { for (var i = 0; i < _closePortalDrivers.Count; i++) { var portalDriver = _closePortalDrivers[i]; var side = CalculateSide(portalDriver.transform); if (portalDriver.entrySide < 0 && side >= 0) // must have entered from the front and exited the back { _closePortalDrivers.Remove(portalDriver); linkedPortal._closePortalDrivers.Add(portalDriver); portalDriver.entrySide = -1; portalDriver.Teleport(this, linkedPortal); i--; // decrease the loop counter because the list is one element smaller now } } } private void OnTriggerEnter(Collider other) { var portalDriver = other.GetComponent(); if (portalDriver && !_closePortalDrivers.Contains(portalDriver)) { _closePortalDrivers.Add(portalDriver); portalDriver.entrySide = CalculateSide(portalDriver.transform); } } private void OnTriggerExit(Collider other) { var portalDriver = other.GetComponent(); if (portalDriver) { _closePortalDrivers.Remove(portalDriver); } } private int CalculateSide(Transform portalDriverTransform) { var t = transform; return Math.Sign(Vector3.Dot(t.forward, portalDriverTransform.position - t.position)); } } }