Files
AppleHillsProduction/Assets/Scripts/UI/Tutorial/DivingTutorial.cs

176 lines
4.9 KiB
C#
Raw Normal View History

2025-10-21 12:51:24 +02:00
using System.Collections;
using System.Linq;
2025-10-15 15:58:19 +02:00
using UnityEngine;
using Pixelplacement;
using Minigames.DivingForPictures;
using Input;
using UnityEngine.Events;
public class DivingTutorial : MonoBehaviour, ITouchInputConsumer
{
private StateMachine stateMachine;
public DivingGameManager divingGameManager;
public bool playTutorial;
2025-10-21 12:51:24 +02:00
// gating for input until current state's animation finishes first loop
private bool canAcceptInput = false;
private Coroutine waitLoopCoroutine;
2025-10-15 15:58:19 +02:00
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
2025-10-21 12:51:24 +02:00
if (playTutorial == true)
2025-10-15 15:58:19 +02:00
{
InitializeTutorial();
}
else { RemoveTutorial(); }
}
void InitializeTutorial()
{
stateMachine = GetComponentInChildren<StateMachine>();
divingGameManager.Pause();
InputManager.Instance.RegisterOverrideConsumer(this);
stateMachine.OnLastStateExited.AddListener(RemoveTutorial);
2025-10-21 12:51:24 +02:00
// prepare gating for the initial active state
SetupInputGateForCurrentState();
2025-10-15 15:58:19 +02:00
}
void RemoveTutorial()
{
Debug.Log("Remove me!");
2025-10-21 12:51:24 +02:00
if (waitLoopCoroutine != null)
{
StopCoroutine(waitLoopCoroutine);
waitLoopCoroutine = null;
}
2025-10-15 15:58:19 +02:00
InputManager.Instance.UnregisterOverrideConsumer(this);
divingGameManager.DoResume();
2025-10-21 12:51:24 +02:00
Destroy(gameObject);
2025-10-15 15:58:19 +02:00
}
public void OnTap(Vector2 position)
{
2025-10-21 12:51:24 +02:00
if (!canAcceptInput) return; // block taps until allowed
// consume this tap and immediately block further taps
canAcceptInput = false;
// move to next state
2025-10-15 15:58:19 +02:00
stateMachine.Next(true);
2025-10-21 12:51:24 +02:00
// after the state changes, set up gating for the new active state's animation
SetupInputGateForCurrentState();
2025-10-15 15:58:19 +02:00
}
public void OnHoldStart(Vector2 position)
{
return;
2025-10-15 15:58:19 +02:00
}
public void OnHoldMove(Vector2 position)
{
return;
2025-10-15 15:58:19 +02:00
}
public void OnHoldEnd(Vector2 position)
{
return;
2025-10-15 15:58:19 +02:00
}
2025-10-21 12:51:24 +02:00
private void SetupInputGateForCurrentState()
{
if (waitLoopCoroutine != null)
{
StopCoroutine(waitLoopCoroutine);
waitLoopCoroutine = null;
}
waitLoopCoroutine = StartCoroutine(WaitForFirstLoopOnActiveState());
}
private IEnumerator WaitForFirstLoopOnActiveState()
{
// wait a frame to ensure StateMachine has activated the correct state GameObject
yield return null;
// find the active child under the StateMachine (the current state)
Transform smTransform = stateMachine != null ? stateMachine.transform : transform;
Transform activeState = null;
for (int i = 0; i < smTransform.childCount; i++)
{
var child = smTransform.GetChild(i);
if (child.gameObject.activeInHierarchy)
{
activeState = child;
break;
}
}
if (activeState == null)
{
// if we can't find an active state, fail open: allow input
canAcceptInput = true;
yield break;
}
// look for a legacy Animation component on the active state
var anim = activeState.GetComponent<Animation>();
if (anim == null)
{
// no animation to wait for; allow input immediately
canAcceptInput = true;
yield break;
}
// determine a clip/state to observe
string clipName = anim.clip != null ? anim.clip.name : null;
AnimationState observedState = null;
if (!string.IsNullOrEmpty(clipName))
{
observedState = anim[clipName];
}
else
{
// fallback: take the first enabled state in the Animation
foreach (AnimationState st in anim)
{
observedState = st;
break;
}
}
if (observedState == null)
{
// nothing to observe; allow input
canAcceptInput = true;
yield break;
}
// wait until the animation starts playing the observed clip
float safetyTimer = 0f;
while (anim.isActiveAndEnabled && activeState.gameObject.activeInHierarchy && !anim.IsPlaying(observedState.name) && safetyTimer < 2f)
{
safetyTimer += Time.deltaTime;
yield return null;
}
// wait until the first loop completes (normalizedTime >= 1)
while (anim.isActiveAndEnabled && activeState.gameObject.activeInHierarchy)
{
// if state changed (not playing anymore), allow input to avoid deadlock
if (!anim.IsPlaying(observedState.name)) break;
if (observedState.normalizedTime >= 1f)
{
break;
}
yield return null;
}
canAcceptInput = true;
waitLoopCoroutine = null;
}
2025-10-15 15:58:19 +02:00
}