180 lines
5.4 KiB
C#
180 lines
5.4 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using DG.Tweening;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using VMdemo.Simulation;
|
|
|
|
namespace VMdemo.UI
|
|
{
|
|
public class StepFlowAnimator : MonoBehaviour
|
|
{
|
|
[Serializable]
|
|
public class StepNodeView
|
|
{
|
|
public TranslationStep step;
|
|
public RectTransform target;
|
|
public CanvasGroup canvasGroup;
|
|
public Image background;
|
|
}
|
|
|
|
[Header("Step Nodes")] [SerializeField]
|
|
private List<StepNodeView> stepNodes = new List<StepNodeView>();
|
|
|
|
[Header("Colors")] [SerializeField] private Color idleColor = new Color(0.18f, 0.22f, 0.28f, 1f);
|
|
[SerializeField] private Color activeColor = new Color(0.19f, 0.62f, 0.98f, 1f);
|
|
[SerializeField] private Color faultColor = new Color(0.97f, 0.31f, 0.27f, 1f);
|
|
|
|
[Header("Animation")] [SerializeField] private float highlightDuration = 0.2f;
|
|
[SerializeField] private float normalScale = 1f;
|
|
[SerializeField] private float activeScale = 1.08f;
|
|
[SerializeField] private float pulseScale = 1.04f;
|
|
[SerializeField] private RectTransform accessPulseTarget;
|
|
|
|
private readonly Dictionary<TranslationStep, StepNodeView> _nodeMap =
|
|
new Dictionary<TranslationStep, StepNodeView>();
|
|
|
|
private TranslationStep? _lastStep;
|
|
|
|
private void Awake()
|
|
{
|
|
BuildNodeMap();
|
|
ResetVisual();
|
|
}
|
|
|
|
public void ResetVisual()
|
|
{
|
|
DOTween.Kill(this);
|
|
_lastStep = null;
|
|
|
|
foreach (var node in stepNodes)
|
|
{
|
|
if (node == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (node.target != null)
|
|
{
|
|
node.target.localScale = Vector3.one * normalScale;
|
|
}
|
|
|
|
if (node.canvasGroup != null)
|
|
{
|
|
node.canvasGroup.alpha = 0.72f;
|
|
}
|
|
|
|
if (node.background != null)
|
|
{
|
|
node.background.color = idleColor;
|
|
}
|
|
}
|
|
|
|
if (accessPulseTarget != null)
|
|
{
|
|
accessPulseTarget.localScale = Vector3.one;
|
|
}
|
|
}
|
|
|
|
public void AnimateStep(TranslationStep currentStep, bool isPageFault, bool accessCompleted)
|
|
{
|
|
BuildNodeMap();
|
|
if (_lastStep.HasValue && _nodeMap.TryGetValue(_lastStep.Value, out var lastNode))
|
|
{
|
|
AnimateToIdle(lastNode);
|
|
}
|
|
|
|
if (_nodeMap.TryGetValue(currentStep, out var currentNode))
|
|
{
|
|
AnimateToActive(currentNode, isPageFault && currentStep == TranslationStep.HandlePageFault);
|
|
}
|
|
|
|
if (accessCompleted)
|
|
{
|
|
AnimateAccessCompletedPulse();
|
|
}
|
|
|
|
_lastStep = currentStep;
|
|
}
|
|
|
|
private void BuildNodeMap()
|
|
{
|
|
_nodeMap.Clear();
|
|
foreach (var node in stepNodes)
|
|
{
|
|
if (node == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!_nodeMap.ContainsKey(node.step))
|
|
{
|
|
_nodeMap.Add(node.step, node);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void AnimateToIdle(StepNodeView node)
|
|
{
|
|
if (node.target != null)
|
|
{
|
|
node.target.DOKill();
|
|
node.target.DOScale(normalScale, highlightDuration).SetEase(Ease.OutQuad).SetTarget(this);
|
|
}
|
|
|
|
if (node.canvasGroup != null)
|
|
{
|
|
node.canvasGroup.DOKill();
|
|
node.canvasGroup.DOFade(0.72f, highlightDuration).SetEase(Ease.OutQuad).SetTarget(this);
|
|
}
|
|
|
|
if (node.background != null)
|
|
{
|
|
node.background.DOKill();
|
|
node.background.DOColor(idleColor, highlightDuration).SetEase(Ease.OutQuad).SetTarget(this);
|
|
}
|
|
}
|
|
|
|
private void AnimateToActive(StepNodeView node, bool emphasizeFault)
|
|
{
|
|
if (node.target != null)
|
|
{
|
|
node.target.DOKill();
|
|
node.target.DOScale(activeScale, highlightDuration).SetEase(Ease.OutBack).SetTarget(this);
|
|
}
|
|
|
|
if (node.canvasGroup != null)
|
|
{
|
|
node.canvasGroup.DOKill();
|
|
node.canvasGroup.DOFade(1f, highlightDuration).SetEase(Ease.OutQuad).SetTarget(this);
|
|
}
|
|
|
|
if (node.background != null)
|
|
{
|
|
node.background.DOKill();
|
|
var targetColor = emphasizeFault ? faultColor : activeColor;
|
|
node.background.DOColor(targetColor, highlightDuration).SetEase(Ease.OutQuad).SetTarget(this);
|
|
}
|
|
|
|
if (emphasizeFault && node.target != null)
|
|
{
|
|
node.target.DOPunchScale(new Vector3(0.07f, 0.07f, 0f), 0.28f, 6, 0.75f).SetTarget(this);
|
|
}
|
|
}
|
|
|
|
private void AnimateAccessCompletedPulse()
|
|
{
|
|
if (accessPulseTarget == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
accessPulseTarget.DOKill();
|
|
accessPulseTarget
|
|
.DOScale(pulseScale, 0.12f)
|
|
.SetEase(Ease.OutQuad)
|
|
.SetLoops(2, LoopType.Yoyo)
|
|
.SetTarget(this);
|
|
}
|
|
}
|
|
} |