Keep local version of files

This commit is contained in:
2026-10-08 00:49:10 +05:30
parent 7fa0621ff8
commit 053665c690
7343 changed files with 5470578 additions and 5470528 deletions
+31 -31
View File
@@ -1,31 +1,31 @@
using UnityEngine;
public class CanvasGroupUtils : MonoBehaviour
{
public UnityEngine.UI.Graphic[] graphics;
public bool useOverrideColor = false;
public Color overrideColor = Color.white;
void OnValidate()
{
RefreshColor();
}
void Update()
{
RefreshColor();
}
void RefreshColor(){
if(useOverrideColor)
{
foreach(var graphic in graphics)
{
graphic.color = new Color(overrideColor.r, overrideColor.g, overrideColor.b, overrideColor.a);
}
}
}
}
using UnityEngine;
public class CanvasGroupUtils : MonoBehaviour
{
public UnityEngine.UI.Graphic[] graphics;
public bool useOverrideColor = false;
public Color overrideColor = Color.white;
void OnValidate()
{
RefreshColor();
}
void Update()
{
RefreshColor();
}
void RefreshColor(){
if(useOverrideColor)
{
foreach(var graphic in graphics)
{
graphic.color = new Color(overrideColor.r, overrideColor.g, overrideColor.b, overrideColor.a);
}
}
}
}
@@ -1,2 +1,2 @@
fileFormatVersion: 2
fileFormatVersion: 2
guid: c6e9b80351cd150478194c9959e87012
+456 -456
View File
@@ -1,456 +1,456 @@
using System;
using System.Collections.Generic;
using DG.Tweening;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;
[RequireComponent(typeof(EventTrigger))]
public class CardCarousel : MonoBehaviour
{
[SerializeField] RectTransform[] items;
[SerializeField] float spacing = 40f;
[SerializeField] float swipeThreshold = 60f;
[SerializeField] float snapDuration = 0.25f;
[SerializeField] Ease snapEase = Ease.OutCubic;
[Tooltip("Horizontal half-width of the center tap zone, in local units of this RectTransform.")]
[SerializeField] float centerTapHalfWidth = 260f;
[SerializeField] bool looped = true;
[SerializeField] int selectedIndex;
[Header("Focus Animation")]
[SerializeField] float activeScale = 1.05f;
[SerializeField] float inactiveScale = 0.88f;
[SerializeField] float activePullDown = 35f;
public UnityEvent<int> onSelected = new UnityEvent<int>();
EventTrigger eventTrigger;
RectTransform rectTransform;
RectTransform dragSpace;
RectTransform duplicateClone;
readonly Dictionary<RectTransform, Vector3> baseScales = new();
float slotStep;
float focusX;
float focusY;
float focusPosition;
float dragStartPosition;
float pointerDownLocalX;
bool isDragging;
bool isAnimating;
Tween snapTween;
public int SelectedIndex => selectedIndex;
void Awake()
{
rectTransform = (RectTransform)transform;
eventTrigger = GetComponent<EventTrigger>();
RegisterTrigger(EventTriggerType.PointerDown, OnPointerDown);
RegisterTrigger(EventTriggerType.Drag, OnDrag);
RegisterTrigger(EventTriggerType.PointerUp, OnPointerUp);
}
void Start()
{
if (items == null || items.Length < 2)
{
Debug.LogWarning($"{nameof(CardCarousel)} on {name} needs at least 2 items.", this);
return;
}
selectedIndex = Mathf.Clamp(selectedIndex, 0, items.Length - 1);
dragSpace = items[0].parent as RectTransform;
slotStep = items[0].rect.width + spacing;
focusX = items[0].anchoredPosition.x;
focusY = items[0].anchoredPosition.y;
duplicateClone = CreateClone(items[0], "_carouselClone_Dup");
foreach (var item in items)
CacheBaseScale(item);
focusPosition = selectedIndex;
ApplyLayout();
}
void OnDestroy()
{
snapTween?.Kill();
}
void RegisterTrigger(EventTriggerType type, Action<BaseEventData> handler)
{
var entry = new EventTrigger.Entry { eventID = type };
entry.callback.AddListener(handler.Invoke);
eventTrigger.triggers.Add(entry);
}
RectTransform CreateClone(RectTransform source, string suffix)
{
var clone = Instantiate(source, source.parent);
clone.name = source.name + suffix;
DisableInteractions(clone);
return clone;
}
static void DisableInteractions(RectTransform target)
{
foreach (var graphic in target.GetComponentsInChildren<Graphic>(true))
graphic.raycastTarget = false;
foreach (var button in target.GetComponentsInChildren<Button>(true))
button.interactable = false;
}
void OnPointerDown(BaseEventData eventData)
{
if (!TryGetPointer(eventData, out var pointer) || isAnimating || items == null || items.Length < 2)
return;
snapTween?.Kill();
isAnimating = false;
isDragging = false;
dragStartPosition = focusPosition;
pointerDownLocalX = GetLocalDragX(pointer);
}
void OnDrag(BaseEventData eventData)
{
if (!TryGetPointer(eventData, out var pointer) || items == null || items.Length < 2)
return;
isDragging = true;
float delta = GetLocalDragX(pointer) - pointerDownLocalX;
focusPosition = dragStartPosition - delta / slotStep;
if (!looped)
focusPosition = Mathf.Clamp(focusPosition, 0f, items.Length - 1);
ApplyLayout();
}
void OnPointerUp(BaseEventData eventData)
{
if (!TryGetPointer(eventData, out var pointer) || isAnimating || items == null || items.Length < 2)
return;
float pointerDelta = GetLocalDragX(pointer) - pointerDownLocalX;
float dragDelta = focusPosition - dragStartPosition;
bool passedSwipeThreshold = Mathf.Abs(pointerDelta) >= swipeThreshold
|| Mathf.Abs(dragDelta * slotStep) >= swipeThreshold;
if (!passedSwipeThreshold)
{
if (TryGetTapZone(pointer, out int tapDirection))
{
if (tapDirection == 0)
SelectCurrent();
else if (CanMoveBy(tapDirection))
AnimateToDirection(tapDirection);
else
SnapTo(selectedIndex, null);
}
else
SnapTo(selectedIndex, null);
isDragging = false;
return;
}
isDragging = false;
int direction = dragDelta > 0f ? 1 : -1;
if (Mathf.Abs(focusPosition - selectedIndex) > 0.5f)
{
int nearest = Mathf.RoundToInt(focusPosition);
if (!looped)
nearest = Mathf.Clamp(nearest, 0, items.Length - 1);
if (nearest != selectedIndex && CanMoveBy(nearest > selectedIndex ? 1 : -1))
{
AnimateTo(nearest);
return;
}
}
if (!CanMoveBy(direction))
{
SnapTo(selectedIndex, null);
return;
}
AnimateToDirection(direction);
}
float GetLocalDragX(PointerEventData pointer)
{
if (dragSpace == null)
return pointer.position.x;
RectTransformUtility.ScreenPointToLocalPointInRectangle(
dragSpace, pointer.position, pointer.pressEventCamera, out var local);
return local.x;
}
bool TryGetTapZone(PointerEventData pointer, out int direction)
{
direction = 0;
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(
rectTransform, pointer.position, pointer.pressEventCamera, out var local))
return false;
if (Mathf.Abs(local.x) <= centerTapHalfWidth)
return true;
direction = local.x < 0f ? -1 : 1;
return true;
}
void SelectCurrent()
{
if (Mathf.Approximately(focusPosition, selectedIndex))
onSelected.Invoke(selectedIndex);
else
SnapTo(selectedIndex, () => onSelected.Invoke(selectedIndex));
}
void AnimateToDirection(int direction)
{
int newIndex = GetAdjacentIndex(direction, items.Length);
if (newIndex < 0)
return;
AnimateTo(newIndex);
}
void AnimateTo(int newIndex)
{
isAnimating = true;
snapTween?.Kill();
snapTween = DOTween.To(
() => focusPosition,
value =>
{
focusPosition = value;
ApplyLayout();
},
newIndex,
snapDuration)
.SetEase(snapEase)
.OnComplete(() => CompleteSlide(newIndex));
}
void CompleteSlide(int newIndex)
{
selectedIndex = newIndex;
focusPosition = newIndex;
isAnimating = false;
ApplyLayout();
}
void SnapTo(float targetPosition, Action onComplete)
{
isAnimating = true;
snapTween?.Kill();
snapTween = DOTween.To(
() => focusPosition,
value =>
{
focusPosition = value;
ApplyLayout();
},
targetPosition,
snapDuration)
.SetEase(snapEase)
.OnComplete(() =>
{
isAnimating = false;
onComplete?.Invoke();
});
}
float GetItemOffset(int itemIndex)
{
return (itemIndex - focusPosition) * slotStep;
}
bool IsItemVisible(float offset)
{
return Mathf.Abs(offset) <= slotStep * 1.5f;
}
void ApplyLayout()
{
int count = items.Length;
bool useDuplicate = looped && count == 2;
for (int i = 0; i < count; i++)
{
float offset = GetItemOffset(i);
if (IsItemVisible(offset))
{
SetItemTransform(items[i], offset);
items[i].gameObject.SetActive(true);
}
else
items[i].gameObject.SetActive(false);
}
if (useDuplicate && Mathf.Approximately(focusPosition, Mathf.Round(focusPosition)))
{
int restIndex = Mathf.RoundToInt(focusPosition);
int otherIndex = 1 - restIndex;
float otherOffset = GetItemOffset(otherIndex);
float duplicateOffset = -otherOffset;
if (IsItemVisible(duplicateOffset))
{
SyncDuplicateClone(items[otherIndex]);
SetItemTransform(duplicateClone, duplicateOffset);
duplicateClone.gameObject.SetActive(true);
}
else if (duplicateClone != null)
duplicateClone.gameObject.SetActive(false);
}
else if (duplicateClone != null)
{
duplicateClone.gameObject.SetActive(false);
}
int topIndex = 0;
float bestFocus = float.MaxValue;
for (int i = 0; i < count; i++)
{
if (!items[i].gameObject.activeSelf)
continue;
float focus = GetFocusT(GetItemOffset(i));
if (focus < bestFocus)
{
bestFocus = focus;
topIndex = i;
}
}
items[topIndex].SetAsLastSibling();
}
void SyncDuplicateClone(RectTransform source)
{
string expectedName = source.name + "_carouselClone_Dup";
if (duplicateClone == null || duplicateClone.name != expectedName)
{
var parent = source.parent;
int sibling = duplicateClone != null ? duplicateClone.GetSiblingIndex() : source.GetSiblingIndex();
if (duplicateClone != null)
{
baseScales.Remove(duplicateClone);
Destroy(duplicateClone.gameObject);
}
duplicateClone = CreateClone(source, "_carouselClone_Dup");
duplicateClone.SetParent(parent, false);
duplicateClone.SetSiblingIndex(sibling);
}
CacheBaseScale(duplicateClone, source);
}
void CacheBaseScale(RectTransform item, RectTransform source = null)
{
if (baseScales.ContainsKey(item))
return;
baseScales[item] = source != null ? source.localScale : item.localScale;
}
void SetItemTransform(RectTransform item, float xOffset)
{
CacheBaseScale(item);
float focusT = GetFocusT(xOffset);
float scale = Mathf.Lerp(activeScale, inactiveScale, focusT);
item.localScale = baseScales[item] * scale;
var pos = item.anchoredPosition;
pos.x = focusX + xOffset;
pos.y = focusY - Mathf.Lerp(activePullDown, 0f, focusT);
item.anchoredPosition = pos;
}
float GetFocusT(float xOffset)
{
if (slotStep <= 0f)
return 0f;
float t = Mathf.Clamp01(Mathf.Abs(xOffset) / slotStep);
return t * t * (3f - 2f * t);
}
static int WrapIndex(int index, int count)
{
if (count <= 0)
return 0;
return ((index % count) + count) % count;
}
int GetAdjacentIndex(int direction, int count)
{
int index = selectedIndex + direction;
if (looped)
return WrapIndex(index, count);
return index >= 0 && index < count ? index : -1;
}
bool CanMoveBy(int direction)
{
if (items == null || items.Length == 0)
return false;
return GetAdjacentIndex(direction, items.Length) >= 0;
}
int NormalizeIndex(int index)
{
if (items == null || items.Length == 0)
return 0;
return looped ? WrapIndex(index, items.Length) : Mathf.Clamp(index, 0, items.Length - 1);
}
static bool TryGetPointer(BaseEventData eventData, out PointerEventData pointer)
{
pointer = eventData as PointerEventData;
return pointer != null;
}
public void SetSelectedIndex(int index, bool animate = false)
{
if (items == null || items.Length == 0)
return;
int target = NormalizeIndex(index);
if (target == selectedIndex)
return;
if (!animate || !isActiveAndEnabled)
{
snapTween?.Kill();
isAnimating = false;
selectedIndex = target;
focusPosition = target;
ApplyLayout();
return;
}
int direction = target > selectedIndex ? 1 : -1;
if (!CanMoveBy(direction) || Mathf.Abs(target - selectedIndex) != 1)
{
selectedIndex = target;
focusPosition = target;
ApplyLayout();
return;
}
AnimateToDirection(direction);
}
}
using System;
using System.Collections.Generic;
using DG.Tweening;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;
[RequireComponent(typeof(EventTrigger))]
public class CardCarousel : MonoBehaviour
{
[SerializeField] RectTransform[] items;
[SerializeField] float spacing = 40f;
[SerializeField] float swipeThreshold = 60f;
[SerializeField] float snapDuration = 0.25f;
[SerializeField] Ease snapEase = Ease.OutCubic;
[Tooltip("Horizontal half-width of the center tap zone, in local units of this RectTransform.")]
[SerializeField] float centerTapHalfWidth = 260f;
[SerializeField] bool looped = true;
[SerializeField] int selectedIndex;
[Header("Focus Animation")]
[SerializeField] float activeScale = 1.05f;
[SerializeField] float inactiveScale = 0.88f;
[SerializeField] float activePullDown = 35f;
public UnityEvent<int> onSelected = new UnityEvent<int>();
EventTrigger eventTrigger;
RectTransform rectTransform;
RectTransform dragSpace;
RectTransform duplicateClone;
readonly Dictionary<RectTransform, Vector3> baseScales = new();
float slotStep;
float focusX;
float focusY;
float focusPosition;
float dragStartPosition;
float pointerDownLocalX;
bool isDragging;
bool isAnimating;
Tween snapTween;
public int SelectedIndex => selectedIndex;
void Awake()
{
rectTransform = (RectTransform)transform;
eventTrigger = GetComponent<EventTrigger>();
RegisterTrigger(EventTriggerType.PointerDown, OnPointerDown);
RegisterTrigger(EventTriggerType.Drag, OnDrag);
RegisterTrigger(EventTriggerType.PointerUp, OnPointerUp);
}
void Start()
{
if (items == null || items.Length < 2)
{
Debug.LogWarning($"{nameof(CardCarousel)} on {name} needs at least 2 items.", this);
return;
}
selectedIndex = Mathf.Clamp(selectedIndex, 0, items.Length - 1);
dragSpace = items[0].parent as RectTransform;
slotStep = items[0].rect.width + spacing;
focusX = items[0].anchoredPosition.x;
focusY = items[0].anchoredPosition.y;
duplicateClone = CreateClone(items[0], "_carouselClone_Dup");
foreach (var item in items)
CacheBaseScale(item);
focusPosition = selectedIndex;
ApplyLayout();
}
void OnDestroy()
{
snapTween?.Kill();
}
void RegisterTrigger(EventTriggerType type, Action<BaseEventData> handler)
{
var entry = new EventTrigger.Entry { eventID = type };
entry.callback.AddListener(handler.Invoke);
eventTrigger.triggers.Add(entry);
}
RectTransform CreateClone(RectTransform source, string suffix)
{
var clone = Instantiate(source, source.parent);
clone.name = source.name + suffix;
DisableInteractions(clone);
return clone;
}
static void DisableInteractions(RectTransform target)
{
foreach (var graphic in target.GetComponentsInChildren<Graphic>(true))
graphic.raycastTarget = false;
foreach (var button in target.GetComponentsInChildren<Button>(true))
button.interactable = false;
}
void OnPointerDown(BaseEventData eventData)
{
if (!TryGetPointer(eventData, out var pointer) || isAnimating || items == null || items.Length < 2)
return;
snapTween?.Kill();
isAnimating = false;
isDragging = false;
dragStartPosition = focusPosition;
pointerDownLocalX = GetLocalDragX(pointer);
}
void OnDrag(BaseEventData eventData)
{
if (!TryGetPointer(eventData, out var pointer) || items == null || items.Length < 2)
return;
isDragging = true;
float delta = GetLocalDragX(pointer) - pointerDownLocalX;
focusPosition = dragStartPosition - delta / slotStep;
if (!looped)
focusPosition = Mathf.Clamp(focusPosition, 0f, items.Length - 1);
ApplyLayout();
}
void OnPointerUp(BaseEventData eventData)
{
if (!TryGetPointer(eventData, out var pointer) || isAnimating || items == null || items.Length < 2)
return;
float pointerDelta = GetLocalDragX(pointer) - pointerDownLocalX;
float dragDelta = focusPosition - dragStartPosition;
bool passedSwipeThreshold = Mathf.Abs(pointerDelta) >= swipeThreshold
|| Mathf.Abs(dragDelta * slotStep) >= swipeThreshold;
if (!passedSwipeThreshold)
{
if (TryGetTapZone(pointer, out int tapDirection))
{
if (tapDirection == 0)
SelectCurrent();
else if (CanMoveBy(tapDirection))
AnimateToDirection(tapDirection);
else
SnapTo(selectedIndex, null);
}
else
SnapTo(selectedIndex, null);
isDragging = false;
return;
}
isDragging = false;
int direction = dragDelta > 0f ? 1 : -1;
if (Mathf.Abs(focusPosition - selectedIndex) > 0.5f)
{
int nearest = Mathf.RoundToInt(focusPosition);
if (!looped)
nearest = Mathf.Clamp(nearest, 0, items.Length - 1);
if (nearest != selectedIndex && CanMoveBy(nearest > selectedIndex ? 1 : -1))
{
AnimateTo(nearest);
return;
}
}
if (!CanMoveBy(direction))
{
SnapTo(selectedIndex, null);
return;
}
AnimateToDirection(direction);
}
float GetLocalDragX(PointerEventData pointer)
{
if (dragSpace == null)
return pointer.position.x;
RectTransformUtility.ScreenPointToLocalPointInRectangle(
dragSpace, pointer.position, pointer.pressEventCamera, out var local);
return local.x;
}
bool TryGetTapZone(PointerEventData pointer, out int direction)
{
direction = 0;
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(
rectTransform, pointer.position, pointer.pressEventCamera, out var local))
return false;
if (Mathf.Abs(local.x) <= centerTapHalfWidth)
return true;
direction = local.x < 0f ? -1 : 1;
return true;
}
void SelectCurrent()
{
if (Mathf.Approximately(focusPosition, selectedIndex))
onSelected.Invoke(selectedIndex);
else
SnapTo(selectedIndex, () => onSelected.Invoke(selectedIndex));
}
void AnimateToDirection(int direction)
{
int newIndex = GetAdjacentIndex(direction, items.Length);
if (newIndex < 0)
return;
AnimateTo(newIndex);
}
void AnimateTo(int newIndex)
{
isAnimating = true;
snapTween?.Kill();
snapTween = DOTween.To(
() => focusPosition,
value =>
{
focusPosition = value;
ApplyLayout();
},
newIndex,
snapDuration)
.SetEase(snapEase)
.OnComplete(() => CompleteSlide(newIndex));
}
void CompleteSlide(int newIndex)
{
selectedIndex = newIndex;
focusPosition = newIndex;
isAnimating = false;
ApplyLayout();
}
void SnapTo(float targetPosition, Action onComplete)
{
isAnimating = true;
snapTween?.Kill();
snapTween = DOTween.To(
() => focusPosition,
value =>
{
focusPosition = value;
ApplyLayout();
},
targetPosition,
snapDuration)
.SetEase(snapEase)
.OnComplete(() =>
{
isAnimating = false;
onComplete?.Invoke();
});
}
float GetItemOffset(int itemIndex)
{
return (itemIndex - focusPosition) * slotStep;
}
bool IsItemVisible(float offset)
{
return Mathf.Abs(offset) <= slotStep * 1.5f;
}
void ApplyLayout()
{
int count = items.Length;
bool useDuplicate = looped && count == 2;
for (int i = 0; i < count; i++)
{
float offset = GetItemOffset(i);
if (IsItemVisible(offset))
{
SetItemTransform(items[i], offset);
items[i].gameObject.SetActive(true);
}
else
items[i].gameObject.SetActive(false);
}
if (useDuplicate && Mathf.Approximately(focusPosition, Mathf.Round(focusPosition)))
{
int restIndex = Mathf.RoundToInt(focusPosition);
int otherIndex = 1 - restIndex;
float otherOffset = GetItemOffset(otherIndex);
float duplicateOffset = -otherOffset;
if (IsItemVisible(duplicateOffset))
{
SyncDuplicateClone(items[otherIndex]);
SetItemTransform(duplicateClone, duplicateOffset);
duplicateClone.gameObject.SetActive(true);
}
else if (duplicateClone != null)
duplicateClone.gameObject.SetActive(false);
}
else if (duplicateClone != null)
{
duplicateClone.gameObject.SetActive(false);
}
int topIndex = 0;
float bestFocus = float.MaxValue;
for (int i = 0; i < count; i++)
{
if (!items[i].gameObject.activeSelf)
continue;
float focus = GetFocusT(GetItemOffset(i));
if (focus < bestFocus)
{
bestFocus = focus;
topIndex = i;
}
}
items[topIndex].SetAsLastSibling();
}
void SyncDuplicateClone(RectTransform source)
{
string expectedName = source.name + "_carouselClone_Dup";
if (duplicateClone == null || duplicateClone.name != expectedName)
{
var parent = source.parent;
int sibling = duplicateClone != null ? duplicateClone.GetSiblingIndex() : source.GetSiblingIndex();
if (duplicateClone != null)
{
baseScales.Remove(duplicateClone);
Destroy(duplicateClone.gameObject);
}
duplicateClone = CreateClone(source, "_carouselClone_Dup");
duplicateClone.SetParent(parent, false);
duplicateClone.SetSiblingIndex(sibling);
}
CacheBaseScale(duplicateClone, source);
}
void CacheBaseScale(RectTransform item, RectTransform source = null)
{
if (baseScales.ContainsKey(item))
return;
baseScales[item] = source != null ? source.localScale : item.localScale;
}
void SetItemTransform(RectTransform item, float xOffset)
{
CacheBaseScale(item);
float focusT = GetFocusT(xOffset);
float scale = Mathf.Lerp(activeScale, inactiveScale, focusT);
item.localScale = baseScales[item] * scale;
var pos = item.anchoredPosition;
pos.x = focusX + xOffset;
pos.y = focusY - Mathf.Lerp(activePullDown, 0f, focusT);
item.anchoredPosition = pos;
}
float GetFocusT(float xOffset)
{
if (slotStep <= 0f)
return 0f;
float t = Mathf.Clamp01(Mathf.Abs(xOffset) / slotStep);
return t * t * (3f - 2f * t);
}
static int WrapIndex(int index, int count)
{
if (count <= 0)
return 0;
return ((index % count) + count) % count;
}
int GetAdjacentIndex(int direction, int count)
{
int index = selectedIndex + direction;
if (looped)
return WrapIndex(index, count);
return index >= 0 && index < count ? index : -1;
}
bool CanMoveBy(int direction)
{
if (items == null || items.Length == 0)
return false;
return GetAdjacentIndex(direction, items.Length) >= 0;
}
int NormalizeIndex(int index)
{
if (items == null || items.Length == 0)
return 0;
return looped ? WrapIndex(index, items.Length) : Mathf.Clamp(index, 0, items.Length - 1);
}
static bool TryGetPointer(BaseEventData eventData, out PointerEventData pointer)
{
pointer = eventData as PointerEventData;
return pointer != null;
}
public void SetSelectedIndex(int index, bool animate = false)
{
if (items == null || items.Length == 0)
return;
int target = NormalizeIndex(index);
if (target == selectedIndex)
return;
if (!animate || !isActiveAndEnabled)
{
snapTween?.Kill();
isAnimating = false;
selectedIndex = target;
focusPosition = target;
ApplyLayout();
return;
}
int direction = target > selectedIndex ? 1 : -1;
if (!CanMoveBy(direction) || Mathf.Abs(target - selectedIndex) != 1)
{
selectedIndex = target;
focusPosition = target;
ApplyLayout();
return;
}
AnimateToDirection(direction);
}
}
+1 -1
View File
@@ -1,2 +1,2 @@
fileFormatVersion: 2
fileFormatVersion: 2
guid: a4951ec6b41c5d14cb8f5a8803dfa0c2
+20 -20
View File
@@ -1,20 +1,20 @@
using TMPro;
using UnityEngine;
[RequireComponent(typeof(TMP_Text))]
public class CopyTextTMP : MonoBehaviour
{
public TMP_Text origin;
TMP_Text _text;
void Awake()
{
_text = GetComponent<TMP_Text>();
}
void Update()
{
_text.text = origin.text;
}
}
using TMPro;
using UnityEngine;
[RequireComponent(typeof(TMP_Text))]
public class CopyTextTMP : MonoBehaviour
{
public TMP_Text origin;
TMP_Text _text;
void Awake()
{
_text = GetComponent<TMP_Text>();
}
void Update()
{
_text.text = origin.text;
}
}
+1 -1
View File
@@ -1,2 +1,2 @@
fileFormatVersion: 2
fileFormatVersion: 2
guid: 981262cae0f1178448cf21d0273828dc
+105 -105
View File
@@ -1,105 +1,105 @@
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;
/// <summary>
/// Inverted stencil mask (see materialForRendering). Raycast options live on
/// <see cref="CutoutMaskUISettings"/> on the same GameObject (Unity's Image
/// inspector does not show fields on Image subclasses).
///
/// Parent <see cref="Mask"/> also implements <see cref="ICanvasRaycastFilter"/> and only
/// allows points inside its RectTransform. A fullscreen child under a small mask would
/// otherwise fail the raycast outside that rect (dimmed area lets clicks through) while
/// still blocking inside the mask bounds. We skip only Mask/RectMask2D in the raycast
/// walk (<see cref="Graphic.Raycast(UnityEngine.Vector2,UnityEngine.Camera,bool)"/> with
/// ignoreMasks) so hit testing matches the fullscreen Image; rendering still uses stencil
/// because <see cref="MaskableGraphic.maskable"/> stays true.
/// </summary>
[RequireComponent(typeof(CutoutMaskUISettings))]
public class CutoutMaskUI : Image
{
CutoutMaskUISettings settings;
Mask cachedParentMask;
Graphic cachedMaskGraphic;
bool storedMaskGraphicRaycast;
bool storedMaskGraphicRaycastValid;
public override bool Raycast(Vector2 sp, Camera eventCamera)
{
return Raycast(sp, eventCamera, ignoreMasks: true);
}
public override Material materialForRendering
{
get
{
Material material = new Material(base.materialForRendering);
material.SetInt("_StencilComp", (int)CompareFunction.NotEqual);
return material;
}
}
protected override void OnEnable()
{
settings = GetComponent<CutoutMaskUISettings>();
base.OnEnable();
if (settings == null || !settings.disableRaycastOnParentMaskGraphic)
return;
cachedParentMask = GetComponentInParent<Mask>();
if (cachedParentMask == null)
return;
cachedMaskGraphic = cachedParentMask.graphic;
if (cachedMaskGraphic == null || cachedMaskGraphic == this)
return;
storedMaskGraphicRaycastValid = true;
storedMaskGraphicRaycast = cachedMaskGraphic.raycastTarget;
cachedMaskGraphic.raycastTarget = false;
}
protected override void OnDisable()
{
if (storedMaskGraphicRaycastValid && cachedMaskGraphic != null)
{
cachedMaskGraphic.raycastTarget = storedMaskGraphicRaycast;
storedMaskGraphicRaycastValid = false;
}
cachedMaskGraphic = null;
cachedParentMask = null;
base.OnDisable();
}
public override bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera)
{
if (IsInsidePassThroughHole(screenPoint, eventCamera))
return settings != null && settings.blockRaycastThroughCutout;
return base.IsRaycastLocationValid(screenPoint, eventCamera);
}
bool IsInsidePassThroughHole(Vector2 screenPoint, Camera eventCamera)
{
RectTransform[] passThroughRects = settings != null ? settings.raycastPassThroughRects : null;
if (passThroughRects != null)
{
for (int i = 0; i < passThroughRects.Length; i++)
{
RectTransform rect = passThroughRects[i];
if (rect != null && RectTransformUtility.RectangleContainsScreenPoint(rect, screenPoint, eventCamera))
return true;
}
}
Mask mask = cachedParentMask != null ? cachedParentMask : GetComponentInParent<Mask>();
if (mask != null && mask.rectTransform != null &&
RectTransformUtility.RectangleContainsScreenPoint(mask.rectTransform, screenPoint, eventCamera))
return true;
return false;
}
}
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;
/// <summary>
/// Inverted stencil mask (see materialForRendering). Raycast options live on
/// <see cref="CutoutMaskUISettings"/> on the same GameObject (Unity's Image
/// inspector does not show fields on Image subclasses).
///
/// Parent <see cref="Mask"/> also implements <see cref="ICanvasRaycastFilter"/> and only
/// allows points inside its RectTransform. A fullscreen child under a small mask would
/// otherwise fail the raycast outside that rect (dimmed area lets clicks through) while
/// still blocking inside the mask bounds. We skip only Mask/RectMask2D in the raycast
/// walk (<see cref="Graphic.Raycast(UnityEngine.Vector2,UnityEngine.Camera,bool)"/> with
/// ignoreMasks) so hit testing matches the fullscreen Image; rendering still uses stencil
/// because <see cref="MaskableGraphic.maskable"/> stays true.
/// </summary>
[RequireComponent(typeof(CutoutMaskUISettings))]
public class CutoutMaskUI : Image
{
CutoutMaskUISettings settings;
Mask cachedParentMask;
Graphic cachedMaskGraphic;
bool storedMaskGraphicRaycast;
bool storedMaskGraphicRaycastValid;
public override bool Raycast(Vector2 sp, Camera eventCamera)
{
return Raycast(sp, eventCamera, ignoreMasks: true);
}
public override Material materialForRendering
{
get
{
Material material = new Material(base.materialForRendering);
material.SetInt("_StencilComp", (int)CompareFunction.NotEqual);
return material;
}
}
protected override void OnEnable()
{
settings = GetComponent<CutoutMaskUISettings>();
base.OnEnable();
if (settings == null || !settings.disableRaycastOnParentMaskGraphic)
return;
cachedParentMask = GetComponentInParent<Mask>();
if (cachedParentMask == null)
return;
cachedMaskGraphic = cachedParentMask.graphic;
if (cachedMaskGraphic == null || cachedMaskGraphic == this)
return;
storedMaskGraphicRaycastValid = true;
storedMaskGraphicRaycast = cachedMaskGraphic.raycastTarget;
cachedMaskGraphic.raycastTarget = false;
}
protected override void OnDisable()
{
if (storedMaskGraphicRaycastValid && cachedMaskGraphic != null)
{
cachedMaskGraphic.raycastTarget = storedMaskGraphicRaycast;
storedMaskGraphicRaycastValid = false;
}
cachedMaskGraphic = null;
cachedParentMask = null;
base.OnDisable();
}
public override bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera)
{
if (IsInsidePassThroughHole(screenPoint, eventCamera))
return settings != null && settings.blockRaycastThroughCutout;
return base.IsRaycastLocationValid(screenPoint, eventCamera);
}
bool IsInsidePassThroughHole(Vector2 screenPoint, Camera eventCamera)
{
RectTransform[] passThroughRects = settings != null ? settings.raycastPassThroughRects : null;
if (passThroughRects != null)
{
for (int i = 0; i < passThroughRects.Length; i++)
{
RectTransform rect = passThroughRects[i];
if (rect != null && RectTransformUtility.RectangleContainsScreenPoint(rect, screenPoint, eventCamera))
return true;
}
}
Mask mask = cachedParentMask != null ? cachedParentMask : GetComponentInParent<Mask>();
if (mask != null && mask.rectTransform != null &&
RectTransformUtility.RectangleContainsScreenPoint(mask.rectTransform, screenPoint, eventCamera))
return true;
return false;
}
}
+1 -1
View File
@@ -1,2 +1,2 @@
fileFormatVersion: 2
fileFormatVersion: 2
guid: 721d1e0343adc3c42b4508f55c455957
+15 -15
View File
@@ -1,15 +1,15 @@
using UnityEngine;
[DisallowMultipleComponent]
[RequireComponent(typeof(CutoutMaskUI))]
public class CutoutMaskUISettings : MonoBehaviour
{
[Tooltip("Rects matching cutout/hole areas. Clicks inside are not consumed by this Image. Leave empty to use the parent Mask's RectTransform.")]
public RectTransform[] raycastPassThroughRects;
[Tooltip("The Image on the same object as Mask is usually the cutout shape and still receives raycasts. When this is on, that graphic's Raycast Target is turned off while this component is enabled so the hole reaches UI behind the overlay.")]
public bool disableRaycastOnParentMaskGraphic = true;
[Tooltip("When enabled, clicks inside cutout/hole areas are consumed by this Image instead of passing through to UI behind.")]
public bool blockRaycastThroughCutout;
}
using UnityEngine;
[DisallowMultipleComponent]
[RequireComponent(typeof(CutoutMaskUI))]
public class CutoutMaskUISettings : MonoBehaviour
{
[Tooltip("Rects matching cutout/hole areas. Clicks inside are not consumed by this Image. Leave empty to use the parent Mask's RectTransform.")]
public RectTransform[] raycastPassThroughRects;
[Tooltip("The Image on the same object as Mask is usually the cutout shape and still receives raycasts. When this is on, that graphic's Raycast Target is turned off while this component is enabled so the hole reaches UI behind the overlay.")]
public bool disableRaycastOnParentMaskGraphic = true;
[Tooltip("When enabled, clicks inside cutout/hole areas are consumed by this Image instead of passing through to UI behind.")]
public bool blockRaycastThroughCutout;
}
@@ -1,2 +1,2 @@
fileFormatVersion: 2
fileFormatVersion: 2
guid: 29b95265513fc314995c59cb90745214
+8 -8
View File
@@ -1,8 +1,8 @@
fileFormatVersion: 2
guid: 05aa9e67ef3520047a8c20a6f96165d8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: 05aa9e67ef3520047a8c20a6f96165d8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+271 -271
View File
@@ -1,271 +1,271 @@
using UnityEngine.UI;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
[ExecuteAlways]
public class FrameAnimator : MonoBehaviour
{
public Sprite[] sprites;
public float frameRate = 10f;
public bool preview;
public bool isPlaying = false;
public bool loop = true;
public int currentFrame = 0;
float m_frameTimer = 0f;
bool m_previewPlaying = false;
#if UNITY_EDITOR
double m_lastEditorTime = 0d;
bool m_editorHooked;
#endif
Image m_img;
Image img {
get{
if(m_img==null){
m_img= GetComponent<Image>();
}
return m_img;
}
}
void OnValidate()
{
if(preview)
{
preview=false;
StartPreviewOnce();
}
}
void OnEnable()
{
#if UNITY_EDITOR
// Never hook editor updates during play-mode enter/exit — QueuePlayerLoopUpdate
// + isPlaying serialized true can infinite-reload Temp/__Backupscenes.
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
TryHookEditorUpdate();
#endif
}
void OnDisable()
{
#if UNITY_EDITOR
UnhookEditorUpdate();
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
#endif
}
void Start()
{
if (sprites == null || sprites.Length == 0)
{
return;
}
currentFrame = Mathf.Clamp(currentFrame, 0, sprites.Length - 1);
ApplyCurrentFrame();
}
// Update is called once per frame
void Update()
{
if (!Application.isPlaying)
{
return;
}
TickAnimation(Time.deltaTime);
}
#if UNITY_EDITOR
void OnPlayModeStateChanged(PlayModeStateChange state)
{
if (state == PlayModeStateChange.ExitingEditMode ||
state == PlayModeStateChange.EnteredPlayMode ||
state == PlayModeStateChange.ExitingPlayMode)
{
m_previewPlaying = false;
UnhookEditorUpdate();
}
else if (state == PlayModeStateChange.EnteredEditMode)
{
TryHookEditorUpdate();
}
}
void TryHookEditorUpdate()
{
if (Application.isPlaying || EditorApplication.isPlayingOrWillChangePlaymode)
{
UnhookEditorUpdate();
return;
}
if (m_editorHooked)
return;
m_lastEditorTime = EditorApplication.timeSinceStartup;
EditorApplication.update += OnEditorUpdate;
m_editorHooked = true;
}
void UnhookEditorUpdate()
{
if (!m_editorHooked)
return;
EditorApplication.update -= OnEditorUpdate;
m_editorHooked = false;
}
void OnEditorUpdate()
{
if (Application.isPlaying ||
EditorApplication.isPlayingOrWillChangePlaymode ||
this == null ||
!isActiveAndEnabled)
{
UnhookEditorUpdate();
return;
}
// Edit-mode animation is preview-only. Ignoring serialized isPlaying prevents
// permanent editor loops when isPlaying was left true in the scene.
if (!m_previewPlaying)
return;
double now = EditorApplication.timeSinceStartup;
float dt = (float)(now - m_lastEditorTime);
m_lastEditorTime = now;
if (dt <= 0f)
return;
int frameBefore = currentFrame;
TickAnimation(dt);
if (currentFrame != frameBefore || m_previewPlaying)
EditorApplication.QueuePlayerLoopUpdate();
}
#endif
void TickAnimation(float deltaTime)
{
if (frameRate <= 0f || sprites == null || sprites.Length == 0)
{
return;
}
bool shouldAnimate = Application.isPlaying
? (m_previewPlaying || isPlaying)
: m_previewPlaying;
if (!shouldAnimate)
{
return;
}
m_frameTimer += deltaTime;
float frameDuration = 1f / frameRate;
while (m_frameTimer >= frameDuration)
{
m_frameTimer -= frameDuration;
if (m_previewPlaying)
{
AdvancePreviewFrame();
}
else
{
AdvanceFrame();
}
}
}
public void Play(bool restart = false)
{
if (sprites == null || sprites.Length == 0)
{
return;
}
if (restart)
{
currentFrame = 0;
m_frameTimer = 0f;
ApplyCurrentFrame();
}
isPlaying = true;
}
public void Stop()
{
isPlaying = false;
m_frameTimer = 0f;
}
public void ResetToFirstFrame()
{
currentFrame = 0;
m_frameTimer = 0f;
ApplyCurrentFrame();
}
void StartPreviewOnce()
{
if (sprites == null || sprites.Length == 0)
{
return;
}
isPlaying = false;
m_previewPlaying = true;
m_frameTimer = 0f;
currentFrame = 0;
ApplyCurrentFrame();
}
void AdvancePreviewFrame()
{
currentFrame++;
if (currentFrame >= sprites.Length)
{
currentFrame = sprites.Length - 1;
m_previewPlaying = false;
}
ApplyCurrentFrame();
}
void AdvanceFrame()
{
currentFrame++;
if (currentFrame >= sprites.Length)
{
if (loop)
{
currentFrame = 0;
}
else
{
currentFrame = sprites.Length - 1;
isPlaying = false;
}
}
ApplyCurrentFrame();
}
void ApplyCurrentFrame()
{
if (img == null || sprites == null || sprites.Length == 0)
{
return;
}
currentFrame = Mathf.Clamp(currentFrame, 0, sprites.Length - 1);
img.sprite = sprites[currentFrame];
}
}
using UnityEngine.UI;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
[ExecuteAlways]
public class FrameAnimator : MonoBehaviour
{
public Sprite[] sprites;
public float frameRate = 10f;
public bool preview;
public bool isPlaying = false;
public bool loop = true;
public int currentFrame = 0;
float m_frameTimer = 0f;
bool m_previewPlaying = false;
#if UNITY_EDITOR
double m_lastEditorTime = 0d;
bool m_editorHooked;
#endif
Image m_img;
Image img {
get{
if(m_img==null){
m_img= GetComponent<Image>();
}
return m_img;
}
}
void OnValidate()
{
if(preview)
{
preview=false;
StartPreviewOnce();
}
}
void OnEnable()
{
#if UNITY_EDITOR
// Never hook editor updates during play-mode enter/exit — QueuePlayerLoopUpdate
// + isPlaying serialized true can infinite-reload Temp/__Backupscenes.
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
TryHookEditorUpdate();
#endif
}
void OnDisable()
{
#if UNITY_EDITOR
UnhookEditorUpdate();
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
#endif
}
void Start()
{
if (sprites == null || sprites.Length == 0)
{
return;
}
currentFrame = Mathf.Clamp(currentFrame, 0, sprites.Length - 1);
ApplyCurrentFrame();
}
// Update is called once per frame
void Update()
{
if (!Application.isPlaying)
{
return;
}
TickAnimation(Time.deltaTime);
}
#if UNITY_EDITOR
void OnPlayModeStateChanged(PlayModeStateChange state)
{
if (state == PlayModeStateChange.ExitingEditMode ||
state == PlayModeStateChange.EnteredPlayMode ||
state == PlayModeStateChange.ExitingPlayMode)
{
m_previewPlaying = false;
UnhookEditorUpdate();
}
else if (state == PlayModeStateChange.EnteredEditMode)
{
TryHookEditorUpdate();
}
}
void TryHookEditorUpdate()
{
if (Application.isPlaying || EditorApplication.isPlayingOrWillChangePlaymode)
{
UnhookEditorUpdate();
return;
}
if (m_editorHooked)
return;
m_lastEditorTime = EditorApplication.timeSinceStartup;
EditorApplication.update += OnEditorUpdate;
m_editorHooked = true;
}
void UnhookEditorUpdate()
{
if (!m_editorHooked)
return;
EditorApplication.update -= OnEditorUpdate;
m_editorHooked = false;
}
void OnEditorUpdate()
{
if (Application.isPlaying ||
EditorApplication.isPlayingOrWillChangePlaymode ||
this == null ||
!isActiveAndEnabled)
{
UnhookEditorUpdate();
return;
}
// Edit-mode animation is preview-only. Ignoring serialized isPlaying prevents
// permanent editor loops when isPlaying was left true in the scene.
if (!m_previewPlaying)
return;
double now = EditorApplication.timeSinceStartup;
float dt = (float)(now - m_lastEditorTime);
m_lastEditorTime = now;
if (dt <= 0f)
return;
int frameBefore = currentFrame;
TickAnimation(dt);
if (currentFrame != frameBefore || m_previewPlaying)
EditorApplication.QueuePlayerLoopUpdate();
}
#endif
void TickAnimation(float deltaTime)
{
if (frameRate <= 0f || sprites == null || sprites.Length == 0)
{
return;
}
bool shouldAnimate = Application.isPlaying
? (m_previewPlaying || isPlaying)
: m_previewPlaying;
if (!shouldAnimate)
{
return;
}
m_frameTimer += deltaTime;
float frameDuration = 1f / frameRate;
while (m_frameTimer >= frameDuration)
{
m_frameTimer -= frameDuration;
if (m_previewPlaying)
{
AdvancePreviewFrame();
}
else
{
AdvanceFrame();
}
}
}
public void Play(bool restart = false)
{
if (sprites == null || sprites.Length == 0)
{
return;
}
if (restart)
{
currentFrame = 0;
m_frameTimer = 0f;
ApplyCurrentFrame();
}
isPlaying = true;
}
public void Stop()
{
isPlaying = false;
m_frameTimer = 0f;
}
public void ResetToFirstFrame()
{
currentFrame = 0;
m_frameTimer = 0f;
ApplyCurrentFrame();
}
void StartPreviewOnce()
{
if (sprites == null || sprites.Length == 0)
{
return;
}
isPlaying = false;
m_previewPlaying = true;
m_frameTimer = 0f;
currentFrame = 0;
ApplyCurrentFrame();
}
void AdvancePreviewFrame()
{
currentFrame++;
if (currentFrame >= sprites.Length)
{
currentFrame = sprites.Length - 1;
m_previewPlaying = false;
}
ApplyCurrentFrame();
}
void AdvanceFrame()
{
currentFrame++;
if (currentFrame >= sprites.Length)
{
if (loop)
{
currentFrame = 0;
}
else
{
currentFrame = sprites.Length - 1;
isPlaying = false;
}
}
ApplyCurrentFrame();
}
void ApplyCurrentFrame()
{
if (img == null || sprites == null || sprites.Length == 0)
{
return;
}
currentFrame = Mathf.Clamp(currentFrame, 0, sprites.Length - 1);
img.sprite = sprites[currentFrame];
}
}
@@ -1,2 +1,2 @@
fileFormatVersion: 2
fileFormatVersion: 2
guid: b861af9d256faea40b17dd89fad46ee6
+22 -22
View File
@@ -1,22 +1,22 @@
using UnityEngine;
using DG.Tweening;
using UnityEngine.UI;
[RequireComponent(typeof(Image))]
public class ImageBlinker : MonoBehaviour
{
public float duration = 0.5f;
public Ease ease = Ease.InOutSine;
public float from = 0f;
public float to = 1f;
public int loops = -1;
public LoopType loopType = LoopType.Yoyo;
void Start()
{
var image = GetComponent<Image>();
var c = image.color;
c.a = from;
image.color = c;
image.DOFade(to, duration).SetEase(ease).SetLoops(loops, loopType);
}
}
using UnityEngine;
using DG.Tweening;
using UnityEngine.UI;
[RequireComponent(typeof(Image))]
public class ImageBlinker : MonoBehaviour
{
public float duration = 0.5f;
public Ease ease = Ease.InOutSine;
public float from = 0f;
public float to = 1f;
public int loops = -1;
public LoopType loopType = LoopType.Yoyo;
void Start()
{
var image = GetComponent<Image>();
var c = image.color;
c.a = from;
image.color = c;
image.DOFade(to, duration).SetEase(ease).SetLoops(loops, loopType);
}
}
+1 -1
View File
@@ -1,2 +1,2 @@
fileFormatVersion: 2
fileFormatVersion: 2
guid: ee65e1f8cf52cc24b989d032d572c1fa
+29 -29
View File
@@ -1,29 +1,29 @@
using TMPro;
using UnityEngine;
[RequireComponent(typeof(TMP_Text))]
public class LoadingTextTMP : MonoBehaviour
{
public string baseText = "Loading";
public char dotChar = '.';
public int dotCount =3;
public float interval = 1f;
TMP_Text txt;
void Start()
{
txt = GetComponent<TMP_Text>();
}
float timer = 0;
void Update(){
timer += Time.deltaTime;
if(timer > interval * dotCount){
timer =0;
}
int dots = (int)(timer / interval);
txt.text = baseText + new string(dotChar, dots);
}
}
using TMPro;
using UnityEngine;
[RequireComponent(typeof(TMP_Text))]
public class LoadingTextTMP : MonoBehaviour
{
public string baseText = "Loading";
public char dotChar = '.';
public int dotCount =3;
public float interval = 1f;
TMP_Text txt;
void Start()
{
txt = GetComponent<TMP_Text>();
}
float timer = 0;
void Update(){
timer += Time.deltaTime;
if(timer > interval * dotCount){
timer =0;
}
int dots = (int)(timer / interval);
txt.text = baseText + new string(dotChar, dots);
}
}
@@ -1,2 +1,2 @@
fileFormatVersion: 2
fileFormatVersion: 2
guid: 093b12f4aa5fb0446a9c1aa544025970
+34 -34
View File
@@ -1,34 +1,34 @@
using UnityEngine;
using DG.Tweening;
using UnityEngine.EventSystems;
[RequireComponent(typeof(EventTrigger))]
public class ScaleOnHover : MonoBehaviour
{
public float scaleFactor = 1.1f;
public float duration = 0.1f;
public Ease ease = Ease.OutBack;
void Start()
{
EventTrigger eventTrigger = GetComponent<EventTrigger>();
EventTrigger.Entry entry = new EventTrigger.Entry();
entry.eventID = EventTriggerType.PointerEnter;
entry.callback.AddListener((data) => { OnPointerEnter((PointerEventData)data); });
eventTrigger.triggers.Add(entry);
entry = new EventTrigger.Entry();
entry.eventID = EventTriggerType.PointerExit;
entry.callback.AddListener((data) => { OnPointerExit((PointerEventData)data); });
eventTrigger.triggers.Add(entry);
}
public void OnPointerEnter(PointerEventData eventData)
{
transform.DOScale(scaleFactor, duration).SetEase(ease);
}
public void OnPointerExit(PointerEventData eventData)
{
transform.DOKill();
transform.DOScale(1f, duration).SetEase(ease);
}
}
using UnityEngine;
using DG.Tweening;
using UnityEngine.EventSystems;
[RequireComponent(typeof(EventTrigger))]
public class ScaleOnHover : MonoBehaviour
{
public float scaleFactor = 1.1f;
public float duration = 0.1f;
public Ease ease = Ease.OutBack;
void Start()
{
EventTrigger eventTrigger = GetComponent<EventTrigger>();
EventTrigger.Entry entry = new EventTrigger.Entry();
entry.eventID = EventTriggerType.PointerEnter;
entry.callback.AddListener((data) => { OnPointerEnter((PointerEventData)data); });
eventTrigger.triggers.Add(entry);
entry = new EventTrigger.Entry();
entry.eventID = EventTriggerType.PointerExit;
entry.callback.AddListener((data) => { OnPointerExit((PointerEventData)data); });
eventTrigger.triggers.Add(entry);
}
public void OnPointerEnter(PointerEventData eventData)
{
transform.DOScale(scaleFactor, duration).SetEase(ease);
}
public void OnPointerExit(PointerEventData eventData)
{
transform.DOKill();
transform.DOScale(1f, duration).SetEase(ease);
}
}
+1 -1
View File
@@ -1,2 +1,2 @@
fileFormatVersion: 2
fileFormatVersion: 2
guid: 4e4c65221cd965e45853c892a9facd82
+45 -45
View File
@@ -1,45 +1,45 @@
using UnityEngine;
using UnityEngine.UI;
public class TabGroup : MonoBehaviour
{
public Button[] buttons;
public GameObject[] contents;
public int selectedIndex = 0;
void OnValidate(){
if(buttons == null || buttons.Length == 0){
buttons=GetComponentsInChildren<Button>();
}
}
void Awake()
{
SetSelectedIndex(selectedIndex);
for(int i=0; i < buttons.Length; i++)
{
int index = i;
buttons[i].onClick.AddListener(() => SetSelectedIndex(index));
}
}
public void SetSelectedIndex(int index)
{
if(index < 0 || index >= buttons.Length) return;
selectedIndex = index;
for(int i = 0; i < buttons.Length; i++)
{
buttons[i].targetGraphic.color = i == index ? buttons[i].colors.normalColor : buttons[i].colors.disabledColor;
try{
contents[i].SetActive(i == index);
}catch{
Debug.LogError("Content not found for index: " + i);
}
}
}
}
using UnityEngine;
using UnityEngine.UI;
public class TabGroup : MonoBehaviour
{
public Button[] buttons;
public GameObject[] contents;
public int selectedIndex = 0;
void OnValidate(){
if(buttons == null || buttons.Length == 0){
buttons=GetComponentsInChildren<Button>();
}
}
void Awake()
{
SetSelectedIndex(selectedIndex);
for(int i=0; i < buttons.Length; i++)
{
int index = i;
buttons[i].onClick.AddListener(() => SetSelectedIndex(index));
}
}
public void SetSelectedIndex(int index)
{
if(index < 0 || index >= buttons.Length) return;
selectedIndex = index;
for(int i = 0; i < buttons.Length; i++)
{
buttons[i].targetGraphic.color = i == index ? buttons[i].colors.normalColor : buttons[i].colors.disabledColor;
try{
contents[i].SetActive(i == index);
}catch{
Debug.LogError("Content not found for index: " + i);
}
}
}
}
+1 -1
View File
@@ -1,2 +1,2 @@
fileFormatVersion: 2
fileFormatVersion: 2
guid: d961ea20492fa0f448fbedacd3495911
+23 -23
View File
@@ -1,23 +1,23 @@
using UnityEngine;
using DG.Tweening;
using UnityEngine.UI;
using TMPro;
[RequireComponent(typeof(TMP_Text))]
public class TextBlinker : MonoBehaviour
{
public float duration = 0.5f;
public Ease ease = Ease.InOutSine;
public float from = 0f;
public float to = 1f;
public int loops = -1;
public LoopType loopType = LoopType.Yoyo;
void Start()
{
var txt = GetComponent<TMP_Text>();
var c = txt.color;
c.a = from;
txt.color = c;
txt.DOFade(to, duration).SetEase(ease).SetLoops(loops, loopType);
}
}
using UnityEngine;
using DG.Tweening;
using UnityEngine.UI;
using TMPro;
[RequireComponent(typeof(TMP_Text))]
public class TextBlinker : MonoBehaviour
{
public float duration = 0.5f;
public Ease ease = Ease.InOutSine;
public float from = 0f;
public float to = 1f;
public int loops = -1;
public LoopType loopType = LoopType.Yoyo;
void Start()
{
var txt = GetComponent<TMP_Text>();
var c = txt.color;
c.a = from;
txt.color = c;
txt.DOFade(to, duration).SetEase(ease).SetLoops(loops, loopType);
}
}
+2 -2
View File
@@ -1,2 +1,2 @@
fileFormatVersion: 2
guid: 430ada29524e05f41b887541b79adc2c
fileFormatVersion: 2
guid: 430ada29524e05f41b887541b79adc2c
+30 -30
View File
@@ -1,30 +1,30 @@
using TMPro;
using UnityEngine;
[RequireComponent(typeof(TMP_Text))]
public class TextColorFlash : MonoBehaviour
{
public Color colorA = Color.white;
public Color colorB = Color.red;
public float duration = 1f;
float a =0;
public float t;
TMP_Text txt;
void Start()
{
txt = GetComponent<TMP_Text>();
}
void Update()
{
if(duration <= 0){return;}
float sinA = Mathf.Sin(a);
t = sinA * 0.5f + 0.5f;
Color color = Color.Lerp(colorA, colorB, t);
txt.color = color;
a += Time.deltaTime * duration;
}
}
using TMPro;
using UnityEngine;
[RequireComponent(typeof(TMP_Text))]
public class TextColorFlash : MonoBehaviour
{
public Color colorA = Color.white;
public Color colorB = Color.red;
public float duration = 1f;
float a =0;
public float t;
TMP_Text txt;
void Start()
{
txt = GetComponent<TMP_Text>();
}
void Update()
{
if(duration <= 0){return;}
float sinA = Mathf.Sin(a);
t = sinA * 0.5f + 0.5f;
Color color = Color.Lerp(colorA, colorB, t);
txt.color = color;
a += Time.deltaTime * duration;
}
}
@@ -1,2 +1,2 @@
fileFormatVersion: 2
fileFormatVersion: 2
guid: 0d2075bb87ea2e44ebc4a00fcdac4ff2
+44 -44
View File
@@ -1,44 +1,44 @@
using System;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
[RequireComponent(typeof(Button))]
public class ToggleButton : MonoBehaviour
{
[SerializeField]
public ToggleSpriteData[] toggleSpriteData;
public bool isOn = false;
Button btn;
public UnityEvent<bool> onToggleValueChanged = new UnityEvent<bool>();
void Start()
{
btn = GetComponent<Button>();
btn.onClick.AddListener(OnClick);
}
void OnClick()
{
SetIsOn(!isOn);
}
public void SetIsOn(bool isOn)
{
this.isOn = isOn;
foreach (var spriteData in toggleSpriteData)
{
spriteData.target.sprite = isOn ? spriteData.onSprite : spriteData.offSprite;
}
onToggleValueChanged.Invoke(isOn);
}
}
[Serializable]
public class ToggleSpriteData{
public Image target;
public Sprite onSprite;
public Sprite offSprite;
}
using System;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
[RequireComponent(typeof(Button))]
public class ToggleButton : MonoBehaviour
{
[SerializeField]
public ToggleSpriteData[] toggleSpriteData;
public bool isOn = false;
Button btn;
public UnityEvent<bool> onToggleValueChanged = new UnityEvent<bool>();
void Start()
{
btn = GetComponent<Button>();
btn.onClick.AddListener(OnClick);
}
void OnClick()
{
SetIsOn(!isOn);
}
public void SetIsOn(bool isOn)
{
this.isOn = isOn;
foreach (var spriteData in toggleSpriteData)
{
spriteData.target.sprite = isOn ? spriteData.onSprite : spriteData.offSprite;
}
onToggleValueChanged.Invoke(isOn);
}
}
[Serializable]
public class ToggleSpriteData{
public Image target;
public Sprite onSprite;
public Sprite offSprite;
}
+1 -1
View File
@@ -1,2 +1,2 @@
fileFormatVersion: 2
fileFormatVersion: 2
guid: 32dd41e420d0032409b03beba9058456