using Cysharp.Threading.Tasks; using System; using System.Collections.Generic; using System.Threading; using TMPro; using UnityEngine; using UnityEngine.UI; public class Instruction : MonoBehaviour { [Header("Exit progress")] [SerializeField] private CanvasGroup progressGroup; [SerializeField] private Image bar; private bool groupVisible = false; private float progress; private CancellationTokenSource exitBarCts; [Header("Instruction")] [SerializeField] TextMeshProUGUI instructionLabel; [SerializeField] CanvasGroup UpLeft, UpRight, DownLeft, DownRight, LabelCG; [SerializeField] List instructions; private CancellationTokenSource instructionCts; private Dictionary buttons; public void SetProgress(float percent) => progress = percent; public void Init() { buttons = new() { [InSignal.UpLeft] = UpLeft, [InSignal.UpRight] = UpRight, [InSignal.DownLeft] = DownLeft, [InSignal.DownRight] = DownRight }; instructionCts = new(); StartInstructionsSequence(instructionCts.Token).Forget(); SetProgress(0); } private void Update() { ProgressBarProcess(); } private void OnDestroy() { instructionCts?.Cancel(); instructionCts?.Dispose(); exitBarCts?.Cancel(); exitBarCts?.Dispose(); } private void ProgressBarProcess() { if (!groupVisible && progress > 0) { exitBarCts?.Cancel(); exitBarCts?.Dispose(); exitBarCts = new(); SetVisibility(true, exitBarCts.Token).Forget(); } if (groupVisible && progress == 0) { exitBarCts?.Cancel(); exitBarCts?.Dispose(); exitBarCts = new(); SetVisibility(false, exitBarCts.Token).Forget(); } bar.fillAmount = progress; } private async UniTask SetVisibility(bool visible, CancellationToken token) { float targetAlpha = visible ? 1 : 0; groupVisible = visible; while (progressGroup.alpha != targetAlpha && !token.IsCancellationRequested) { progressGroup.alpha = Mathf.MoveTowards(progressGroup.alpha, targetAlpha, Time.deltaTime); await UniTask.Yield(PlayerLoopTiming.Update, token); } } private async UniTask StartInstructionsSequence(CancellationToken token) { if (instructions == null) return; if (instructions.Count == 0) return; int instructionIndex = 0; while (!token.IsCancellationRequested) { await ShowInstruction(instructions[instructionIndex], token); instructionIndex = (instructionIndex + 1) % instructions.Count; } } private async UniTask ShowInstruction(InstructionBlock instruction, CancellationToken token) { HideInstruction(); instructionLabel.text = instruction.text; float t = 0; //Зажигаем while (!token.IsCancellationRequested && t < 1) { t += Time.deltaTime; t = Mathf.Min(t, 1); foreach (var signal in instruction.signals) buttons[signal].alpha = t; LabelCG.alpha = t; await UniTask.Yield(token); } await UniTask.Delay(1000, cancellationToken: token); t = 0; //Тушим while (!token.IsCancellationRequested && t < 1) { t += Time.deltaTime; t = Mathf.Min(t, 1); float oneMinus = 1 - t; foreach (var signal in instruction.signals) buttons[signal].alpha = oneMinus; LabelCG.alpha = oneMinus; await UniTask.Yield(token); } } private void HideInstruction() { UpLeft.alpha = 0; UpRight.alpha = 0; DownLeft.alpha = 0; DownRight.alpha = 0; LabelCG.alpha = 0; } [Serializable] private class InstructionBlock { public List signals; [TextArea] public string text; } }