using UnityEngine; using UnityEngine.Events; using UnityEngine.EventSystems; namespace Passer { using Humanoid; /// The Teleport Target provides control to where a player can teleport and can be used in combination with a generic Interaction Pointer. /// The Teleport Target can be placed on a static or moving Rigidbody object with a collider. /// It has been implemented as a Event Trigger and will teleport when an PointerDown event is received. [HelpURLAttribute("https://passervr.com/documentation/humanoid-control/tools/teleport-target/")] public class TeleportTarget : EventTrigger { public enum TargetPosRot { Pointer, Transform } /// Teleport the root transform instead of the transform itself. /// If this is enabled the root of the transform (the topmost transform) /// will be teleported instead of the transform itself. public bool teleportRoot = false; /// Check the target location for collisions. /// if enabled this will check if the location to which the pointer is pointing contains a collider. /// Teleporting will only take place if no collider has been found. /// The check is executed using a capsule of 2 meters/units high and 0.2 meters/units radius. public bool checkCollision = true; /// The type of movement used to reacht the teleport target. /// determines how the Transform is moved to the Target Point. /// Teleport = direct placement a the target point. /// Dash = a quick movement is a short time from the originating point to the target point. public MovementType movementType; /// Determines the target position and rotation. /// TargetPosRot.Pointer = The interaction pointer location is the target position and rotation. /// TargetPosRot.Transform = The targetTransform determines the target position and rototation. public TargetPosRot targetPosRot = TargetPosRot.Pointer; /// The target transform for the teleport. /// If targetPosRot is set to TargetPosRot.Transform the targetTransform will determine the /// position and rotation of the transform to teleport. /// Next to that, the teleported transform will become a child of this teleportTarget after teleporting public Transform targetTransform; /// The pose of a humanoid after it has been teleported. /// This is an optional Pose of the Humanoid after it has been teleported. /// This enables you to teleport to a different pose like a seating pose for instance. public Pose pose; /// Enables humanoid animators after teleporting. /// This will enable or disable the hips and foot animator after teleporting. /// For poses like seating a walking foot animation is not required. /// In such cases the foot animator can be switch off with this setting. public bool enableAnimators = true; /// Teleport the transform to this Teleport Target. /// This function will teleport the given transform to this teleport target using the /// teleport target settings. /// If the targetPosRot is set to TargetPosRot.Pointer, the transform will be transported /// using the transform of the gameObject as there is no pointer information. /// The transform to teleport public void TeleportToHere(Transform t) { if (targetPosRot == TargetPosRot.Transform && targetTransform != null) Teleport(t, targetTransform.position, targetTransform.rotation, movementType, targetTransform); else Teleport(t, gameObject.transform.position, gameObject.transform.rotation, movementType, null); } /// Teleport the Humanoid to this Teleport Target. /// This function will teleport the given humanoid to this teleport target using the /// teleport target settings. /// If the targetPosRot is set to TargetPosRot.Pointer, the humanoid will be transported /// using the transform of the gameObject as there is no pointer information. /// The humanoid to teleport public void TeleportToHere(HumanoidControl humanoid) { if (targetPosRot == TargetPosRot.Transform && targetTransform != null) Teleport(humanoid.transform, targetTransform.position, targetTransform.rotation, movementType, targetTransform); else Teleport(humanoid.transform, gameObject.transform.position, gameObject.transform.rotation, movementType); } /// Teleporting initialized by an Unity UI Event. public override void OnPointerDown(PointerEventData eventData) { Vector3 pointingPosition = eventData.pointerCurrentRaycast.worldPosition; if (IsValid(pointingPosition) && eventData.currentInputModule != null) { GameObject originator = eventData.currentInputModule.gameObject; Transform teleportingTransform = originator.transform; HumanoidControl humanoid = originator.transform.GetComponentInParent(); if (humanoid != null) { teleportingTransform = humanoid.transform; humanoid.hipsTarget.torsoAnimator.enabled = enableAnimators; humanoid.leftFootTarget.legAnimator.enabled = enableAnimators; humanoid.rightFootTarget.legAnimator.enabled = enableAnimators; } if (targetPosRot == TargetPosRot.Pointer) Teleport(teleportingTransform, pointingPosition, originator.transform.rotation, movementType, null); else if (targetTransform != null) Teleport(teleportingTransform, targetTransform.position, targetTransform.rotation, movementType, targetTransform); else Teleport(teleportingTransform, transform.position, transform.rotation, movementType, targetTransform); if (humanoid != null) { humanoid.pose = pose; if (pose != null) { float oldNeckHeight = humanoid.headTarget.head.target.transform.position.y; humanoid.pose.Show(humanoid); float deltaNeckHeight = humanoid.headTarget.head.target.transform.position.y - oldNeckHeight; humanoid.AdjustTracking(new Vector3(0, deltaNeckHeight, 0)); humanoid.CopyRigToTargets(); } } } base.OnPointerDown(eventData); } /// Teleport the transform to a position and rotation. /// This function will teleport the given transform to this teleport target using the /// teleport target settings. /// If the targetPosRot is set to TargetPosRot.Pointer, the transform will be transported /// using the transform of the gameObject as there is no pointer information. /// The transform to teleport /// The new world position of the transform after teleporting /// The new world rotation of the transform after teleporting /// The movement type to use to get to the target /// The new parent of the transform after teleporting protected virtual void Teleport(Transform transform, Vector3 position, Quaternion rotation, MovementType movementType = MovementType.Teleport, Transform newParent = null) { if (newParent != null && transform.parent == newParent) // The transform is already at the teleport target, do not teleport again return; Vector3 originPosition = transform.position; Quaternion humanoidRotation = Quaternion.identity; HumanoidControl humanoid = transform.GetComponent(); if (humanoid != null) { Vector3 humanoidPosition = humanoid.GetHumanoidPosition(); Vector3 deltaHumanoid = humanoidPosition - transform.position; Vector3 humanoidForward = humanoid.hipsTarget.transform.forward; humanoidForward.y = 0; humanoidRotation = Quaternion.LookRotation(humanoidForward, humanoid.up); GameObject realWorld = HumanoidControl.GetRealWorld(humanoid.transform); realWorld.transform.position -= deltaHumanoid; realWorld.transform.rotation *= Quaternion.Inverse(humanoidRotation); } if (teleportRoot) { Vector3 translation = position - originPosition; // World coordinates transform = transform.root; position = transform.position + translation; } Debug.Log("TeleportRoot: " + teleportRoot + ", teleporting " + transform.name); transform.MoveTo(position, movementType); transform.rotation = rotation; transform.SetParent(newParent, true); } /// Check is the target position is valid. protected virtual bool IsValid(Vector3 position) { if (!checkCollision) return true; Vector3 start = position + new Vector3(0, 0.3F, 0); Vector3 end = position + new Vector3(0, 1.8F, 0); bool isOccupied = Physics.CheckCapsule(start, end, 0.2F); return (!isOccupied); } public UnityEvent unityEvents; } }