Untitled
unknown
plain_text
7 months ago
19 kB
5
Indexable
using System;
using System.Collections;
using System.Collections.Generic;
using DG.Tweening;
using OnboardingSystem.Scripts.Interfaces;
using OnboardingSystem.Scripts.Utilities;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace OnboardingSystem.Scripts
{
public class OnboardingUI : MonoBehaviour, IOnboardingUI
{
[SerializeField] private GameObject panel;
[SerializeField] private GameObject messagePanel;
[SerializeField] private TextMeshProUGUI messageLabel;
[SerializeField] private GameObject highlightPrefab;
[SerializeField] private RectTransform highlightParent;
[SerializeField] private RectTransform finger;
[SerializeField] private Image fingerImage;
[SerializeField] private Image highlightBackground;
[SerializeField] private Image messageBackground;
private Sprite _fingerPressedSprite;
private Sprite _fingerReleasedSprite;
private Coroutine _fingerMoveRoutine;
private Sequence _activeFingerSequence;
private readonly List<GameObject> activeHighlights = new();
private void Start()
{
ToggleHighlightBackground(false);
OnboardingEvents.OnShowOnboarding += Show;
OnboardingEvents.OnHideOnboarding += Hide;
}
private void OnDisable()
{
finger?.DOKill();
finger?.transform.DOKill();
messagePanel?.transform.DOKill();
foreach (var highlight in activeHighlights)
{
highlight?.transform.DOKill();
}
OnboardingEvents.OnShowOnboarding -= Show;
OnboardingEvents.OnHideOnboarding -= Hide;
}
public void ShowMessage(string message, float textAnimationSpeed, bool canDismiss, float displayTime, Action onDismiss = null, Vector2? anchor = null, Vector2? offset = null, float scaleAnimationDuration = 0.5f, Ease scaleAnimationEase = Ease.OutBack)
{
messagePanel.transform.DOKill();
messageLabel.DOKill();
RectTransform messageRect = messagePanel.GetComponent<RectTransform>();
if (anchor.HasValue)
{
messageRect.anchorMin = anchor.Value;
messageRect.anchorMax = anchor.Value;
messageRect.pivot = anchor.Value;
}
if (offset.HasValue) messageRect.anchoredPosition = offset.Value;
messageLabel.text = "";
messagePanel.SetActive(true);
messageLabel.DOText(message, textAnimationSpeed).SetEase(Ease.Linear);
Tween tween = messagePanel.transform.DOScale(Vector3.one, scaleAnimationDuration).SetEase(scaleAnimationEase);
if (canDismiss)
{
tween.OnComplete(() =>
{
Button btn = messagePanel.GetComponent<Button>();
if (btn == null) btn = messagePanel.AddComponent<Button>();
btn.onClick.RemoveAllListeners();
btn.onClick.AddListener(() => { HideMessage(() => onDismiss?.Invoke()); });
});
}
else if (messagePanel.TryGetComponent(out Button button)) Destroy(button);
if (displayTime > 0) DOVirtual.DelayedCall(displayTime, () => HideMessage(null));
}
public void SetFontSize(bool useConstantFontSize, float constantFontSize, float minFontSize, float maxFontSize)
{
if (useConstantFontSize) messageLabel.fontSize = constantFontSize;
else
{
messageLabel.enableAutoSizing = true;
messageLabel.fontSizeMin = minFontSize;
messageLabel.fontSizeMax = maxFontSize;
}
}
public void HideMessage(Action onComplete)
{
messagePanel.transform.DOKill();
messageLabel.text = "";
messagePanel.transform.DOScale(Vector3.zero, 0.3f).SetEase(Ease.InBack).OnComplete(() =>
{
messagePanel.SetActive(false);
onComplete?.Invoke();
});
}
public void Highlight(Vector3 position, Vector2 size, bool useWorldPosition = true, Sprite highlightSprite = null)
{
ToggleHighlightBackground(true);
Camera uiCamera = highlightParent.GetComponentInParent<Canvas>().worldCamera;
Vector2 screenPos;
if (useWorldPosition)
{
screenPos = RectTransformUtility.WorldToScreenPoint(uiCamera, position);
}
else
{
screenPos = position;
}
RectTransformUtility.ScreenPointToLocalPointInRectangle(highlightParent, screenPos, uiCamera, out Vector2 localPos);
GameObject newHighlight = Instantiate(highlightPrefab, highlightParent.transform);
if (highlightSprite != null) newHighlight.GetComponent<Image>().sprite = highlightSprite;
newHighlight.transform.SetAsFirstSibling();
RectTransform highlightRect = newHighlight.GetComponent<RectTransform>();
highlightRect.anchoredPosition = localPos;
highlightRect.sizeDelta = size;
activeHighlights.Add(newHighlight);
}
public void HighlightWithId(int id, Vector2 size, bool useWorldPosition = true, Sprite highlightSprite = null)
{
var target = OnboardingUtilities.GetTargetById(id);
if (target == null) return;
Vector3 position;
if (useWorldPosition)
{
position = target.transform.position;
}
else
{
RectTransform rectTransform = target.GetComponent<RectTransform>();
if (rectTransform != null)
{
position = rectTransform.position;
}
else
{
Camera uiCamera = highlightParent.GetComponentInParent<Canvas>().worldCamera;
position = RectTransformUtility.WorldToScreenPoint(uiCamera, target.transform.position);
}
}
Highlight(position, size, useWorldPosition, highlightSprite);
}
public void DragDropFingerAnimation(Vector3 startWorldPos, Vector3 endWorldPos, Vector2 offset, float duration, Ease ease, LoopType loopType, int loopCount, float startScale, float pressScale, float endScale)
{
HideFinger();
Camera uiCamera = GetComponentInParent<Canvas>().worldCamera;
Vector2 startScreenPos = RectTransformUtility.WorldToScreenPoint(uiCamera, startWorldPos);
Vector2 endScreenPos = RectTransformUtility.WorldToScreenPoint(uiCamera, endWorldPos);
RectTransformUtility.ScreenPointToLocalPointInRectangle(transform as RectTransform, startScreenPos, uiCamera, out Vector2 startLocalPos);
RectTransformUtility.ScreenPointToLocalPointInRectangle(transform as RectTransform, endScreenPos, uiCamera, out Vector2 endLocalPos);
finger.gameObject.SetActive(true);
finger.anchoredPosition = startLocalPos + offset;
endLocalPos += offset;
fingerImage.color = new Color(1, 1, 1, 0);
finger.localScale = Vector3.one * startScale;
_activeFingerSequence?.Kill();
_activeFingerSequence = DOTween.Sequence();
_activeFingerSequence.Append(fingerImage.DOFade(1, 0.3f).SetEase(Ease.OutQuad));
_activeFingerSequence.AppendCallback(() => { fingerImage.sprite = _fingerPressedSprite; finger.localScale = Vector3.one * pressScale; });
_activeFingerSequence.Join(finger.DOScale(Vector3.one * pressScale, 0.2f).SetEase(Ease.OutBack));
_activeFingerSequence.Append(finger.DOAnchorPos(endLocalPos, duration).SetEase(Ease.InOutQuad));
_activeFingerSequence.AppendCallback(() => { fingerImage.sprite = _fingerReleasedSprite; finger.localScale = Vector3.one * endScale; });
_activeFingerSequence.Join(finger.DOScale(Vector3.one * endScale, 0.2f).SetEase(Ease.OutBack));
_activeFingerSequence.Append(fingerImage.DOFade(0, 0.3f).SetEase(Ease.InQuad));
_activeFingerSequence.Join(finger.DOScale(Vector3.one * startScale, 0.3f));
if (loopCount > 0) _activeFingerSequence.SetLoops(loopCount, loopType).OnComplete(() => finger.gameObject.SetActive(false));
else _activeFingerSequence.SetLoops(-1, loopType);
_activeFingerSequence.OnKill(() =>
{
fingerImage.color = Color.white;
finger.localScale = Vector3.one;
});
}
public void DragDropFingerAnimationWithIds(int startId, int endId, Vector2 offset, float duration, Ease ease, LoopType loopType, int loopCount, float startScale, float pressScale, float endScale)
{
if (finger != null)
{
finger.DOKill();
finger.transform.DOKill();
}
if (_fingerMoveRoutine != null) StopCoroutine(_fingerMoveRoutine);
_fingerMoveRoutine = StartCoroutine(MoveFingerRoutine(startId, endId, offset, duration, ease, loopType, loopCount, startScale, pressScale, endScale));
}
private IEnumerator MoveFingerRoutine(int startId, int endId, Vector2 offset, float duration, Ease ease, LoopType loopType, int loopCount, float startScale, float pressScale, float endScale)
{
Canvas canvas = GetComponentInParent<Canvas>();
Camera uiCamera = canvas.renderMode == RenderMode.ScreenSpaceOverlay ? null : canvas.worldCamera;
if (finger == null || fingerImage == null) yield break;
finger.gameObject.SetActive(true);
fingerImage.color = new Color(1, 1, 1, 0);
finger.localScale = Vector3.one * startScale;
int currentLoop = 0;
while (loopCount <= 0 || currentLoop < loopCount)
{
var onboardingObjects = FindObjectsOfType<OnboardingObject>();
var startObject = Array.Find(onboardingObjects, obj => obj.id == startId);
var endObject = Array.Find(onboardingObjects, obj => obj.id == endId);
if (startObject == null || endObject == null)
{
Debug.LogError("Onboarding object with id not found");
yield break;
}
Vector2 startScreenPos = RectTransformUtility.WorldToScreenPoint(uiCamera, startObject.transform.position);
Vector2 endScreenPos = RectTransformUtility.WorldToScreenPoint(uiCamera, endObject.transform.position);
RectTransform rt = transform as RectTransform;
if (rt == null || !RectTransformUtility.ScreenPointToLocalPointInRectangle(rt, startScreenPos, uiCamera, out Vector2 startLocalPos) ||
!RectTransformUtility.ScreenPointToLocalPointInRectangle(rt, endScreenPos, uiCamera, out Vector2 endLocalPos))
{
yield return null;
continue;
}
finger.DOKill();
finger.transform.DOKill();
finger.anchoredPosition = startLocalPos + offset;
endLocalPos += offset;
Sequence seq = DOTween.Sequence();
seq.SetTarget(finger);
seq.SetEase(ease);
seq.Append(fingerImage.DOFade(1, 0.3f).SetEase(Ease.OutQuad));
seq.AppendCallback(() => { fingerImage.sprite = _fingerPressedSprite; finger.localScale = Vector3.one * pressScale; });
seq.Join(finger.DOScale(Vector3.one * pressScale, 0.2f).SetEase(Ease.OutBack));
seq.Append(finger.DOAnchorPos(endLocalPos, duration).SetEase(Ease.InOutQuad));
seq.AppendCallback(() => { fingerImage.sprite = _fingerReleasedSprite; finger.localScale = Vector3.one * endScale; });
seq.Join(finger.DOScale(Vector3.one * endScale, 0.2f).SetEase(Ease.OutBack));
seq.Append(fingerImage.DOFade(0, 0.3f).SetEase(Ease.InQuad));
seq.Join(finger.DOScale(Vector3.one * startScale, 0.3f));
seq.AppendInterval(0.3f);
yield return seq.WaitForCompletion();
currentLoop++;
}
finger.gameObject.SetActive(false);
}
public void PointFingerAt(Vector3 worldPosition, Vector2 offset, float duration, Ease ease, LoopType loopType, int loopCount, float startScale, float pressScale, float endScale)
{
HideFinger();
Camera uiCamera = GetComponentInParent<Canvas>().worldCamera;
Vector2 screenPos = RectTransformUtility.WorldToScreenPoint(uiCamera, worldPosition);
RectTransformUtility.ScreenPointToLocalPointInRectangle(transform as RectTransform, screenPos, uiCamera, out Vector2 localPos);
finger.gameObject.SetActive(true);
finger.anchoredPosition = localPos + offset;
finger.localScale = Vector3.one * startScale;
_activeFingerSequence?.Kill();
_activeFingerSequence = DOTween.Sequence();
_activeFingerSequence.SetEase(ease);
_activeFingerSequence.AppendCallback(() => { fingerImage.sprite = _fingerPressedSprite; });
_activeFingerSequence.Append(finger.DOScale(Vector3.one * pressScale, 0.2f).SetEase(Ease.OutBack));
_activeFingerSequence.AppendInterval(duration);
_activeFingerSequence.AppendCallback(() => { fingerImage.sprite = _fingerReleasedSprite; });
_activeFingerSequence.Append(finger.DOScale(Vector3.one * endScale, 0.3f).SetEase(Ease.OutBack));
_activeFingerSequence.AppendInterval(0.3f);
if (loopCount > 0) _activeFingerSequence.SetLoops(loopCount, loopType).OnComplete(() => finger.gameObject.SetActive(false));
else _activeFingerSequence.SetLoops(-1, loopType);
}
public void PointFingerAtWithId(int id, Vector2 offset, float duration, Ease ease, LoopType loopType, int loopCount, float startScale, float pressScale, float endScale)
{
if (finger != null)
{
finger.DOKill();
finger.transform.DOKill();
}
if (_fingerMoveRoutine != null) StopCoroutine(_fingerMoveRoutine);
_fingerMoveRoutine = StartCoroutine(PointFingerAtWithIdRoutine(id, offset, duration, ease, loopType, loopCount, startScale, pressScale, endScale));
}
private IEnumerator PointFingerAtWithIdRoutine(int endId, Vector2 offset, float duration, Ease ease, LoopType loopType, int loopCount, float startScale, float pressScale, float endScale)
{
Canvas canvas = GetComponentInParent<Canvas>();
Camera uiCamera = canvas.renderMode == RenderMode.ScreenSpaceOverlay ? null : canvas.worldCamera;
if (finger == null || fingerImage == null) yield break;
int currentLoop = 0;
while (loopCount <= 0 || currentLoop < loopCount)
{
var onboardingObjects = FindObjectsOfType<OnboardingObject>();
var endObject = Array.Find(onboardingObjects, obj => obj.id == endId);
if (endObject == null)
{
Debug.LogError("Onboarding object with id not found");
yield break;
}
Vector2 screenPos = RectTransformUtility.WorldToScreenPoint(uiCamera, endObject.transform.position);
RectTransformUtility.ScreenPointToLocalPointInRectangle(transform as RectTransform, screenPos, uiCamera, out Vector2 targetLocalPos);
finger.anchoredPosition = targetLocalPos + offset;
finger.gameObject.SetActive(true);
finger.localScale = Vector3.one * startScale;
Sequence seq = DOTween.Sequence();
seq.SetEase(ease);
seq.AppendCallback(() => { fingerImage.sprite = _fingerPressedSprite; });
seq.Append(finger.DOScale(Vector3.one * pressScale, 0.2f).SetEase(Ease.OutBack));
seq.AppendInterval(duration);
seq.AppendCallback(() => { fingerImage.sprite = _fingerReleasedSprite; });
seq.Append(finger.DOScale(Vector3.one * endScale, 0.3f).SetEase(Ease.OutBack));
seq.AppendInterval(0.3f);
yield return seq.WaitForCompletion();
currentLoop++;
}
finger.gameObject.SetActive(false);
}
public void HideFinger()
{
if (_fingerMoveRoutine != null) StopCoroutine(_fingerMoveRoutine);
_fingerMoveRoutine = null;
finger.DOKill();
finger.transform.DOKill();
if (_activeFingerSequence != null && _activeFingerSequence.IsActive()) _activeFingerSequence.Kill();
finger.gameObject.SetActive(false);
finger.anchoredPosition = Vector2.zero;
fingerImage.color = Color.white;
finger.localScale = Vector3.one;
}
public void ClearHighlights(bool hideBackground)
{
foreach (var highlight in activeHighlights) Destroy(highlight);
activeHighlights.Clear();
ToggleHighlightBackground(!hideBackground);
}
public void Hide() => panel.SetActive(false);
public void Show() => panel.SetActive(true);
public void SetFingerSprites(Sprite released, Sprite pressed)
{
_fingerReleasedSprite = released;
_fingerPressedSprite = pressed;
}
public void SetMessageBackground(Sprite sprite) => messageBackground.sprite = sprite;
public void Deactivate()
{
Hide();
HideMessage(null);
HideFinger();
ClearHighlights(true);
}
private void ToggleHighlightBackground(bool show) => highlightBackground.gameObject.SetActive(show);
}
}
Editor is loading...
Leave a Comment