summaryrefslogtreecommitdiff
path: root/Assets/Samples/XR Interaction Toolkit/3.1.2/Starter Assets/Scripts/ClimbTeleportDestinationIndicator.cs
blob: f64d1561df07d13918a3cb7f0879ab99dd523d93 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
using UnityEngine.XR.Interaction.Toolkit.Locomotion.Climbing;
using UnityEngine.XR.Interaction.Toolkit.Locomotion.Teleportation;
using UnityEngine.XR.Interaction.Toolkit.Utilities;

namespace UnityEngine.XR.Interaction.Toolkit.Samples.StarterAssets
{
    /// <summary>
    /// Affordance component used in conjunction with a <see cref="ClimbTeleportInteractor"/> to display an object
    /// pointing at the target teleport destination while climbing.
    /// </summary>
    public class ClimbTeleportDestinationIndicator : MonoBehaviour
    {
        [SerializeField]
        [Tooltip("The interactor that drives the display and placement of the pointer object.")]
        ClimbTeleportInteractor m_ClimbTeleportInteractor;

        /// <summary>
        /// The interactor that drives the display and placement of the pointer object.
        /// </summary>
        public ClimbTeleportInteractor climbTeleportInteractor
        {
            get => m_ClimbTeleportInteractor;
            set => m_ClimbTeleportInteractor = value;
        }

        [SerializeField]
        [Tooltip("The prefab to spawn when a teleport destination is chosen. The instance will spawn next to the " +
            "destination and point its forward vector at the destination and its up vector at the camera.")]
        GameObject m_PointerPrefab;

        /// <summary>
        /// The prefab to spawn when a teleport destination is chosen. The instance will spawn next to the destination
        /// and point its forward vector at the destination and its up vector at the camera.
        /// </summary>
        public GameObject pointerPrefab
        {
            get => m_PointerPrefab;
            set => m_PointerPrefab = value;
        }

        [SerializeField]
        [Tooltip("The distance from the destination at which the pointer object spawns.")]
        float m_PointerDistance = 0.3f;

        /// <summary>
        /// The distance from the destination at which the pointer object spawns.
        /// </summary>
        public float pointerDistance
        {
            get => m_PointerDistance;
            set => m_PointerDistance = value;
        }

        TeleportationMultiAnchorVolume m_ActiveTeleportVolume;
        Transform m_PointerInstance;

        /// <summary>
        /// See <see cref="MonoBehaviour"/>.
        /// </summary>
        protected void OnEnable()
        {
            if (m_ClimbTeleportInteractor == null)
            {
                if (!ComponentLocatorUtility<ClimbTeleportInteractor>.TryFindComponent(out m_ClimbTeleportInteractor))
                {
                    Debug.LogError($"Could not find {nameof(ClimbTeleportInteractor)} in scene.");
                    enabled = false;
                    return;
                }
            }

            m_ClimbTeleportInteractor.hoverEntered.AddListener(OnInteractorHoverEntered);
            m_ClimbTeleportInteractor.hoverExited.AddListener(OnInteractorHoverExited);
        }

        /// <summary>
        /// See <see cref="MonoBehaviour"/>.
        /// </summary>
        protected void OnDisable()
        {
            HideIndicator();

            if (m_ActiveTeleportVolume != null)
            {
                m_ActiveTeleportVolume.destinationAnchorChanged -= OnClimbTeleportDestinationAnchorChanged;
                m_ActiveTeleportVolume = null;
            }

            if (m_ClimbTeleportInteractor != null)
            {
                m_ClimbTeleportInteractor.hoverEntered.RemoveListener(OnInteractorHoverEntered);
                m_ClimbTeleportInteractor.hoverExited.RemoveListener(OnInteractorHoverExited);
            }
        }

        void OnInteractorHoverEntered(HoverEnterEventArgs args)
        {
            if (m_ActiveTeleportVolume != null || !(args.interactableObject is TeleportationMultiAnchorVolume teleportVolume))
                return;

            m_ActiveTeleportVolume = teleportVolume;
            if (m_ActiveTeleportVolume.destinationAnchor != null)
                OnClimbTeleportDestinationAnchorChanged(m_ActiveTeleportVolume);

            m_ActiveTeleportVolume.destinationAnchorChanged += OnClimbTeleportDestinationAnchorChanged;
        }

        void OnInteractorHoverExited(HoverExitEventArgs args)
        {
            if (!(args.interactableObject is TeleportationMultiAnchorVolume teleportVolume) || teleportVolume != m_ActiveTeleportVolume)
                return;

            HideIndicator();
            m_ActiveTeleportVolume.destinationAnchorChanged -= OnClimbTeleportDestinationAnchorChanged;
            m_ActiveTeleportVolume = null;
        }

        void OnClimbTeleportDestinationAnchorChanged(TeleportationMultiAnchorVolume teleportVolume)
        {
            HideIndicator();

            var destinationAnchor = teleportVolume.destinationAnchor;
            if (destinationAnchor == null)
                return;

            m_PointerInstance = Instantiate(m_PointerPrefab).transform;
            var cameraTrans = teleportVolume.teleportationProvider.mediator.xrOrigin.Camera.transform;
            var cameraPosition = cameraTrans.position;
            var destinationPosition = destinationAnchor.position;
            var destinationDirectionInScreenSpace = cameraTrans.InverseTransformDirection(destinationPosition - cameraPosition);
            destinationDirectionInScreenSpace.z = 0f;
            var pointerDirection = cameraTrans.TransformDirection(destinationDirectionInScreenSpace).normalized;
            m_PointerInstance.position = destinationPosition - pointerDirection * m_PointerDistance;
            m_PointerInstance.rotation = Quaternion.LookRotation(pointerDirection, -cameraTrans.forward);
        }

        void HideIndicator()
        {
            if (m_PointerInstance != null)
                Destroy(m_PointerInstance.gameObject);
        }
    }
}