/// <summary> /// Teleports the given teleportable, making passthrough and image effects seamless. /// </summary> /// <param name="teleportable">Teleportable to teleport</param> /// <param name="col">Associated Collider</param> private void TryTeleportTeleporable(Teleportable teleportable, Collider col) { if (!PortalUtils.IsBehind(teleportable.TeleportableBounds.center, Origin.position, Origin.forward) || teleportable.VisOnly) { return; } //if (!PortalUtils.IsBehind(col.transform.position, Origin.position, Origin.forward) || teleportable.VisOnly) return; if (teleportable.TeleportedLastFrame) { return; } teleportable.TeleportedLastFrame = true; RemoveTeleportable(teleportable); //Makes objects not with invisible buffer bounds in the case of portals being too close foreach (Collider c in BufferWall) { teleportable.IgnoreCollision(this, c, true); } PortalUtils.TeleportObject(teleportable.root.gameObject, Origin, ArrivalTarget, teleportable.root, null, true, !SKSGlobalRenderSettings.NonScaledRenderers); TargetPortal.FixedUpdate(); teleportable.Teleport(); //TargetPortal.UpdateDopplegangers(); TargetPortal.PhysicsPassthrough.UpdatePhysics(); //teleportable.SetClipPlane(Vector3.zero, Vector3.zero, teleportable.Renderers.Keys); TargetPortal.PhysicsPassthrough.ForceRescanOnColliders(teleportable.Colliders.Values); PhysicsPassthrough.ForceRescanOnColliders(teleportable.Colliders.Values); TargetPortal.E_OnTriggerStay(col); //TargetPortal.UpdateDopplegangers(true); if (teleportable == GlobalPortalSettings.PlayerTeleportable) { TargetPortal.UpdateDopplegangers(true); TargetPortal.IncomingCamera(); _cheeseActivated = -1; _headInPortalTrigger = false; //Resets the vis depth of the Portal volume if (!Is3D) { transform.localScale = new Vector3(1f, 1f, FudgeFactor); } } //teleportable.EnableDoppleganger(); //teleportable.SetClipPlane(); //Applies relative velocity if (!SKSGlobalRenderSettings.PhysStyleB) { return; } Rigidbody body; if (body = col.attachedRigidbody) { bool colliderEnabled = PortalCollider.enabled; bool otherColliderEnabled = TargetPortal.PortalCollider.enabled; PortalCollider.enabled = true; TargetPortal.PortalCollider.enabled = true; Rigidbody portalBody = PortalCollider.attachedRigidbody; Rigidbody targetBody = TargetPortal.PortalCollider.attachedRigidbody; PortalCollider.enabled = colliderEnabled; TargetPortal.PortalCollider.enabled = otherColliderEnabled; if ((portalBody) != null && (targetBody) != null) { Vector3 relativeVelocity = Quaternion.Inverse(portalBody.rotation) * portalBody.velocity; relativeVelocity += Quaternion.Inverse(targetBody.rotation) * targetBody.velocity; relativeVelocity = targetBody.rotation * relativeVelocity; body.AddForce(relativeVelocity, ForceMode.Impulse); } } TargetPortal.UpdateDopplegangers(true); UpdateDopplegangers(true); }
/// <summary> /// Attempt to add a teleportableScript to the nearteleportables group /// </summary> /// <param name="teleportScript">the script to add</param> private void AddTeleportable(Teleportable teleportScript) { if (!TargetPortal) { return; } if (!teleportScript || NearTeleportables.Contains(teleportScript)) { return; } if (teleportScript.AddedLastFrame) { return; } SetBufferWallActive(true); teleportScript.AddedLastFrame = true; teleportScript.EnableDoppleganger(); NearTeleportables.Add(teleportScript); //Ignores collision with rear objects Vector3[] checkedVerts = PortalUtils.ReferenceVerts(MeshFilter.mesh); //Ignore collision with the Portal itself teleportScript.IgnoreCollision(this, PortalCollider); teleportScript.IgnoreCollision(this, TargetPortal.PortalCollider); //Ignores rear-facing colliders Ray ray = new Ray(); RaycastHit[] hit; //Enables the buffer wall if it is disabled foreach (Transform tran in BufferWallObj.transform) { Collider c = tran.GetComponent <Collider>(); c.enabled = true; } foreach (Vector3 v in checkedVerts) { ray.origin = transform.TransformPoint(v) + transform.forward * 0.01f; ray.direction = -transform.forward; hit = Physics.RaycastAll(ray, 1 * transform.parent.localScale.z, ~0, QueryTriggerInteraction.Collide); Debug.DrawRay(ray.origin, -transform.forward * transform.parent.localScale.z, Color.cyan, 10); if (hit.Length <= 0) { continue; } foreach (RaycastHit h in hit) { //Never ignore collisions with teleportables //Never ignore collisions with teleportables if (h.collider.gameObject.tag.Equals("PhysicsPassthroughDuplicate") || h.collider.gameObject.GetComponent <Teleportable>() != null) { continue; } if (h.collider.transform.parent && transform.parent && h.collider.transform.parent.parent && transform.parent.parent) { if (h.collider.transform.parent.parent != transform.parent.parent) { teleportScript.IgnoreCollision(this, h.collider); } } else { teleportScript.IgnoreCollision(this, h.collider); } } } //todo: Remove this when multiple simultaneous portal intersection gets added //TargetPortal.RemoveTeleportable(teleportScript); UpdateDopplegangers(); }
/// <summary> /// Checks if objects are in Portal, and teleports them if they are. Also handles player entry. /// </summary> /// <param name="col"></param> public void E_OnTriggerStay(Collider col) { if (!TargetPortal) { return; } Rigidbody teleportableBody = col.attachedRigidbody; if (!teleportableBody) { return; } //todo: cache these Teleportable teleportScript = teleportableBody.GetComponent <Teleportable>(); AddTeleportable(teleportScript); if (!Enterable || !teleportScript || !teleportScript.initialized) { return; } if (teleportScript == GlobalPortalSettings.PlayerTeleportable) { _headInPortalTrigger = true; //teleportScript = PlayerTeleportable; } //Updates clip planes for disappearing effect if (!NonObliqueOverride) { teleportScript.SetClipPlane(Origin.position, Origin.forward /* (1 + transform.localScale.z)*/ + (Origin.forward * 0.01f), teleportScript.Renderers.Keys); teleportScript.SetClipPlane(ArrivalTarget.position, -ArrivalTarget.forward, teleportScript.Renderers.Values); } WakeBufferWall(); //Makes objects collide with invisible buffer bounds foreach (Collider c in BufferWall) { teleportScript.AddCollision(this, c); } //Makes objects collide with invisible buffer bounds foreach (Collider c in TargetPortal.BufferWall) { teleportScript.IgnoreCollision(this, c, true); } if (SKSGlobalRenderSettings.PhysicsPassthrough) { //Makes objects collide with objects on the other side of the Portal foreach (Collider c in PassthroughColliders.Values) { teleportScript.AddCollision(this, c); } } //Passes Portal info to teleport script teleportScript.SetPortalInfo(this); //Enables Doppleganger teleportScript.EnableDoppleganger(); //Checks if object should be teleported TryTeleportTeleporable(teleportScript, col); }