/// <summary> /// Adds a child to the teleportable and updates components /// </summary> /// <param name="gameObject">GameObject to add</param> public void AddChild(GameObject gameObject) { gameObject.SetActive(!gameObject.activeSelf); var newObject = Instantiate(gameObject); gameObject.SetActive(!gameObject.activeSelf); newObject.transform.parent = SKSGeneralUtils.FindAnalogousTransform(gameObject.transform.parent, Root, Doppleganger.transform, true); UpdateBounds(); InstantiateDoppleganger(newObject.transform); }
public virtual void Initialize(Teleportable teleportable) { this.teleportable = teleportable; originalParent = transform.parent; try { otherTransform = SKSGeneralUtils.FindAnalogousTransform(transform, teleportable.Root, teleportable.Doppleganger.transform, true); otherTransformParent = otherTransform.parent; } catch (NullReferenceException e) { Debug.LogError("Teleportablescript on " + name + "had a problem:" + e.Message); } originalPosition = transform.localPosition; originalRotation = transform.localRotation; originalScale = transform.localScale; }
// Update is called once per frame public virtual void CustomUpdate() { if (throughPortal) { Teleport(); } //Check if the gameobject this script is attached to is through a Portal if (!throughPortal && currentPortal && SKSGeneralUtils.IsBehind(transform.position, currentPortal.Origin.position, currentPortal.Origin.forward * 1.01f)) { StartCoroutine(DelayedTeleport()); } else if (throughPortal && currentPortal && SKSGeneralUtils.IsBehind(transform.position, currentPortal.Target.Origin.position, currentPortal.Target.Origin.forward * 1.01f)) { StartCoroutine(DelayedUnTeleport()); } }
/// <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 (!SKSGeneralUtils.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 (var c in BufferWall) { #if !DISABLE_PHYSICS_IGNORE teleportable.CollisionManager.IgnoreCollision(this, c, true); #endif } var targetPortal = (Portal)Target; teleportable.StartTeleport(this); PortalUtils.TeleportObject(teleportable.Root.gameObject, Origin, ArrivalTarget, teleportable.Root, null, true, !SKSGlobalRenderSettings.NonScaledRenderers); targetPortal.FixedUpdate(); teleportable.Teleport(this, targetPortal); targetPortal.PhysicsPassthrough.UpdatePhysics(); var teleportableColliders = teleportable.CollisionManager.Colliders.ToArray(); targetPortal.PhysicsPassthrough.ForceRescanOnColliders(teleportableColliders); PhysicsPassthrough.ForceRescanOnColliders(teleportableColliders); targetPortal.E_OnTriggerStay(col); teleportable.FinishTeleport(this); if (teleportable == GlobalPortalSettings.PlayerTeleportable) { } targetPortal.UpdateDopplegangers(true); UpdateDopplegangers(true); //Un-register head as being in portal trigger to prevent flash if (teleportable == GlobalPortalSettings.PlayerTeleportable) { _headInPortalTrigger = false; targetPortal.UpdateDopplegangers(true); targetPortal.IncomingCamera(); CheeseActivated = -1; //Resets the vis depth of the Portal volume if (!Is3D) { transform.localScale = new Vector3(1f, 1f, FudgeFactor); } } Rigidbody body; if ((body = col.attachedRigidbody) && SKSGlobalRenderSettings.PhysStyleB) { var colliderEnabled = PortalCollider.enabled; var otherColliderEnabled = targetPortal.PortalCollider.enabled; PortalCollider.enabled = true; targetPortal.PortalCollider.enabled = true; var portalBody = PortalCollider.attachedRigidbody; var targetBody = targetPortal.PortalCollider.attachedRigidbody; PortalCollider.enabled = colliderEnabled; targetPortal.PortalCollider.enabled = otherColliderEnabled; if (portalBody != null && targetBody != null) { var relativeVelocity = Quaternion.Inverse(portalBody.rotation) * portalBody.velocity; relativeVelocity += Quaternion.Inverse(targetBody.rotation) * targetBody.velocity; relativeVelocity = targetBody.rotation * relativeVelocity; body.AddForce(relativeVelocity, ForceMode.Impulse); } } if (OnTeleportObject != null) { OnTeleportObject.Invoke(teleportable, (Portal)Target); } if (targetPortal.OnObjectArrived != null) { targetPortal.OnObjectArrived.Invoke(teleportable, this); } }
/// <summary> /// Render a Renderer frame, assuming that the camera is in front of the Renderer and all conditions are met. /// </summary> /// <param name="camera">The camera rendering the Renderer</param> /// <param name="nearClipVerts">The vertices of the camera's near clip plane</param> private void TryRender(Camera camera, Vector3[] nearClipVerts) { if (!Target || !Rendering) { return; } //bool isVisible = false; var isVisible = false; //Check if the camera itself is behind the Renderer, even if the frustum isn't. if (!IsMirror) { if (!SKSGeneralUtils.IsBehind(camera.gameObject.transform.position, Origin.position, Origin.forward)) { isVisible = true; } else { foreach (var v in nearClipVerts) { if (!SKSGeneralUtils.IsBehind(v, Origin.position, Origin.forward)) { isVisible = true; break; } } } } else { if (SKSGeneralUtils.IsBehind(camera.gameObject.transform.position, Origin.position, Origin.forward)) { isVisible = true; } else { foreach (var v in nearClipVerts) { if (SKSGeneralUtils.IsBehind(v, Origin.position, Origin.forward)) { isVisible = true; break; } } } } if (isVisible || CheeseActivated != -1) { EffectCamera.RenderIntoMaterial( camera, RenderMaterial, MeshRenderer, Target.MeshRenderer, MeshFilter.mesh, !NonObliqueOverride ? CheeseActivated == -1 : false, Is3D, IsMirror, IsLowqEffect); } MeshRenderer.GetPropertyBlock(_seamlessRecursionBlock); SeamlessRecursionRenderer.SetPropertyBlock(_seamlessRecursionBlock); }
/// <summary> /// Remove child from teleportable /// </summary> /// <param name="gameObject"></param> public void RemoveChild(GameObject gameObject) { Destroy(SKSGeneralUtils.FindAnalogousTransform(gameObject.transform, Root, Doppleganger.transform) .gameObject); }
private void FixedUpdate() { if (!gameObject.activeInHierarchy) { return; } UpdateBounds(); if (!FastMoving) { return; } if (!AttachedCollider || !AttachedCollider.attachedRigidbody) { return; } RaycastHit[] hits; var velocity = AttachedCollider.attachedRigidbody.velocity.normalized; var magnitude = velocity.magnitude * Time.deltaTime; if (!Bullet) { hits = Physics.BoxCastAll(transform.position - velocity * magnitude, AttachedCollider.bounds.extents, velocity, Quaternion.identity, AttachedCollider.attachedRigidbody.velocity.magnitude * Time.deltaTime, ~0, QueryTriggerInteraction.Collide); #if UNITY_EDITOR DebugDrawExtensions.DrawBoxCastBox(transform.position - velocity * magnitude, AttachedCollider.bounds.extents, Quaternion.identity, velocity, AttachedCollider.attachedRigidbody.velocity.magnitude * Time.deltaTime * 2f, Color.white); #endif } else { hits = Physics.BoxCastAll(transform.position - velocity * magnitude, AttachedCollider.bounds.extents, velocity, Quaternion.identity, AttachedCollider.attachedRigidbody.velocity.magnitude * Time.deltaTime * 2f, ~0, QueryTriggerInteraction.Collide); #if UNITY_EDITOR DebugDrawExtensions.DrawBoxCastBox(transform.position - velocity * magnitude, AttachedCollider.bounds.extents, Quaternion.identity, velocity, AttachedCollider.attachedRigidbody.velocity.magnitude * Time.deltaTime * 2f, Color.white); #endif } var predictedCollide = false; foreach (var h in hits) { if (!h.collider) { continue; } var portal = h.collider.GetComponent <Portal>(); if (!portal) { PortalTrigger trigger; if (trigger = h.collider.GetComponent <PortalTrigger>()) { portal = trigger.portal; } } if (portal) { //Force the next physics step to tick on the bullet if (Bullet) { if (SKSGeneralUtils.IsBehind( transform.position + AttachedCollider.attachedRigidbody.velocity * Time.deltaTime, portal.Origin.position, portal.Origin.forward)) { transform.position += AttachedCollider.attachedRigidbody.velocity * Time.deltaTime; PortalUtils.TeleportObject(gameObject, portal.Origin, portal.ArrivalTarget, Root); } } portal.E_OnTriggerStay(AttachedCollider); predictedCollide = true; fastMovingAdded = true; } /* * if (portal) { * if (PortalUtils.IsBehind(transform.position + velocity, portal.Origin.position, * portal.Origin.forward)) { * portal.E_OnTriggerEnter(AttachedCollider); * predictedCollide = true; * } * * }*/ } if (!predictedCollide && fastMovingAdded) { if (CurrentPortal != null && AttachedCollider) { CurrentPortal.E_OnTriggerExit(AttachedCollider); fastMovingAdded = false; } } }
/// <summary> /// Instantiate the Doppeganger recursively. Makes a fully copy of all visual /// components of the object, discarding non-visual components. /// </summary> /// <param name="currentLevel">Current level to target</param> private void InstantiateDoppleganger(Transform currentLevel) { var other = SKSGeneralUtils.FindAnalogousTransform(currentLevel, Doppleganger.transform, Root, true); //Remove the MainCamera tag if it's been erroniously copied. if (currentLevel.tag.Equals("MainCamera")) { currentLevel.tag = Keywords.Tags.Untagged; } currentLevel.gameObject.name = currentLevel.gameObject.name; foreach (var component in currentLevel.GetComponents <Component>()) { if (component is Teleportable) { component.SafeDestroyComponent(); } //Copies Transforms for later updating else if (component is Transform) { if (other) { if (!Transforms.ContainsKey(other)) { Transforms.Add(other, (Transform)component); } } else { Destroy(currentLevel.gameObject); break; } } else if (component is Renderer) { if (component is SkinnedMeshRenderer) { SkinnedRenderers.Add(component as SkinnedMeshRenderer); } var meshRenderer = component as MeshRenderer; if (meshRenderer != null) { var otherRend = other.GetComponent <MeshRenderer>(); if (!Renderers.ContainsKey(otherRend)) { Renderers[otherRend] = meshRenderer; } //Adds colliders to list for collision ignoring upon Portal entry } else { var otherRend = other.GetComponent <Renderer>(); if (!Renderers.ContainsKey(otherRend)) { Renderers[otherRend] = (Renderer)component; } //Adds colliders to list for collision ignoring upon Portal entry } } else if (component is Collider) { if (!component.GetComponent <TeleportablePhysExclude>()) { var c = other.GetComponent <Collider>(); if (!_colliders.ContainsKey(c.GetInstanceID())) { _colliders.Add(c.GetInstanceID(), c); } #if SKS_VR else { //Fix for VRTK double-genning body colliders for no reason currentLevel.gameObject.transform.SetParent(null); c.enabled = false; int key = c.GetInstanceID(); _colliders[key].enabled = false; c.isTrigger = true; _colliders[key].isTrigger = true; DestroyImmediate(_colliders[key].gameObject); DestroyImmediate(currentLevel.gameObject); continue; } #endif } if (StripColliders && component) { component.SafeDestroyComponent(); } } else if (component is Rigidbody) { if (StripRigidbodies) { component.SafeDestroyComponent(); } } else if (component is Joint) { if (StripJoints) { component.SafeDestroyComponent(); } } else if (component is MonoBehaviour) { //Handling of teleportable scripts if (component is TeleportableScript) { TeleportableScripts.Add(other.GetComponent <TeleportableScript>()); } if (!StripScripts) { ((MonoBehaviour)component).enabled = true; } else { component.SafeDestroyComponent(); } //Nonspecific setup copying } else { var system = component as ParticleSystem; if (system != null) { var otherSystem = other.GetComponent <ParticleSystem>(); system.randomSeed = otherSystem.randomSeed; system.time = otherSystem.time; } else if (component is MeshFilter || component is Light) { //nothin to do } else { component.SafeDestroyComponent(); } } } if (other) { currentLevel.gameObject.SetActive(other.gameObject.activeSelf); } foreach (Transform t in currentLevel) { InstantiateDoppleganger(t); } }
private void InstantiateDoppleganger(Transform currentLevel) { Transform other = SKSGeneralUtils.FindAnalogousTransform(currentLevel, Doppleganger.transform, root, true); if (currentLevel.tag.Equals("MainCamera")) { currentLevel.tag = "Untagged"; } currentLevel.gameObject.name = currentLevel.gameObject.name; foreach (Component component in currentLevel.GetComponents <Component>()) { if (component is Teleportable) { component.SafeDestroyComponent(); } //Copies Transforms for later updating else if (component is Transform) { if (other) { if (!Transforms.ContainsKey(other)) { Transforms.Add(other, (Transform)component); } } else { Destroy(currentLevel.gameObject); break; } } else if (component is Renderer) { if (component is SkinnedMeshRenderer) { SkinnedRenderers.Add(component as SkinnedMeshRenderer); } if (component is Renderer) { if (!Renderers.ContainsKey((Renderer)component)) { Renderers[other.GetComponent <Renderer>()] = (Renderer)component; } //Adds colliders to list for collision ignoring upon Portal entry } } else if (component is Collider) { if (!component.GetComponent <TeleportablePhysExclude>()) { Collider c = other.GetComponent <Collider>(); if (!Colliders.ContainsKey(c.GetInstanceID())) { Colliders.Add(c.GetInstanceID(), c); } else { //Fix for VRTK double-genning body colliders for no reason currentLevel.gameObject.transform.SetParent(null); c.enabled = false; Colliders[c.GetInstanceID()].enabled = false; c.isTrigger = true; Colliders[c.GetInstanceID()].isTrigger = true; DestroyImmediate(Colliders[c.GetInstanceID()].gameObject); DestroyImmediate(currentLevel.gameObject); return; } } if (StripColliders && component) { component.SafeDestroyComponent(); } } else if (component is Rigidbody) { if (StripRigidbodies) { component.SafeDestroyComponent(); } } else if (component is Joint) { if (StripJoints) { component.SafeDestroyComponent(); } } else if (component is MonoBehaviour) { //Handling of teleportable scripts if (component is TeleportableScript) { TeleportableScripts.Add(other.GetComponent <TeleportableScript>()); } if (!StripScripts) { if (component != null) { ((MonoBehaviour)component).enabled = true; } } else { component.SafeDestroyComponent(); } //Nonspecific setup copying } else if (component is MeshFilter || component is ParticleSystem || component is Light) { //nothin to do } else { component.SafeDestroyComponent(); } } if (other) { currentLevel.gameObject.SetActive(other.gameObject.activeSelf); } foreach (Transform t in currentLevel) { InstantiateDoppleganger(t); } }