forked from cgvr/DeltaVR
		
	
		
			
				
	
	
		
			289 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			289 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using System;
 | 
						|
using System.Collections.Generic;
 | 
						|
using UnityEngine.Events;
 | 
						|
using UnityEngine.XR.Interaction.Toolkit;
 | 
						|
 | 
						|
namespace UnityEngine.XR.Content.Walkthrough
 | 
						|
{
 | 
						|
    /// <summary>
 | 
						|
    /// Contains information needed to process one step of a walkthrough.
 | 
						|
    /// </summary>
 | 
						|
    public class WalkthroughStep : MonoBehaviour
 | 
						|
    {
 | 
						|
        /// Local method use only -- created here to reduce garbage collection. Collections must be cleared before use
 | 
						|
        static readonly List<WalkthroughTrigger> s_TriggersToRemove = new List<WalkthroughTrigger>();
 | 
						|
 | 
						|
        [SerializeField]
 | 
						|
        [Tooltip("Camera target to reposition user.")]
 | 
						|
        GameObject m_CameraTarget;
 | 
						|
 | 
						|
        [SerializeField]
 | 
						|
        [Tooltip("The Teleportation Provider used to reposition the user. Usually a component on the XR Origin.")]
 | 
						|
        TeleportationProvider m_TeleportationProvider;
 | 
						|
 | 
						|
        [SerializeField]
 | 
						|
        [Tooltip("Optional audio source for voiceover")]
 | 
						|
        AudioSource m_AudioSource;
 | 
						|
 | 
						|
        [SerializeField]
 | 
						|
        [Tooltip("Objects to enable when this step is active.")]
 | 
						|
        List<GameObject> m_Visuals = new List<GameObject>();
 | 
						|
 | 
						|
#pragma warning disable 649
 | 
						|
        [SerializeField]
 | 
						|
        [Tooltip("Actions to call when the step starts.")]
 | 
						|
        UnityEvent m_OnStepBegin;
 | 
						|
 | 
						|
        [SerializeField]
 | 
						|
        [Tooltip("Actions to call when the step completes.")]
 | 
						|
        UnityEvent m_OnStepComplete;
 | 
						|
 | 
						|
        [SerializeField]
 | 
						|
        [Tooltip("The purpose of this step.")]
 | 
						|
        string m_Description;
 | 
						|
#pragma warning restore 649
 | 
						|
 | 
						|
        [SerializeField]
 | 
						|
        [Tooltip("If true, this step cannot be skipped until completed at least once.")]
 | 
						|
        bool m_BlockUntilComplete;
 | 
						|
 | 
						|
        [SerializeField]
 | 
						|
        [Tooltip("If true, this step will automatically progress when complete - unless explicitly skipped to.")]
 | 
						|
        bool m_AutoProgressOnComplete = true;
 | 
						|
 | 
						|
        bool m_Started;
 | 
						|
        bool m_AutoProgressEnabled = true;
 | 
						|
        bool m_StepInvoked;
 | 
						|
 | 
						|
        Action<bool> m_OnComplete;
 | 
						|
        GameObject m_Waypoint;
 | 
						|
        GameObject m_Link;
 | 
						|
 | 
						|
        List<WalkthroughTrigger> m_Triggers = new List<WalkthroughTrigger>();
 | 
						|
        List<WalkthroughTrigger> m_RemainingTriggers = new List<WalkthroughTrigger>();
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// The purpose of this step. Appends a (Complete) if complete and normally has triggers.
 | 
						|
        /// </summary>
 | 
						|
        public string description => $"{m_Description}{(completed && m_Triggers.Count > 0 ? " (Complete)" : "") }";
 | 
						|
 | 
						|
 | 
						|
        public GameObject waypoint
 | 
						|
        {
 | 
						|
            get => m_Waypoint;
 | 
						|
            set => m_Waypoint = value;
 | 
						|
        }
 | 
						|
 | 
						|
        public GameObject link
 | 
						|
        {
 | 
						|
            get => m_Link;
 | 
						|
            set => m_Link = value;
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Ensures the step visuals are hidden until active and that all triggers are accounted for
 | 
						|
        /// </summary>
 | 
						|
        public void Initialize()
 | 
						|
        {
 | 
						|
            if (!m_Started)
 | 
						|
                SetVisualsState(false);
 | 
						|
 | 
						|
            GetComponents(m_Triggers);
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Returns true if this step does not currently have any triggers remaining to fire
 | 
						|
        /// </summary>
 | 
						|
        public bool canProgress => (!m_BlockUntilComplete || (m_RemainingTriggers.Count == 0));
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Returns true if this step does not block, or has been completed at least once.
 | 
						|
        /// </summary>
 | 
						|
        public bool canSkip => (!m_BlockUntilComplete || completed);
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// True if this step's triggers have been activated at least once
 | 
						|
        /// </summary>
 | 
						|
        public bool completed { get; private set; }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Makes this step and its triggers the active focus of a walkthrough
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="onComplete">Callback to fire when this step's triggers are complete</param>
 | 
						|
        /// <param name="allowAutoProgress">If this step is allow to auto-progress during this activation</param>
 | 
						|
        public void StartStep(Action<bool> onComplete, bool allowAutoProgress = true)
 | 
						|
        {
 | 
						|
            if (m_Started)
 | 
						|
                return;
 | 
						|
 | 
						|
            // Autoprogression is enabled only if the step AND walkthrough allow it
 | 
						|
            m_AutoProgressEnabled = allowAutoProgress && m_AutoProgressOnComplete;
 | 
						|
 | 
						|
            SetVisualsState(true);
 | 
						|
            SetAudioSource(true);
 | 
						|
            if (m_Waypoint != null)
 | 
						|
            {
 | 
						|
                m_Waypoint.SetActive(false);
 | 
						|
            }
 | 
						|
 | 
						|
            if (m_CameraTarget != null && m_TeleportationProvider != null)
 | 
						|
            {
 | 
						|
                SetCameraPosition();
 | 
						|
            }
 | 
						|
 | 
						|
            m_OnComplete = onComplete;
 | 
						|
 | 
						|
            m_Started = true;
 | 
						|
 | 
						|
            if (m_Triggers.Count == 0 && m_AutoProgressEnabled)
 | 
						|
            {
 | 
						|
                CompleteStep();
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            foreach (var currentTrigger in m_Triggers)
 | 
						|
            {
 | 
						|
                if (currentTrigger.ResetTrigger())
 | 
						|
                    m_RemainingTriggers.Add(currentTrigger);
 | 
						|
            }
 | 
						|
 | 
						|
            if (m_RemainingTriggers.Count == 0)
 | 
						|
            {
 | 
						|
                CompleteStep();
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            if (m_RemainingTriggers.Count > 0)
 | 
						|
                m_AutoProgressEnabled = m_AutoProgressOnComplete;
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Ends this step being the focus of the current walkthrough
 | 
						|
        /// </summary>
 | 
						|
        public void CancelStep()
 | 
						|
        {
 | 
						|
            SetVisualsState(false);
 | 
						|
            SetAudioSource(false);
 | 
						|
            if (m_Waypoint != null)
 | 
						|
            {
 | 
						|
                m_Waypoint.SetActive(true);
 | 
						|
            }
 | 
						|
 | 
						|
            if (!m_Started)
 | 
						|
                return;
 | 
						|
 | 
						|
            m_OnComplete = null;
 | 
						|
            m_Started = false;
 | 
						|
 | 
						|
            m_RemainingTriggers.Clear();
 | 
						|
        }
 | 
						|
 | 
						|
        void CompleteStep()
 | 
						|
        {
 | 
						|
            if (!m_Started)
 | 
						|
                return;
 | 
						|
 | 
						|
            completed = true;
 | 
						|
 | 
						|
            m_OnComplete?.Invoke(m_AutoProgressEnabled);
 | 
						|
            m_OnComplete = null;
 | 
						|
            m_Started = false;
 | 
						|
 | 
						|
            // We disable visuals if the the next step is being activated
 | 
						|
            if (m_AutoProgressEnabled)
 | 
						|
            {
 | 
						|
                SetVisualsState(false);
 | 
						|
                SetAudioSource(false);
 | 
						|
                if (m_Waypoint != null)
 | 
						|
                {
 | 
						|
                    m_Waypoint.SetActive(true);
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            m_RemainingTriggers.Clear();
 | 
						|
        }
 | 
						|
 | 
						|
        void Update()
 | 
						|
        {
 | 
						|
            // If this step is running, check remaining triggers.  Any triggers that are now met get removed.
 | 
						|
            // If there are no triggers left, then the step is complete.
 | 
						|
            if (!m_Started)
 | 
						|
                return;
 | 
						|
 | 
						|
            if (m_RemainingTriggers.Count == 0)
 | 
						|
                return;
 | 
						|
 | 
						|
            s_TriggersToRemove.Clear();
 | 
						|
            foreach (var currentTrigger in m_RemainingTriggers)
 | 
						|
            {
 | 
						|
                if (currentTrigger.Check())
 | 
						|
                    s_TriggersToRemove.Add(currentTrigger);
 | 
						|
            }
 | 
						|
 | 
						|
            foreach (var toRemove in s_TriggersToRemove)
 | 
						|
            {
 | 
						|
                m_RemainingTriggers.Remove(toRemove);
 | 
						|
            }
 | 
						|
            s_TriggersToRemove.Clear();
 | 
						|
 | 
						|
            if (m_RemainingTriggers.Count == 0)
 | 
						|
            {
 | 
						|
                CompleteStep();
 | 
						|
                return;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        void SetVisualsState(bool enabled)
 | 
						|
        {
 | 
						|
            if (m_Visuals != null)
 | 
						|
            {
 | 
						|
                foreach (var currentVisual in m_Visuals)
 | 
						|
                {
 | 
						|
                    if (currentVisual != null)
 | 
						|
                        currentVisual.SetActive(enabled);
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            if (m_StepInvoked == enabled)
 | 
						|
                return;
 | 
						|
 | 
						|
            m_StepInvoked = enabled;
 | 
						|
 | 
						|
            if (enabled && m_OnStepBegin != null)
 | 
						|
                m_OnStepBegin.Invoke();
 | 
						|
 | 
						|
            if (!enabled && m_OnStepComplete != null)
 | 
						|
                m_OnStepComplete.Invoke();
 | 
						|
        }
 | 
						|
 | 
						|
        void SetAudioSource(bool enabled)
 | 
						|
        {
 | 
						|
            if (m_AudioSource != null)
 | 
						|
            {
 | 
						|
                if (enabled)
 | 
						|
                {
 | 
						|
                    m_AudioSource.Play();
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    m_AudioSource.Stop();
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        void SetCameraPosition()
 | 
						|
        {
 | 
						|
            TeleportRequest request = new TeleportRequest()
 | 
						|
            {
 | 
						|
                requestTime = Time.time,
 | 
						|
                matchOrientation = MatchOrientation.TargetUpAndForward,
 | 
						|
 | 
						|
                destinationPosition = m_CameraTarget.transform.position,
 | 
						|
                destinationRotation = m_CameraTarget.transform.rotation
 | 
						|
            };
 | 
						|
 | 
						|
            m_TeleportationProvider.QueueTeleportRequest(request);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |