602 lines
22 KiB
C#
602 lines
22 KiB
C#
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using AibisDream.Kit;
|
||
using DG.Tweening;
|
||
using UnityEngine;
|
||
|
||
namespace AibisDream.MiniGame.Tarot
|
||
{
|
||
public class TarotDeck : MonoBehaviour
|
||
{
|
||
[Header("Fan Spread")]
|
||
[Tooltip("Total angle of the fan arc (degrees)")]
|
||
[SerializeField] private float fanAngleRange = 120f;
|
||
|
||
[Tooltip("Radius of the fan arc")]
|
||
[SerializeField] private float fanRadius = 3f;
|
||
|
||
[Tooltip("Fan spread animation duration")]
|
||
[SerializeField] private float spreadDuration = 0.6f;
|
||
|
||
[Tooltip("相邻牌启动时间差;0 = 同时展开。中心向外错开时仍乘以此值")]
|
||
[SerializeField] private float spreadStagger = 0.028f;
|
||
|
||
[Tooltip("true:中间牌先动、向两侧铺开;false:从左到右依次展开")]
|
||
[SerializeField] private bool spreadFromCenterOut = true;
|
||
|
||
[Tooltip("位移缓动;OutBack 易过冲显乱,默认 InOutQuint 更稳")]
|
||
[SerializeField] private Ease spreadMoveEase = Ease.InOutQuint;
|
||
|
||
[Tooltip("旋转缓动,可与位移略不同以增加层次")]
|
||
[SerializeField] private Ease spreadRotateEase = Ease.InOutQuint;
|
||
|
||
[Tooltip("可选:非空时优先于 spreadMoveEase / spreadRotateEase(0~1 时间映射)")]
|
||
[SerializeField] private AnimationCurve spreadEaseCurve;
|
||
|
||
[Header("Hover")]
|
||
[Tooltip("Distance a card moves outward on hover")]
|
||
[SerializeField] private float hoverOffset = 0.5f;
|
||
|
||
[Tooltip("Hover animation duration")]
|
||
[SerializeField] private float hoverDuration = 0.18f;
|
||
|
||
[Tooltip("Hover 推出缓动")]
|
||
[SerializeField] private Ease hoverOutEase = Ease.OutQuint;
|
||
|
||
[Tooltip("Hover 收回缓动")]
|
||
[SerializeField] private Ease hoverInEase = Ease.InOutQuart;
|
||
|
||
[Tooltip("可选:覆盖 hover 推出/收回的 Ease")]
|
||
[SerializeField] private AnimationCurve hoverOutCurve;
|
||
|
||
[SerializeField] private AnimationCurve hoverInCurve;
|
||
|
||
[Header("Inspect")]
|
||
[Tooltip("Anchor transform for the inspect position")]
|
||
[SerializeField] private Transform inspectAnchor;
|
||
|
||
[Tooltip("检视 / 初显叠牌缩放;扇形摊开后回到 1")]
|
||
[SerializeField] private float inspectScale = 1.8f;
|
||
|
||
[Tooltip("摊开前从检视缩放到扇形尺寸的时长;0 = 与位移同步缩小")]
|
||
[SerializeField] private float shrinkBeforeSpreadDuration = 0.28f;
|
||
|
||
[Header("Animation Durations")]
|
||
[Tooltip("叠牌出现时整体淡入时长(与 Hide 对称)")]
|
||
[SerializeField] private float fadeInDuration = 0.35f;
|
||
|
||
[Tooltip("Fade-out duration for unselected cards")]
|
||
[SerializeField] private float fadeOutDuration = 0.3f;
|
||
|
||
[Tooltip("Duration for selected card to move to inspect position")]
|
||
[SerializeField] private float moveToInspectDuration = 0.4f;
|
||
|
||
[Header("Card Prefab")]
|
||
[Tooltip("Prefab with SpriteRenderer + BoxCollider2D + EventTriggerEx + TarotCard")]
|
||
[SerializeField] private GameObject cardPrefab;
|
||
|
||
[Header("Gizmo Preview (Scene View)")]
|
||
[Tooltip("关闭则不绘制任何 Gizmo")]
|
||
[SerializeField] private bool showGizmos = true;
|
||
|
||
[Tooltip("勾选:仅选中 TarotDeck 时显示;不勾选:始终显示(半透明,便于摆位时参考)")]
|
||
[SerializeField] private bool gizmoOnlyWhenSelected = true;
|
||
|
||
[Tooltip("Number of card slots to preview when no cards are spawned (edit mode)")]
|
||
[SerializeField] [Min(1)] private int gizmoPreviewCardCount = 5;
|
||
|
||
[SerializeField] private Color gizmoFanArcColor = new Color(0.35f, 0.85f, 1f, 0.9f);
|
||
[SerializeField] private Color gizmoCardSlotColor = new Color(0.35f, 0.85f, 1f, 0.75f);
|
||
[SerializeField] private Color gizmoHoverColor = new Color(1f, 0.65f, 0.2f, 0.85f);
|
||
[SerializeField] private Color gizmoInspectColor = new Color(0.45f, 1f, 0.55f, 0.9f);
|
||
|
||
[Tooltip("gizmoOnlyWhenSelected=false 时,与选中态相比的颜色透明度比例")]
|
||
[SerializeField] [Range(0.15f, 1f)] private float gizmoUnselectedAlphaScale = 0.35f;
|
||
|
||
private readonly List<TarotCard> _cards = new();
|
||
private readonly Dictionary<TarotCard, Vector3> _fanPositions = new();
|
||
private readonly Dictionary<TarotCard, Quaternion> _fanRotations = new();
|
||
|
||
private TarotCard _selectedCard;
|
||
private TarotCard _hoveredCard;
|
||
private bool _isInteractable;
|
||
private readonly Dictionary<TarotCard, Tweener> _hoverTweensByCard = new();
|
||
private TarotCard _pointerDownCard;
|
||
|
||
public TarotCard SelectedCard => _selectedCard;
|
||
public bool HasSelection => _selectedCard != null;
|
||
|
||
public event Action<TarotCard> OnCardSelected;
|
||
|
||
private void Awake()
|
||
{
|
||
if (inspectAnchor == null)
|
||
{
|
||
var t = transform.Find("InspectAnchor");
|
||
if (t != null) inspectAnchor = t;
|
||
}
|
||
}
|
||
|
||
#region Setup & Teardown
|
||
|
||
public void Setup(int cardCount, Sprite frontSprite, Sprite backSprite)
|
||
{
|
||
ClearCards();
|
||
|
||
if (cardPrefab == null)
|
||
{
|
||
Debug.LogError("[TarotDeck] cardPrefab is not assigned!", this);
|
||
return;
|
||
}
|
||
|
||
for (int i = 0; i < cardCount; i++)
|
||
{
|
||
var go = Instantiate(cardPrefab, transform);
|
||
go.name = $"TarotCard_{i}";
|
||
var card = go.GetComponent<TarotCard>();
|
||
if (card == null) card = go.AddComponent<TarotCard>();
|
||
|
||
card.Init(i, frontSprite, backSprite);
|
||
card.SetInteractable(false);
|
||
card.SetSortingOrder(i);
|
||
|
||
// 初显叠成一张背面:落在检视位并以 inspectScale 放大
|
||
Vector3 stackPos = GetInspectLocalPosition();
|
||
go.transform.localPosition = stackPos;
|
||
go.transform.localRotation = Quaternion.identity;
|
||
go.transform.localScale = Vector3.one * inspectScale;
|
||
|
||
card.OnHoverEnter = () => HandleHoverEnter(card);
|
||
card.OnHoverExit = () => HandleHoverExit(card);
|
||
card.OnPointerDown = () => HandleCardPointerDown(card);
|
||
|
||
_cards.Add(card);
|
||
}
|
||
}
|
||
|
||
private Vector3 GetInspectLocalPosition()
|
||
{
|
||
return inspectAnchor != null ? inspectAnchor.localPosition : Vector3.zero;
|
||
}
|
||
|
||
public void ClearCards()
|
||
{
|
||
foreach (var kv in _hoverTweensByCard)
|
||
kv.Value?.Kill();
|
||
_hoverTweensByCard.Clear();
|
||
_pointerDownCard = null;
|
||
_selectedCard = null;
|
||
_hoveredCard = null;
|
||
_isInteractable = false;
|
||
|
||
foreach (var card in _cards)
|
||
{
|
||
if (card != null && card.gameObject != null)
|
||
Destroy(card.gameObject);
|
||
}
|
||
|
||
_cards.Clear();
|
||
_fanPositions.Clear();
|
||
_fanRotations.Clear();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Fan Spread
|
||
|
||
/// <summary>
|
||
/// Fan layout angle in degrees for the i-th card (same as <see cref="SpreadCards"/>).
|
||
/// </summary>
|
||
public float GetFanSlotAngleDegrees(int index, int count)
|
||
{
|
||
if (count <= 0) return 0f;
|
||
// 单张牌落在弧中心(90°),否则 angleStep=0 时会落在 90°+fanRange/2 的端点,视觉上偏一侧
|
||
if (count == 1) return 90f; // 弧段中心(对称轴)
|
||
float angleStep = fanAngleRange / (count - 1);
|
||
float startAngle = 90f + fanAngleRange * 0.5f;
|
||
return startAngle - index * angleStep;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Local position of the i-th card in fan layout (same math as <see cref="SpreadCards"/>).
|
||
/// </summary>
|
||
public Vector3 GetLocalFanSlotPosition(int index, int count)
|
||
{
|
||
if (count <= 0) return Vector3.zero;
|
||
float angle = GetFanSlotAngleDegrees(index, count);
|
||
float rad = angle * Mathf.Deg2Rad;
|
||
return new Vector3(
|
||
Mathf.Cos(rad) * fanRadius,
|
||
Mathf.Sin(rad) * fanRadius - fanRadius,
|
||
0f
|
||
);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 扇形圆弧所在圆的圆心(本地空间),与 <see cref="GetLocalFanSlotPosition"/> 使用的几何一致。
|
||
/// </summary>
|
||
public Vector3 GetFanCircleCenterLocal() => new Vector3(0f, -fanRadius, 0f);
|
||
|
||
/// <summary>
|
||
/// 从圆心指向牌位的外侧方向(用于 hover 沿径向推出)。
|
||
/// </summary>
|
||
private Vector3 GetFanRadialOutDirection(Vector3 slotLocalPos)
|
||
{
|
||
Vector3 fromCenter = slotLocalPos - GetFanCircleCenterLocal();
|
||
if (fromCenter.sqrMagnitude < 0.0001f) return Vector3.up;
|
||
return fromCenter.normalized;
|
||
}
|
||
|
||
public IEnumerator SpreadCards()
|
||
{
|
||
if (_cards.Count == 0) yield break;
|
||
|
||
int count = _cards.Count;
|
||
Vector3 stackPos = GetInspectLocalPosition();
|
||
|
||
// 先缩小到扇形尺寸(可叠回牌堆中心),再摊开
|
||
if (shrinkBeforeSpreadDuration > 0.001f)
|
||
{
|
||
var shrinkSeq = DOTween.Sequence();
|
||
foreach (var card in _cards)
|
||
{
|
||
shrinkSeq.Join(
|
||
card.transform.DOScale(Vector3.one, shrinkBeforeSpreadDuration)
|
||
.SetEase(Ease.InOutSine));
|
||
shrinkSeq.Join(
|
||
card.transform.DOLocalMove(stackPos, shrinkBeforeSpreadDuration)
|
||
.SetEase(Ease.InOutSine));
|
||
}
|
||
|
||
yield return shrinkSeq.WaitForCompletion();
|
||
}
|
||
|
||
var seq = DOTween.Sequence();
|
||
|
||
for (int i = 0; i < count; i++)
|
||
{
|
||
var card = _cards[i];
|
||
Vector3 pos = GetLocalFanSlotPosition(i, count);
|
||
float rotZ = GetFanSlotAngleDegrees(i, count) - 90f;
|
||
Quaternion rot = Quaternion.Euler(0f, 0f, rotZ);
|
||
|
||
_fanPositions[card] = pos;
|
||
_fanRotations[card] = rot;
|
||
|
||
float delay = GetSpreadDelayForIndex(i, count);
|
||
var moveTw = card.transform.DOLocalMove(pos, spreadDuration);
|
||
ApplySpreadMoveEase(moveTw);
|
||
var rotTw = card.transform.DOLocalRotateQuaternion(rot, spreadDuration);
|
||
ApplySpreadRotateEase(rotTw);
|
||
seq.Insert(delay, moveTw);
|
||
seq.Insert(delay, rotTw);
|
||
|
||
// 若未单独缩小时,与位移同步缩回 1
|
||
if (shrinkBeforeSpreadDuration <= 0.001f)
|
||
{
|
||
var scaleTw = card.transform.DOScale(Vector3.one, spreadDuration)
|
||
.SetEase(Ease.InOutSine);
|
||
seq.Insert(delay, scaleTw);
|
||
}
|
||
}
|
||
|
||
yield return seq.WaitForCompletion();
|
||
}
|
||
|
||
private float GetSpreadDelayForIndex(int index, int count)
|
||
{
|
||
if (count <= 1 || spreadStagger <= 0f) return 0f;
|
||
if (spreadFromCenterOut)
|
||
{
|
||
float mid = (count - 1) * 0.5f;
|
||
return Mathf.Abs(index - mid) * spreadStagger;
|
||
}
|
||
|
||
return index * spreadStagger;
|
||
}
|
||
|
||
private void ApplySpreadMoveEase(Tween tween)
|
||
{
|
||
if (spreadEaseCurve != null && spreadEaseCurve.keys.Length > 0)
|
||
tween.SetEase(spreadEaseCurve);
|
||
else
|
||
tween.SetEase(spreadMoveEase);
|
||
}
|
||
|
||
private void ApplySpreadRotateEase(Tween tween)
|
||
{
|
||
if (spreadEaseCurve != null && spreadEaseCurve.keys.Length > 0)
|
||
tween.SetEase(spreadEaseCurve);
|
||
else
|
||
tween.SetEase(spreadRotateEase);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Interaction
|
||
|
||
public void SetInteractable(bool interactable)
|
||
{
|
||
_isInteractable = interactable;
|
||
if (!interactable)
|
||
_pointerDownCard = null;
|
||
foreach (var card in _cards)
|
||
card.SetInteractable(interactable);
|
||
}
|
||
|
||
private void LateUpdate()
|
||
{
|
||
if (_pointerDownCard == null) return;
|
||
if (!Input.GetMouseButtonUp(0)) return;
|
||
|
||
var card = _pointerDownCard;
|
||
_pointerDownCard = null;
|
||
if (card == null) return;
|
||
if (!card.gameObject) return;
|
||
HandleCardClicked(card);
|
||
}
|
||
|
||
private void HandleCardPointerDown(TarotCard card)
|
||
{
|
||
if (!_isInteractable || _selectedCard != null) return;
|
||
_pointerDownCard = card;
|
||
}
|
||
|
||
private void KillHoverTween(TarotCard card)
|
||
{
|
||
if (card == null) return;
|
||
if (_hoverTweensByCard.TryGetValue(card, out var tw))
|
||
{
|
||
tw?.Kill();
|
||
_hoverTweensByCard.Remove(card);
|
||
}
|
||
}
|
||
|
||
private void RestoreHoverToFanSlot(TarotCard card)
|
||
{
|
||
if (card == null) return;
|
||
if (!_fanPositions.TryGetValue(card, out var basePos)) return;
|
||
KillHoverTween(card);
|
||
var backTw = card.transform.DOLocalMove(basePos, hoverDuration);
|
||
ApplyHoverInEase(backTw);
|
||
_hoverTweensByCard[card] = backTw;
|
||
}
|
||
|
||
private void HandleHoverEnter(TarotCard card)
|
||
{
|
||
if (!_isInteractable || _selectedCard != null) return;
|
||
|
||
// 直接 hover 到下一张时,Enter 可能先于上一张的 Exit:先强制收回其它牌
|
||
foreach (var c in _cards)
|
||
{
|
||
if (c != card)
|
||
RestoreHoverToFanSlot(c);
|
||
}
|
||
|
||
_hoveredCard = card;
|
||
KillHoverTween(card);
|
||
|
||
AudioManager.Instance?.PlaySfx("event:/FollowInput/cardPick");
|
||
|
||
if (!_fanPositions.TryGetValue(card, out var basePos)) return;
|
||
|
||
Vector3 pushDir = GetFanRadialOutDirection(basePos);
|
||
Vector3 targetPos = basePos + pushDir * hoverOffset;
|
||
var hoverTw = card.transform.DOLocalMove(targetPos, hoverDuration);
|
||
ApplyHoverOutEase(hoverTw);
|
||
_hoverTweensByCard[card] = hoverTw;
|
||
}
|
||
|
||
private void HandleHoverExit(TarotCard card)
|
||
{
|
||
if (_selectedCard != null) return;
|
||
|
||
if (_hoveredCard == card) _hoveredCard = null;
|
||
|
||
if (!_fanPositions.TryGetValue(card, out var basePos)) return;
|
||
|
||
KillHoverTween(card);
|
||
var backTw = card.transform.DOLocalMove(basePos, hoverDuration);
|
||
ApplyHoverInEase(backTw);
|
||
_hoverTweensByCard[card] = backTw;
|
||
}
|
||
|
||
private void ApplyHoverOutEase(Tween tween)
|
||
{
|
||
if (hoverOutCurve != null && hoverOutCurve.keys.Length > 0)
|
||
tween.SetEase(hoverOutCurve);
|
||
else
|
||
tween.SetEase(hoverOutEase);
|
||
}
|
||
|
||
private void ApplyHoverInEase(Tween tween)
|
||
{
|
||
if (hoverInCurve != null && hoverInCurve.keys.Length > 0)
|
||
tween.SetEase(hoverInCurve);
|
||
else
|
||
tween.SetEase(hoverInEase);
|
||
}
|
||
|
||
private void HandleCardClicked(TarotCard card)
|
||
{
|
||
if (!_isInteractable || _selectedCard != null) return;
|
||
_pointerDownCard = null;
|
||
foreach (var c in _cards)
|
||
KillHoverTween(c);
|
||
_selectedCard = card;
|
||
SetInteractable(false);
|
||
// 立即通知 Yarn(wait_tarot_select 结束);fade + 移至检视位在后台播放,不阻塞对话
|
||
OnCardSelected?.Invoke(card);
|
||
StartCoroutine(SelectCardSequence(card));
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Select Sequence
|
||
|
||
private IEnumerator SelectCardSequence(TarotCard selected)
|
||
{
|
||
selected.SetSortingOrder(200);
|
||
|
||
var fadeSeq = DOTween.Sequence();
|
||
foreach (var card in _cards)
|
||
{
|
||
if (card == selected) continue;
|
||
fadeSeq.Join(card.DOFade(0f, fadeOutDuration));
|
||
}
|
||
|
||
Vector3 inspectPos = GetInspectLocalPosition();
|
||
|
||
fadeSeq.Join(
|
||
selected.transform.DOLocalMove(inspectPos, moveToInspectDuration).SetEase(Ease.InOutCubic)
|
||
);
|
||
fadeSeq.Join(
|
||
selected.transform.DOLocalRotateQuaternion(Quaternion.identity, moveToInspectDuration)
|
||
.SetEase(Ease.InOutCubic)
|
||
);
|
||
fadeSeq.Join(
|
||
selected.transform.DOScale(Vector3.one * inspectScale, moveToInspectDuration)
|
||
.SetEase(Ease.InOutCubic)
|
||
);
|
||
|
||
yield return fadeSeq.WaitForCompletion();
|
||
|
||
foreach (var card in _cards)
|
||
{
|
||
if (card == selected) continue;
|
||
card.gameObject.SetActive(false);
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Show / Hide
|
||
|
||
/// <summary>
|
||
/// 叠牌出现后从透明淡入(调用前需已 <see cref="Setup"/>)。
|
||
/// </summary>
|
||
public IEnumerator FadeInStack(float? duration = null)
|
||
{
|
||
float d = duration ?? fadeInDuration;
|
||
if (_cards.Count == 0) yield break;
|
||
|
||
foreach (var card in _cards)
|
||
card.SetAlpha(0f);
|
||
|
||
var seq = DOTween.Sequence();
|
||
foreach (var card in _cards)
|
||
seq.Join(card.DOFade(1f, d));
|
||
|
||
yield return seq.WaitForCompletion();
|
||
}
|
||
|
||
public IEnumerator HideAll(float duration = 0.3f)
|
||
{
|
||
var seq = DOTween.Sequence();
|
||
foreach (var card in _cards)
|
||
{
|
||
if (!card.gameObject.activeSelf) continue;
|
||
seq.Join(card.DOFade(0f, duration));
|
||
}
|
||
|
||
yield return seq.WaitForCompletion();
|
||
|
||
foreach (var card in _cards)
|
||
card.gameObject.SetActive(false);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Gizmos
|
||
|
||
private void OnDrawGizmos()
|
||
{
|
||
if (!showGizmos || gizmoOnlyWhenSelected) return;
|
||
DrawTarotPreviewGizmos(gizmoUnselectedAlphaScale);
|
||
}
|
||
|
||
private void OnDrawGizmosSelected()
|
||
{
|
||
if (!showGizmos) return;
|
||
if (!gizmoOnlyWhenSelected) return;
|
||
DrawTarotPreviewGizmos(1f);
|
||
}
|
||
|
||
/// <param name="alphaScale">1 = 选中预览;较小值用于「始终显示」时弱化线条</param>
|
||
private void DrawTarotPreviewGizmos(float alphaScale)
|
||
{
|
||
int count = _cards.Count > 0 ? _cards.Count : gizmoPreviewCardCount;
|
||
if (count < 1) count = 1;
|
||
|
||
var anchor = inspectAnchor != null ? inspectAnchor : transform.Find("InspectAnchor");
|
||
|
||
Matrix4x4 old = Gizmos.matrix;
|
||
Gizmos.matrix = transform.localToWorldMatrix;
|
||
|
||
// Fan arc (circle center matches card layout: radius fanRadius around (0,-fanRadius,0))
|
||
Vector3 circleCenter = GetFanCircleCenterLocal();
|
||
Gizmos.color = ScaleColorAlpha(gizmoFanArcColor, alphaScale);
|
||
const int arcSegments = 48;
|
||
float angleMin = 90f + fanAngleRange * 0.5f - fanAngleRange;
|
||
float angleMax = 90f + fanAngleRange * 0.5f;
|
||
Vector3 prev = FanPointOnCircle(circleCenter, fanRadius, angleMin);
|
||
for (int s = 1; s <= arcSegments; s++)
|
||
{
|
||
float t = s / (float)arcSegments;
|
||
float a = Mathf.Lerp(angleMin, angleMax, t);
|
||
Vector3 cur = FanPointOnCircle(circleCenter, fanRadius, a);
|
||
Gizmos.DrawLine(prev, cur);
|
||
prev = cur;
|
||
}
|
||
|
||
// Card slots + hover offset
|
||
float slotRadius = 0.08f * Mathf.Min(fanRadius, 2f);
|
||
for (int i = 0; i < count; i++)
|
||
{
|
||
Vector3 slot = GetLocalFanSlotPosition(i, count);
|
||
Gizmos.color = ScaleColorAlpha(gizmoCardSlotColor, alphaScale);
|
||
Gizmos.DrawWireSphere(slot, slotRadius);
|
||
|
||
Vector3 pushDir = GetFanRadialOutDirection(slot);
|
||
Vector3 hoverEnd = slot + pushDir * hoverOffset;
|
||
Gizmos.color = ScaleColorAlpha(gizmoHoverColor, alphaScale);
|
||
Gizmos.DrawLine(slot, hoverEnd);
|
||
Gizmos.DrawWireSphere(hoverEnd, slotRadius * 0.65f);
|
||
}
|
||
|
||
// Inspect anchor
|
||
Vector3 inspectLocal = anchor != null ? anchor.localPosition : Vector3.zero;
|
||
Gizmos.color = ScaleColorAlpha(gizmoInspectColor, alphaScale);
|
||
float inspectR = 0.12f * inspectScale;
|
||
Gizmos.DrawWireSphere(inspectLocal, inspectR);
|
||
Gizmos.DrawWireCube(inspectLocal, Vector3.one * (0.25f * inspectScale));
|
||
|
||
Gizmos.matrix = old;
|
||
|
||
#if UNITY_EDITOR
|
||
if (alphaScale >= 0.99f)
|
||
{
|
||
UnityEditor.Handles.Label(
|
||
transform.TransformPoint(inspectLocal) + Vector3.up * 0.15f,
|
||
"InspectAnchor");
|
||
}
|
||
#endif
|
||
}
|
||
|
||
private static Color ScaleColorAlpha(Color c, float scale)
|
||
{
|
||
c.a *= scale;
|
||
return c;
|
||
}
|
||
|
||
private static Vector3 FanPointOnCircle(Vector3 circleCenter, float radius, float angleDeg)
|
||
{
|
||
float rad = angleDeg * Mathf.Deg2Rad;
|
||
return circleCenter + new Vector3(Mathf.Cos(rad) * radius, Mathf.Sin(rad) * radius, 0f);
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
}
|