using System; using System.Collections.Generic; using EscapeRoomEngine.Engine.Runtime.Modules; using EscapeRoomEngine.Engine.Runtime.Utilities; using NaughtyAttributes; using UnityEngine; namespace EscapeRoomEngine.Portal.Runtime { public class Portal : DoorState { 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. /// [BoxGroup("Internal")] public PortalCamera portalCamera; /// /// The transform marking the edge of the portal plane. /// [BoxGroup("Internal")] public Transform portalTransform; private bool Connected => linkedPortal != null; private readonly List _closePortalDrivers = new(); private void Awake() { DoorEvent += (_, type) => { if (type == DoorEventType.Connected) { linkedPortal = FromDoorState(Module.ConnectedDoorState); portalCamera.screen.gameObject.SetActive(true); portalCamera.enabled = true; } }; } private void FixedUpdate() { if (Connected) { for (var i = 0; i < _closePortalDrivers.Count; i++) { var portalDriver = _closePortalDrivers[i]; if (portalDriver.entrySide < 0 && CalculateSide(portalDriver.transform) >= 0) // must have entered from the front and exited the back { StopTrackingDriver(portalDriver); linkedPortal.StartTrackingDriver(portalDriver, -1); portalDriver.Teleport(this, linkedPortal); i--; // decrease the loop counter because the list is one element smaller now } } } } private void StartTrackingDriver(PortalDriver portalDriver, int entrySide) { _closePortalDrivers.Add(portalDriver); portalDriver.EnableClone(linkedPortal); portalDriver.entrySide = entrySide; } private void StopTrackingDriver(PortalDriver portalDriver) { _closePortalDrivers.Remove(portalDriver); portalDriver.DisableClone(linkedPortal); } private void OnTriggerEnter(Collider other) { if (Connected) { var portalDriver = other.GetComponent(); if (portalDriver && !_closePortalDrivers.Contains(portalDriver)) { StartTrackingDriver(portalDriver, CalculateSide(portalDriver.transform)); } } } private void OnTriggerExit(Collider other) { if (Connected) { var portalDriver = other.GetComponent(); if (portalDriver) { StopTrackingDriver(portalDriver); } } } private int CalculateSide(Transform portalDriverTransform) { return Math.Sign(Vector3.Dot(portalTransform.forward, portalDriverTransform.position - portalTransform.position)); } private static Portal FromDoorState(DoorState state) { if (state is Portal portal) { return portal; } throw new WrongTypeException(typeof(Portal), state.GetType(), typeof(DoorState)); } } }