239 lines
No EOL
7.5 KiB
C#
239 lines
No EOL
7.5 KiB
C#
using UnityEngine;
|
|
using System.Collections;
|
|
using System;
|
|
using UnityEngine.Events;
|
|
using UnityEngine.XR.Interaction.Toolkit;
|
|
using NaughtyAttributes;
|
|
|
|
public class StepScript : MonoBehaviour
|
|
{
|
|
[Header("Step Info")]
|
|
/// <summary>
|
|
/// Add a description to the step to explain what is supposed to be
|
|
/// </summary>
|
|
[Tooltip("Add a description to the step to explain what is supposed to be")]
|
|
[TextArea(3, 10)]
|
|
public string description;
|
|
|
|
/// <summary>
|
|
/// If true, the game object is enabled at game start
|
|
/// </summary>
|
|
[Tooltip("If true, the game object is visible at game start")]
|
|
public bool isEnabledBeforeStart = true;
|
|
|
|
/// <summary>
|
|
/// If true, the game object will stay enabled after the step is completed
|
|
/// </summary>
|
|
[Tooltip("If true, the game object will stay visible after the step is completed")]
|
|
public bool isEnabledAfterEnd = true;
|
|
|
|
|
|
/// <summary>
|
|
/// Refresh rate of the step, used to update the step
|
|
/// </summary>
|
|
public float RefreshRate = 0.2f;
|
|
|
|
[HorizontalLine(1, EColor.Blue)]
|
|
|
|
|
|
/// <summary>
|
|
/// If true, the step is completed at start, so no other completion event is needed
|
|
/// </summary>
|
|
[Tooltip("If true, the step is completed at start, so no other completion event is needed. It can still use pre and post callbacks")]
|
|
public bool startCompleted = false;
|
|
|
|
/// <summary>
|
|
/// If true, the step is completed when the item is grabbed it needs the XRGrabInteractable component
|
|
/// to detect when the item is grabbed. At least one completion event must be set to avoid an infinite loop
|
|
/// </summary>
|
|
[Tooltip("If true, the step is completed when the item is grabbed it needs the XRGrabInteractable component " +
|
|
"to detect when the item is grabbed. At least one completion event must be set to avoid an infinite loop")]
|
|
[InfoBox("Use this if no other complention events are added", EInfoBoxType.Warning)]
|
|
[HideIf("startCompleted")]
|
|
public bool completeOnItemGrabbed = true;
|
|
|
|
/// <summary>
|
|
/// These will be subscribed, so that they will act as completion events
|
|
/// </summary>
|
|
//[Tooltip("These will be subscribed, so that they will act as completion events. They can be used with the rab event.")]
|
|
//[HideIf("startCompleted")]
|
|
//public UnityEvent StepCompletionEvents;
|
|
|
|
[HorizontalLine(1, EColor.Blue)]
|
|
|
|
[Header("Callbacks")]
|
|
|
|
/// <summary>
|
|
/// If true, run the specified callbacks when the step starts
|
|
/// </summary>
|
|
[Tooltip("If true, run the specified callbacks when the step starts")]
|
|
public bool useOnStart = false;
|
|
|
|
/// <summary>
|
|
/// Event called when the step starts
|
|
/// </summary>
|
|
[ShowIf("useOnStart")]
|
|
[Tooltip("Event called when the step starts, before the update loop")]
|
|
public UnityEvent OnStart;
|
|
|
|
/// <summary>
|
|
/// If true, run the specified callbacks when the step is updated
|
|
/// </summary>
|
|
[HideIf("startCompleted")]
|
|
[Tooltip("This run the main callbacks that run until the step is complete by another event. The refresh rate is the same of the HapticManager")]
|
|
public UnityEvent OnUpdate;
|
|
|
|
/// <summary>
|
|
/// If true, run the specified callbacks when the step is complete
|
|
/// </summary>
|
|
[Tooltip("If true, run the specified callbacks when the step is complete")]
|
|
public bool useOnEnd = false;
|
|
|
|
/// <summary>
|
|
/// If true, run the specified callbacks when the step is complete
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
[ShowIf("useOnEnd")]
|
|
[Tooltip("If true, run the specified callbacks when the step is complete")]
|
|
public UnityEvent OnEnd;
|
|
|
|
/// <summary>
|
|
/// If true, once the OnEnd callback are called, a delay is started, this allows to
|
|
/// run another set of callback after these
|
|
/// </summary>
|
|
[Tooltip("If true, once the OnEnd callback are called, a delay is started, this allows to " +
|
|
"run another set of callback after these")]
|
|
public bool useDelayedEnd = false;
|
|
|
|
/// <summary>
|
|
/// Delay after the list ends, used to wait for delayed effects
|
|
/// </summary>
|
|
[ShowIf("useDelayedEnd")]
|
|
[MinValue(0.0f), MaxValue(60)]
|
|
[Tooltip("Delay after the list ends, used to wait for delayed effects, runned before the OnEndPostDelay")]
|
|
public float endTimeDurationSeconds = 5f;
|
|
|
|
/// <summary>
|
|
/// Event called after the list ends, after a delay
|
|
/// </summary>
|
|
[ShowIf("useDelayedEnd")]
|
|
[Tooltip("Event called after the list ends, after a delay")]
|
|
public UnityEvent OnEndPostDelay;
|
|
|
|
/// <summary>
|
|
/// Flag to check if the step is complete
|
|
/// </summary>
|
|
private bool isStepComplete;
|
|
|
|
/// <summary>
|
|
/// Reference to the XRGrabInteractable component, used to detect when the item is grabbed
|
|
/// </summary>
|
|
private XRGrabInteractable grabInteractable;
|
|
|
|
void Start()
|
|
{
|
|
if(startCompleted)
|
|
{
|
|
completeOnItemGrabbed = false;
|
|
OnUpdate = null;
|
|
}
|
|
|
|
if (gameObject == null)
|
|
{
|
|
throw new Exception("This script cannot access a gameObject");
|
|
}
|
|
else if (gameObject.transform == null)
|
|
{
|
|
throw new Exception("This script cannot access a gameObject transform");
|
|
}
|
|
else if (completeOnItemGrabbed) {
|
|
grabInteractable = gameObject.GetComponent<XRGrabInteractable>();
|
|
|
|
if (grabInteractable == null)
|
|
{
|
|
throw new Exception("This script cannot access a XRGrabInteractable component");
|
|
}
|
|
}
|
|
|
|
gameObject.SetActive(isEnabledBeforeStart);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Run the step, this is called by the StepsListScript
|
|
public IEnumerator StepRun()
|
|
{
|
|
Debug.Log("Step: " + name + " started");
|
|
|
|
isStepComplete = startCompleted;
|
|
|
|
gameObject.SetActive(true);
|
|
|
|
if (useOnStart)
|
|
{
|
|
OnStart.Invoke();
|
|
}
|
|
|
|
if (!startCompleted)
|
|
{
|
|
grabInteractable = gameObject.GetComponent<XRGrabInteractable>();
|
|
SubscribeToCompletionEvents();
|
|
|
|
do
|
|
{
|
|
OnUpdate.Invoke();
|
|
// Debug.Log("Step: " + name + " updated");
|
|
yield return new WaitForSeconds(RefreshRate);
|
|
} while (!isStepComplete);
|
|
|
|
UnSubscribeToCompletionEvents();
|
|
}
|
|
|
|
if (useOnEnd)
|
|
{
|
|
OnEnd.Invoke();
|
|
}
|
|
|
|
if (useDelayedEnd)
|
|
{
|
|
yield return new WaitForSeconds(endTimeDurationSeconds);
|
|
OnEndPostDelay.Invoke();
|
|
}
|
|
|
|
gameObject.SetActive(isEnabledAfterEnd);
|
|
|
|
Debug.Log("Step complete");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Callback for to set the step as complete from any event that calls it
|
|
/// </summary>
|
|
/// <param name="arg0"></param>
|
|
public void StepCompletionListener(SelectEnterEventArgs arg0)
|
|
{
|
|
isStepComplete = true;
|
|
Debug.Log("Step completed by grabbing an item");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Subscribe to the completion events
|
|
/// </summary>
|
|
private void SubscribeToCompletionEvents()
|
|
{
|
|
// subscribe to the grab event, if needed
|
|
if (completeOnItemGrabbed)
|
|
{
|
|
grabInteractable.selectEntered.AddListener(StepCompletionListener);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Unsubscribe to the completion events
|
|
/// </summary>
|
|
private void UnSubscribeToCompletionEvents()
|
|
{
|
|
if (completeOnItemGrabbed)
|
|
{
|
|
grabInteractable.selectEntered.RemoveListener(StepCompletionListener);
|
|
}
|
|
}
|
|
} |