using Sirenix.OdinInspector; using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; namespace Beyond { public class TutorialController : MonoBehaviour { public bool played = false; public GameObject stepPanel; public List steps; public CanvasGroup tutorialButtonsCanva; private float fadeDuration = 0.4f, frameDuration = 0.02f; public List tutorialButtons; //colliders and stuff [SerializeField] private List objectsToEnableOnlyDuringTutorial; private BaseStepController currentStep; public int skipSteps = 0; public float delayToStart = 4f; // Start is called before the first frame update public UnityEvent OnTutorialEnded; private bool finished = false; private void Start() { if (tutorialButtons != null ) tutorialButtons.ForEach(button => button.SetActive(false)); if (tutorialButtonsCanva != null) { tutorialButtonsCanva.interactable = false; tutorialButtonsCanva.blocksRaycasts = false; } } [Button] public void StartTutorial() { StartCoroutine(StartTutorialCoroutine()); } private IEnumerator StartTutorialCoroutine() { //could check based on something different yield return new WaitForEndOfFrame(); if (played) { SkipTutorial(); yield break; } played = true; if (objectsToEnableOnlyDuringTutorial.Count > 0) { objectsToEnableOnlyDuringTutorial.ForEach(obj => obj.SetActive(true)); } yield return new WaitForSecondsRealtime(delayToStart); EnableTutorialButtons(); // tutorialButtons.ForEach(button => button.SetActive(true)); for (int i = 0; i < skipSteps; i++) { steps[i].ForceStepFinished(); } for (int i = skipSteps; i < steps.Count; i++) { if (i != steps.Count - 1) { steps[i].OnCompleted += steps[i + 1].StartStep; //this does not require an additional variable } else { steps[i].OnCompleted += () => { FinishTutorial(); }; } int locali = i; steps[i].OnStarted += () => //this does { Debug.Log("TutorialController.Step.OnStarted "+locali); currentStep = steps[locali]; }; } steps[skipSteps].StartStep(); } [Button] public void SkipTutorial() { if (!currentStep) { if (steps.Count > 0) { currentStep = steps[0]; } else return; } int id = steps.FindIndex(step => step == currentStep); for (int i = id; i < steps.Count; i++) { steps[i].ForceStepFinished(); } FinishTutorial(); } public void EnableTutorialButtons() { StartCoroutine(FadeInTutorialButtons()); } private IEnumerator FadeInTutorialButtons() { tutorialButtons.ForEach(button => button.SetActive(true)); float currentDuration = 0; while (currentDuration < fadeDuration) { yield return new WaitForSecondsRealtime(Time.unscaledDeltaTime); tutorialButtonsCanva.alpha = currentDuration / fadeDuration; currentDuration += Time.unscaledDeltaTime; // texts.ForEach(text => text.alpha = currentDuration / fadeDuration); } tutorialButtonsCanva.alpha = 1f; tutorialButtonsCanva.interactable = true; tutorialButtonsCanva.blocksRaycasts = true; } private void FinishTutorial() { if (finished) { return; } finished = true; played = true; StopAllCoroutines(); DisableTutorialButtons(); objectsToEnableOnlyDuringTutorial.ForEach(obj => obj.SetActive(false)); OnTutorialEnded?.Invoke(); } public void DisableTutorialButtons() { StartCoroutine(FadeOutTutorialButtons()); // tutorialButtons.ForEach(button => button.SetActive(false)); } private IEnumerator FadeOutTutorialButtons() { float currentDuration = 0; while (currentDuration < fadeDuration) { yield return new WaitForSecondsRealtime(Time.unscaledDeltaTime); tutorialButtonsCanva.alpha = (fadeDuration - currentDuration) / fadeDuration; currentDuration += Time.unscaledDeltaTime; // texts.ForEach(text => text.alpha = (fadeDuration - currentDuration) / fadeDuration); } tutorialButtonsCanva.alpha = 0f; tutorialButtonsCanva.interactable = false; tutorialButtonsCanva.blocksRaycasts = false; tutorialButtons.ForEach(button => button.SetActive(false)); } [Button] public void SkipTutorialStep() { try { Debug.Log("skipped"); currentStep.ForceStepFinished(); } catch (Exception e) { Debug.LogError("Exception in TutorialController.SkupTutorialStep, gameObject: "+gameObject.name+" "+e.ToString()); } } public int GetCurrentStepIndex() { return steps.FindIndex(item => item == currentStep); } public void SkipTutorialStepsTo(int stepIndex) { int index = GetCurrentStepIndex(); while (index != stepIndex) { steps[index].ForceStepFinished(); index++; } } } }