using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; namespace Fragilem17.MirrorsAndPortals { /** * Used to transport PortalableObjects to the linked portal defined in the portalSurface */ public class PortalTransporter : MonoBehaviour { private Portal _portal; public List portalableObjects = new List(); //private List cloneObjects = new List(); public HashSet cloneObjects = new HashSet(); public HashSet cloneObjectsActuallyTouching = new HashSet(); public HashSet cloneObjectsToRemove = new HashSet(); private List portalAffectorSpheres = new List(); private Vector3 _originalScale; [Space(10)] [Header("Events")] public UnityEvent OnObjectEnteredPortal; public UnityEvent OnObjectTransportedAwayFromHere; public UnityEvent OnObjectTransportedToHere; public UnityEvent OnObjectExitedPortal; [HideInInspector] public Collider MyCollider; public enum PortalReason { Undefined, ExitedCurrentPortalCollider, EnteredOtherPortalCollider } public Portal Portal { get => _portal; } public void Initialise() { MyCollider = GetComponent(); if (!MyCollider) { Debug.LogWarning(PortalUtils.Colorize("[PORTALS] ", PortalUtils.DebugColors.Warn, true) + name + " has a PortalTransporter Component but no trigger Collider, add a big enough Collider for things to hit it before reaching the actual portal."); } else { MyCollider.isTrigger = true; } Rigidbody rb = GetComponent(); if (!rb) { Debug.LogWarning(PortalUtils.Colorize("[PORTALS] ", PortalUtils.DebugColors.Warn, true) + name + " has a PortalTransporter Component but no RigidBody Component. Add a (Kinematic) Rigidbody Component to this GameObject."); } _portal = GetComponentInParent(); if (!_portal) { Debug.LogWarning(PortalUtils.Colorize("[PORTALS] ", PortalUtils.DebugColors.Warn, true) + name + " has a PortalTransporter Component but no Portal Component, add a Portal Component to this or a parent GameObject."); } } protected void OnEnable() { Initialise(); } private void FixedUpdate() { //CheckNeedPortal(); } private void LateUpdate() { //CheckNeedPortal(); } protected void Update() { CheckNeedPortal(); } protected void CheckNeedPortal() { PortalableObject p = null; for (int i = 0; i < portalableObjects.Count; ++i) { p = portalableObjects[i]; if (p) { Vector3 objPos = _portal.PortalSurface.transform.InverseTransformPoint(p.transform.position); if (objPos.z > 0) { PortalableObject po = portalableObjects[i]; if (po.CanPortal()) { //Debug.Log("PortalTransporter " + Portal.name + " : fixedUpdate z > 0 - doing portal on " + po.name + " : " + objPos.z); if (_portal.OtherPortal && _portal.OtherPortal.PortalTransporter) { // only trigger the ExternalTriggerEnter if we're actually telepoting inside our collider! _portal.OtherPortal.PortalTransporter.ExternalTriggerEnter(po.gameObject, false); _portal.OtherPortal.PortalTransporter.OnObjectTransportedToHere.Invoke(po); } po.PortalFrom(_portal); OnObjectTransportedAwayFromHere.Invoke(po); } } } } } public void ExternalTriggerEnter(GameObject other, bool fromPhysics = false) { // first trigger the exit in the other portal if (!fromPhysics && _portal.OtherPortal && _portal.OtherPortal.PortalTransporter) { _portal.OtherPortal.PortalTransporter.ExternalTriggerExit(other, fromPhysics, PortalReason.EnteredOtherPortalCollider); } Vector3 objPos = _portal.PortalSurface.transform.InverseTransformPoint(other.transform.position); // did we enter in front of the portal? //Debug.Log("ExternalTriggerEnter objPos: " + other.name + " " + objPos.z + " " + fromPhysics + " :" + Portal.name); if (!fromPhysics || (fromPhysics && objPos.z < 0)) { PortalableObject obj = other.GetComponent(); if (obj && obj.isActiveAndEnabled && !portalableObjects.Contains(obj)) { //Debug.Log("Adding to portal list of " + _portal.name + " object:" + other.name); portalableObjects.Add(obj); //obj.OnExitPortalCollider.AddListener(onPortalableObjectExitPortalCollider); obj.SetIsInPortal(_portal); OnObjectEnteredPortal.Invoke(obj); } else { PortalableObjectCollider helper = other.GetComponent(); if (helper && helper.isActiveAndEnabled && !portalableObjects.Contains(helper.PortalableObject)) { //Debug.Log("Adding to portal list of " + _portal.name + " object:" + other.name); portalableObjects.Add(helper.PortalableObject); //obj.OnExitPortalCollider.AddListener(onPortalableObjectExitPortalCollider); helper.PortalableObject.SetIsInPortal(_portal); OnObjectEnteredPortal.Invoke(helper.PortalableObject); } } CloneRenderer cloneObject = other.GetComponent(); if (cloneObject && cloneObject.isActiveAndEnabled && !cloneObjects.Contains(cloneObject)) { cloneObjects.Add(cloneObject); cloneObject.SetIsInPortal(_portal, true); } PortalAffectorSphere affectorSphere = other.GetComponent(); if (affectorSphere && affectorSphere.isActiveAndEnabled && !portalAffectorSpheres.Contains(affectorSphere)) { //if (fromPhysics) //{ portalAffectorSpheres.Add(affectorSphere); //} affectorSphere.SetIsInPortal(_portal); } } } /*private void onPortalableObjectExitPortalCollider(PortalableObject obj, Portal p) { if (p == Portal) { ExternalTriggerExit(obj.gameObject, false); } }*/ public void ExternalTriggerExit(GameObject other, bool fromPhysics = false, PortalReason reason = PortalReason.Undefined) { PortalableObject portalableObj = other.GetComponent(); /* bool isPortallingAlongWithMasterPortalable = false; if (portalableObj) { //portalableObj.OnExitPortalCollider.RemoveListener(onPortalableObjectExitPortalCollider); isPortallingAlongWithMasterPortalable = portalableObj.EnablePortalAlongWithMasterPortalable; } // todo: as long as we're grabbing something, and it's gonna portal along with the player, then don't exit the portal when it's collider exits this transporter. // but, what to do when the player does not portal? if (reason == PortalReason.ExitedCurrentPortalCollider && isPortallingAlongWithMasterPortalable) { // are we on the other side of the surface when exiting the collider? then keep it inside the portal Vector3 objPos = _portal.PortalSurface.transform.InverseTransformPoint(other.transform.position); Debug.Log("objPos: " + objPos.z); if (objPos.z > 0) { return; } }*/ CloneRenderer cloneObject = other.GetComponent(); /*if (cloneObject) { Debug.Log(cloneObject.name + " exits portal " + Portal.name + " IF " + cloneObjects.Contains(cloneObject) + " AND NOT isPortallingAlongWithMasterPortalable: " + isPortallingAlongWithMasterPortalable); }*/ if (cloneObject && cloneObjects.Contains(cloneObject)) { cloneObjects.Remove(cloneObject); cloneObject.ExitPortal(_portal, fromPhysics); } if (portalableObj && portalableObjects.Contains(portalableObj)) { //Debug.Log("Exit Portal " + gameObject.name); //Debug.Log("Removing from portal list of " + _portal.name + " object:" + other.name); //Debug.Log("PortalableObject " + portalableObj.name + " ExitsPortal: " + _portal.name + " fromPhysics: " + fromPhysics); portalableObjects.Remove(portalableObj); portalableObj.ExitPortal(_portal); OnObjectExitedPortal.Invoke(portalableObj); } PortalAffectorSphere affectorSphere = other.GetComponent(); if (affectorSphere && portalAffectorSpheres.Contains(affectorSphere)) { portalAffectorSpheres.Remove(affectorSphere); affectorSphere.ExitPortal(_portal); } } protected void OnTriggerEnter(Collider other) { //Debug.Log("OnTriggerEnter: " + other.name); ExternalTriggerEnter(other.gameObject, true); } protected void OnTriggerExit(Collider other) { ExternalTriggerExit(other.gameObject, true, PortalReason.ExitedCurrentPortalCollider); } } }