using UnityEngine;
using System.Collections;
using System;
using UnityEngine.Events;
using UnityEngine.XR.Interaction.Toolkit;
using NaughtyAttributes;
public class StepScript : MonoBehaviour
{
[Header("Step Info")]
///
/// Add a description to the step to explain what is supposed to be
///
[Tooltip("Add a description to the step to explain what is supposed to be")]
[TextArea(3, 10)]
public string description;
///
/// If true, the game object is enabled at game start
///
[Tooltip("If true, the game object is visible at game start")]
public bool isEnabledBeforeStart = true;
///
/// If true, the game object will stay enabled after the step is completed
///
[Tooltip("If true, the game object will stay visible after the step is completed")]
public bool isEnabledAfterEnd = true;
///
/// Refresh rate of the step, used to update the step
///
public float RefreshRate = 0.2f;
[HorizontalLine(1, EColor.Blue)]
///
/// If true, the step is completed at start, so no other completion event is needed
///
[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;
///
/// 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
///
[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;
///
/// These will be subscribed, so that they will act as completion events
///
//[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")]
///
/// If true, run the specified callbacks when the step starts
///
[Tooltip("If true, run the specified callbacks when the step starts")]
public bool useOnStart = false;
///
/// Event called when the step starts
///
[ShowIf("useOnStart")]
[Tooltip("Event called when the step starts, before the update loop")]
public UnityEvent OnStart;
///
/// If true, run the specified callbacks when the step is updated
///
[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;
///
/// If true, run the specified callbacks when the step is complete
///
[Tooltip("If true, run the specified callbacks when the step is complete")]
public bool useOnEnd = false;
///
/// If true, run the specified callbacks when the step is complete
///
///
[ShowIf("useOnEnd")]
[Tooltip("If true, run the specified callbacks when the step is complete")]
public UnityEvent OnEnd;
///
/// If true, once the OnEnd callback are called, a delay is started, this allows to
/// run another set of callback after these
///
[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;
///
/// Delay after the list ends, used to wait for delayed effects
///
[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;
///
/// Event called after the list ends, after a delay
///
[ShowIf("useDelayedEnd")]
[Tooltip("Event called after the list ends, after a delay")]
public UnityEvent OnEndPostDelay;
///
/// Flag to check if the step is complete
///
private bool isStepComplete;
///
/// Reference to the XRGrabInteractable component, used to detect when the item is grabbed
///
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();
if (grabInteractable == null)
{
throw new Exception("This script cannot access a XRGrabInteractable component");
}
}
gameObject.SetActive(isEnabledBeforeStart);
}
///
/// 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();
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");
}
///
/// Callback for to set the step as complete from any event that calls it
///
///
public void StepCompletionListener(SelectEnterEventArgs arg0)
{
isStepComplete = true;
Debug.Log("Step completed by grabbing an item");
}
///
/// Subscribe to the completion events
///
private void SubscribeToCompletionEvents()
{
// subscribe to the grab event, if needed
if (completeOnItemGrabbed)
{
grabInteractable.selectEntered.AddListener(StepCompletionListener);
}
}
///
/// Unsubscribe to the completion events
///
private void UnSubscribeToCompletionEvents()
{
if (completeOnItemGrabbed)
{
grabInteractable.selectEntered.RemoveListener(StepCompletionListener);
}
}
}