initial commit
This commit is contained in:
commit
f8db72668a
162 files changed
+75914
No files matched your search
@@ -0,0 +1,266 @@
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using LitMotion;
|
||||
using LitMotion.Extensions;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
[RequireComponent(typeof(CanvasGroup))]
|
||||
public class CardView : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler
|
||||
{
|
||||
[Header("Visual Elements")]
|
||||
[SerializeField] private GameObject frontFace;
|
||||
|
||||
[SerializeField] private GameObject backFace;
|
||||
[SerializeField] private Image frontBackground;
|
||||
[SerializeField] private TMP_Text titleText;
|
||||
|
||||
public CardModel Model { get; private set; }
|
||||
public CardContainer CurrentContainer { get; set; }
|
||||
public bool IsFaceUp { get; private set; } = true;
|
||||
public bool IsInteractable { get; set; } = true;
|
||||
|
||||
private RectTransform _rectTransform;
|
||||
private Canvas _rootCanvas;
|
||||
private CanvasGroup _canvasGroup;
|
||||
|
||||
private GameObject _placeholder;
|
||||
private CardContainer _originContainer;
|
||||
|
||||
private MotionHandle _moveMotion;
|
||||
private MotionHandle _scaleMotion;
|
||||
private MotionHandle _rotMotion;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_rectTransform = GetComponent<RectTransform>();
|
||||
_canvasGroup = GetComponent<CanvasGroup>();
|
||||
_rootCanvas = GetComponentInParent<Canvas>();
|
||||
}
|
||||
|
||||
public void Initialize(CardModel model, bool faceUp)
|
||||
{
|
||||
Model = model;
|
||||
titleText.text = model.GetTitle();
|
||||
frontBackground.color = model.GetSuitColor();
|
||||
SetFaceInstant(faceUp);
|
||||
}
|
||||
|
||||
public void SetFaceInstant(bool faceUp)
|
||||
{
|
||||
IsFaceUp = faceUp;
|
||||
frontFace.SetActive(faceUp);
|
||||
backFace.SetActive(!faceUp);
|
||||
_rectTransform.localEulerAngles = Vector3.zero;
|
||||
}
|
||||
|
||||
public async UniTask FlipAsync(bool faceUp, float duration = 0.25f, CancellationToken ct = default)
|
||||
{
|
||||
if (IsFaceUp == faceUp) return;
|
||||
IsFaceUp = faceUp;
|
||||
|
||||
CancelMotion(ref _rotMotion);
|
||||
SoundManager.Instance?.PlayFlip();
|
||||
|
||||
_rotMotion = LMotion.Create(0f, 90f, duration * 0.5f)
|
||||
.WithEase(Ease.InQuad)
|
||||
.BindToLocalEulerAnglesY(_rectTransform);
|
||||
await _rotMotion.ToUniTask(ct);
|
||||
|
||||
frontFace.SetActive(faceUp);
|
||||
backFace.SetActive(!faceUp);
|
||||
|
||||
_rotMotion = LMotion.Create(90f, 0f, duration * 0.5f)
|
||||
.WithEase(Ease.OutQuad)
|
||||
.BindToLocalEulerAnglesY(_rectTransform);
|
||||
await _rotMotion.ToUniTask(ct);
|
||||
}
|
||||
|
||||
public async UniTask AnimateToTargetAsync(CardContainer targetContainer, int siblingIndex = -1, float duration = 0.3f, CancellationToken ct = default)
|
||||
{
|
||||
CancelMotion(ref _moveMotion);
|
||||
CancelMotion(ref _scaleMotion);
|
||||
|
||||
IsInteractable = false;
|
||||
_canvasGroup.blocksRaycasts = false;
|
||||
|
||||
var tempSlot = new GameObject("TempSlot", typeof(RectTransform), typeof(LayoutElement));
|
||||
var tempRect = tempSlot.GetComponent<RectTransform>();
|
||||
tempRect.SetParent(targetContainer.cardHolder, false);
|
||||
tempRect.sizeDelta = _rectTransform.sizeDelta;
|
||||
|
||||
if (siblingIndex >= 0 && siblingIndex <= targetContainer.cardHolder.childCount)
|
||||
tempRect.SetSiblingIndex(siblingIndex);
|
||||
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(targetContainer.cardHolder);
|
||||
|
||||
var targetWorldPos = tempRect.position;
|
||||
|
||||
transform.SetParent(_rootCanvas.transform, true);
|
||||
|
||||
_scaleMotion = LMotion.Create(_rectTransform.localScale, Vector3.one, duration)
|
||||
.WithEase(Ease.OutQuad)
|
||||
.BindToLocalScale(_rectTransform);
|
||||
|
||||
_moveMotion = LMotion.Create(_rectTransform.position, targetWorldPos, duration)
|
||||
.WithEase(Ease.OutCubic)
|
||||
.BindToPosition(_rectTransform);
|
||||
|
||||
await _moveMotion.ToUniTask(ct);
|
||||
|
||||
var finalIndex = tempRect.GetSiblingIndex();
|
||||
Destroy(tempSlot);
|
||||
|
||||
transform.SetParent(targetContainer.cardHolder, false);
|
||||
transform.SetSiblingIndex(finalIndex);
|
||||
_rectTransform.localPosition = Vector3.zero;
|
||||
_rectTransform.localScale = Vector3.one;
|
||||
|
||||
CurrentContainer = targetContainer;
|
||||
_canvasGroup.blocksRaycasts = true;
|
||||
IsInteractable = true;
|
||||
}
|
||||
|
||||
public void OnPointerEnter(PointerEventData eventData)
|
||||
{
|
||||
if (!IsInteractable || eventData.dragging) return;
|
||||
CancelMotion(ref _scaleMotion);
|
||||
_scaleMotion = LMotion.Create(_rectTransform.localScale, Vector3.one * 1.08f, 0.15f)
|
||||
.WithEase(Ease.OutQuad)
|
||||
.BindToLocalScale(_rectTransform);
|
||||
}
|
||||
|
||||
public void OnPointerExit(PointerEventData eventData)
|
||||
{
|
||||
if (!IsInteractable || eventData.dragging) return;
|
||||
CancelMotion(ref _scaleMotion);
|
||||
_scaleMotion = LMotion.Create(_rectTransform.localScale, Vector3.one, 0.15f)
|
||||
.WithEase(Ease.OutQuad)
|
||||
.BindToLocalScale(_rectTransform);
|
||||
}
|
||||
|
||||
public void OnBeginDrag(PointerEventData eventData)
|
||||
{
|
||||
if (!IsInteractable || !GameManager.Instance.CanStartDrag(this))
|
||||
{
|
||||
eventData.pointerDrag = null;
|
||||
return;
|
||||
}
|
||||
|
||||
CancelMotion(ref _moveMotion);
|
||||
CancelMotion(ref _scaleMotion);
|
||||
|
||||
SoundManager.Instance?.PlayDraw();
|
||||
|
||||
_originContainer = CurrentContainer;
|
||||
_originContainer.RemoveCardListReference(this);
|
||||
|
||||
_placeholder = new GameObject("Placeholder", typeof(RectTransform), typeof(LayoutElement));
|
||||
var rt = _placeholder.GetComponent<RectTransform>();
|
||||
rt.SetParent(_originContainer.cardHolder, false);
|
||||
rt.sizeDelta = _rectTransform.sizeDelta;
|
||||
rt.SetSiblingIndex(transform.GetSiblingIndex());
|
||||
|
||||
var le = _placeholder.GetComponent<LayoutElement>();
|
||||
le.preferredWidth = _rectTransform.rect.width;
|
||||
le.preferredHeight = _rectTransform.rect.height;
|
||||
|
||||
transform.SetParent(_rootCanvas.transform, true);
|
||||
_canvasGroup.blocksRaycasts = false;
|
||||
|
||||
_scaleMotion = LMotion.Create(_rectTransform.localScale, Vector3.one * 1.15f, 0.15f)
|
||||
.WithEase(Ease.OutBack)
|
||||
.BindToLocalScale(_rectTransform);
|
||||
}
|
||||
|
||||
public void OnDrag(PointerEventData eventData)
|
||||
{
|
||||
if (!IsInteractable) return;
|
||||
|
||||
if (RectTransformUtility.ScreenPointToWorldPointInRectangle(
|
||||
_rootCanvas.GetComponent<RectTransform>(),
|
||||
eventData.position,
|
||||
eventData.pressEventCamera,
|
||||
out var globalMousePos))
|
||||
{
|
||||
_rectTransform.position = globalMousePos;
|
||||
}
|
||||
|
||||
if (_originContainer != null && _originContainer.type == ContainerType.Hand && _placeholder != null)
|
||||
{
|
||||
UpdatePlaceholderPositionInHand();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePlaceholderPositionInHand()
|
||||
{
|
||||
Transform holder = _originContainer.cardHolder;
|
||||
var newSiblingIndex = holder.childCount;
|
||||
|
||||
for (var i = 0; i < holder.childCount; i++)
|
||||
{
|
||||
var child = holder.GetChild(i);
|
||||
if (child == _placeholder.transform) continue;
|
||||
|
||||
if (_rectTransform.position.x < child.position.x)
|
||||
{
|
||||
newSiblingIndex = i;
|
||||
if (_placeholder.transform.GetSiblingIndex() < newSiblingIndex)
|
||||
newSiblingIndex--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_placeholder.transform.SetSiblingIndex(newSiblingIndex);
|
||||
}
|
||||
|
||||
public void OnEndDrag(PointerEventData eventData)
|
||||
{
|
||||
if (_placeholder == null) return;
|
||||
|
||||
var returnIndex = _placeholder.transform.GetSiblingIndex();
|
||||
Destroy(_placeholder);
|
||||
|
||||
CardContainer targetContainer = null;
|
||||
if (eventData.pointerEnter != null)
|
||||
{
|
||||
targetContainer = eventData.pointerEnter.GetComponentInParent<CardContainer>();
|
||||
}
|
||||
|
||||
GameManager.Instance.HandleCardDropAsync(this, _originContainer, targetContainer, returnIndex).Forget();
|
||||
}
|
||||
|
||||
public void OnPointerClick(PointerEventData eventData)
|
||||
{
|
||||
if (eventData.dragging || CurrentContainer == null) return;
|
||||
|
||||
switch (CurrentContainer.type)
|
||||
{
|
||||
case ContainerType.Deck:
|
||||
GameManager.Instance.DrawCardByClickAsync().Forget();
|
||||
break;
|
||||
|
||||
case ContainerType.Hand:
|
||||
GameManager.Instance.PlayCardFromHandByClickAsync(this).Forget();
|
||||
break;
|
||||
|
||||
case ContainerType.Discard:
|
||||
GameManager.Instance.RecycleDiscardByClickAsync().Forget();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void CancelMotion(ref MotionHandle handle)
|
||||
{
|
||||
if (handle.IsActive()) handle.Cancel();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
CancelMotion(ref _moveMotion);
|
||||
CancelMotion(ref _scaleMotion);
|
||||
CancelMotion(ref _rotMotion);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user