148 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			148 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| 
 | |
| namespace UnityEngine.XR.Content.Walkthrough
 | |
| {
 | |
|     /// <summary>
 | |
|     /// Defines a walkthrough - a series of steps gated by triggers
 | |
|     /// </summary>
 | |
|     public class Walkthrough : MonoBehaviour
 | |
|     {
 | |
| #pragma warning disable 649
 | |
|         [SerializeField]
 | |
|         [Tooltip("The name of this walkthrough - for reference by UI")]
 | |
|         string m_WalkthroughName;
 | |
| 
 | |
|         [SerializeField]
 | |
|         [Tooltip("All of the steps this walkthrough requires, in order")]
 | |
|         WalkthroughStep[] m_Steps;
 | |
| 
 | |
|         [SerializeField]
 | |
|         GameObject m_Waypoint;
 | |
| 
 | |
|         [SerializeField]
 | |
|         GameObject m_WaypointLink;
 | |
| 
 | |
|         [SerializeField]
 | |
|         bool m_LoopOnComplete = false;
 | |
| #pragma warning restore 649
 | |
| 
 | |
|         /// <summary>
 | |
|         /// The name of the walkthrough experience
 | |
|         /// </summary>
 | |
|         public string walkthroughName => m_WalkthroughName;
 | |
| 
 | |
|         /// <summary>
 | |
|         /// All of the steps this walkthrough requires, in order
 | |
|         /// </summary>
 | |
|         public WalkthroughStep[] steps => m_Steps;
 | |
| 
 | |
|         /// <summary>
 | |
|         /// The currently active step of the walkthrough
 | |
|         /// </summary>
 | |
|         public int currentStep { get; private set; } = 0;
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Event that is raised whenever the state of the walkthrough has changed.
 | |
|         /// </summary>
 | |
|         public Action walkthroughChangedCallback;
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Shifts to another step of the walkthrough
 | |
|         /// </summary>
 | |
|         /// <param name="stepIndex">The step to make active</param>
 | |
|         /// <param name="autoProgressIfComplete">If true, allows for skipping to the subsequent step if the current one is already complete.</param>
 | |
|         public void SkipToStep(int stepIndex, bool autoProgressIfComplete)
 | |
|         {
 | |
|             // Ignore invalid indices and no-ops
 | |
|             if (stepIndex < 0 || stepIndex >= m_Steps.Length || stepIndex == currentStep)
 | |
|                 return;
 | |
| 
 | |
|             // If any steps between our current step and the next are incomplete and block progression, we do not allow skipping to occur. This prevents
 | |
|             // problems like skipping to a step where relocalization has not yet occurred.
 | |
|             if (stepIndex > currentStep)
 | |
|             {
 | |
|                 for (var testStepIndex = currentStep; testStepIndex < stepIndex; testStepIndex++)
 | |
|                 {
 | |
|                     var testStep = m_Steps[testStepIndex];
 | |
|                     if (!testStep.canSkip)
 | |
|                     {
 | |
|                         Debug.LogWarning($"Can't skip past incomplete step {testStep.name}");
 | |
|                         walkthroughChangedCallback?.Invoke();
 | |
|                         return;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             // If a valid step is already being displayed, set it back to inactive now
 | |
|             if (currentStep >= 0 && currentStep < m_Steps.Length)
 | |
|                 m_Steps[currentStep].CancelStep();
 | |
| 
 | |
|             currentStep = stepIndex;
 | |
|             m_Steps[currentStep].StartStep(OnStepComplete, autoProgressIfComplete);
 | |
| 
 | |
|             walkthroughChangedCallback?.Invoke();
 | |
|         }
 | |
| 
 | |
|         public void SkipToStep(int stepIndex)
 | |
|         {
 | |
|             SkipToStep(stepIndex, false);
 | |
|         }
 | |
| 
 | |
|         void Awake()
 | |
|         {
 | |
|             int stepIndex = 1;
 | |
|             // We ensure each walkthrough step is ready to work (as we can't ensure components are waking in a determined order), then start the first step
 | |
|             foreach (var step in m_Steps)
 | |
|             {
 | |
|                 step.Initialize();
 | |
|                 var waypoint = Instantiate(m_Waypoint, step.gameObject.transform);
 | |
|                 waypoint.transform.localPosition = Vector3.zero;
 | |
|                 waypoint.transform.rotation = Quaternion.identity;
 | |
|                 var waypointText = waypoint.GetComponentInChildren<TMPro.TMP_Text>();
 | |
|                 waypointText.text = stepIndex.ToString();
 | |
|                 step.waypoint = waypoint;
 | |
| 
 | |
|                 if (stepIndex > 1)
 | |
|                 {
 | |
|                     var link = Instantiate(m_WaypointLink, step.gameObject.transform);
 | |
|                     link.transform.localPosition = Vector3.zero;
 | |
|                     link.transform.rotation = Quaternion.identity;
 | |
|                     var linkCurve = link.GetComponentInChildren<WaypointCurve>();
 | |
|                     linkCurve.start = m_Steps[stepIndex - 2].gameObject.transform.position;
 | |
|                     linkCurve.end = m_Steps[stepIndex - 1].gameObject.transform.position;
 | |
|                     step.link = link;
 | |
|                 }
 | |
| 
 | |
|                 stepIndex++;
 | |
|             }
 | |
|             if (m_Steps != null && m_Steps.Length > 0)
 | |
|                 m_Steps[currentStep].StartStep(OnStepComplete);
 | |
| 
 | |
|             walkthroughChangedCallback?.Invoke();
 | |
|         }
 | |
| 
 | |
|         void OnStepComplete(bool autoProgress)
 | |
|         {
 | |
|             // We still call the changed callback even if we are not auto-progressing, as some UI may want to update labels or controls
 | |
|             if (!autoProgress)
 | |
|             {
 | |
|                 walkthroughChangedCallback?.Invoke();
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             // If we are auto-progressing, increment the step index and start the process again
 | |
|             currentStep++;
 | |
| 
 | |
|             if (m_LoopOnComplete && currentStep >= m_Steps.Length)
 | |
|                 currentStep = 0;
 | |
| 
 | |
|             if (m_Steps == null || currentStep >= m_Steps.Length)
 | |
|                 return;
 | |
| 
 | |
|             m_Steps[currentStep].StartStep(OnStepComplete);
 | |
| 
 | |
|             walkthroughChangedCallback?.Invoke();
 | |
|         }
 | |
|     }
 | |
| }
 |