WOrking card dragging, slotting, previewing

This commit is contained in:
Michal Pikulski
2025-11-07 12:51:45 +01:00
parent 77f7d1ee97
commit 32a477b843
9 changed files with 549 additions and 1288 deletions

View File

@@ -82,17 +82,37 @@ namespace UI.CardSystem
/// </summary>
public void OnPointerClick(PointerEventData eventData)
{
// During reveal flow (before placed in slot), ignore clicks
// Let the parent FlippableCard handle them
Debug.Log($"[CLICK-TRACE-ALBUMCARD] OnPointerClick on {name}, _parentSlot={((_parentSlot != null) ? _parentSlot.name : "NULL")}, _isEnlarged={_isEnlarged}, position={eventData.position}");
// During reveal flow (before placed in slot), forward clicks to parent FlippableCard
if (_parentSlot == null)
{
Debug.Log($"[CLICK-TRACE-ALBUMCARD] {name} - No parent slot, forwarding click to parent FlippableCard");
// Find parent FlippableCard and forward the click
FlippableCard parentFlippable = GetComponentInParent<FlippableCard>();
if (parentFlippable != null)
{
Debug.Log($"[CLICK-TRACE-ALBUMCARD] {name} - Found parent FlippableCard, calling OnPointerClick");
parentFlippable.OnPointerClick(eventData);
}
else
{
Debug.LogWarning($"[CLICK-TRACE-ALBUMCARD] {name} - No parent FlippableCard found!");
}
return;
}
Debug.Log($"[CLICK-TRACE-ALBUMCARD] {name} - Has parent slot, processing click");
if (_isEnlarged)
{
Debug.Log($"[CLICK-TRACE-ALBUMCARD] {name} - Is enlarged, requesting shrink");
OnShrinkRequested?.Invoke(this);
}
else
{
Debug.Log($"[CLICK-TRACE-ALBUMCARD] {name} - Is normal size, requesting enlarge");
OnEnlargeRequested?.Invoke(this);
}
}

View File

@@ -695,6 +695,52 @@ namespace UI.CardSystem
Debug.Log($"[AlbumViewPage] Card shrunk: {card.GetCardData()?.Name}");
}
/// <summary>
/// Show backdrop and reparent slot preview card for enlargement
/// </summary>
public void ShowSlotPreview(AlbumCardSlot slot, Transform previewCardTransform)
{
if (previewCardTransform == null)
return;
Debug.Log($"[AlbumViewPage] ShowSlotPreview called for slot: {slot.name}");
// Show backdrop
if (cardEnlargedBackdrop != null)
{
cardEnlargedBackdrop.SetActive(true);
}
// Reparent preview card to enlarged container (above backdrop)
if (cardEnlargedContainer != null)
{
previewCardTransform.SetParent(cardEnlargedContainer, true);
previewCardTransform.SetAsLastSibling();
}
}
/// <summary>
/// Hide backdrop and trigger shrink animation for slot preview
/// </summary>
public void HideSlotPreview(AlbumCardSlot slot, Transform previewCardTransform, System.Action onComplete)
{
if (previewCardTransform == null)
return;
Debug.Log($"[AlbumViewPage] HideSlotPreview called for slot: {slot.name}");
// Hide backdrop
if (cardEnlargedBackdrop != null)
{
cardEnlargedBackdrop.SetActive(false);
}
// Shrink preview card
Vector3 originalScale = previewCardTransform.localScale / 2.5f; // Assuming 2.5x is enlarged scale
Pixelplacement.Tween.LocalScale(previewCardTransform, originalScale, 0.3f, 0f, Pixelplacement.Tween.EaseInBack,
completeCallback: () => onComplete?.Invoke());
}
#endregion
}
}

View File

@@ -4,6 +4,7 @@ using Core;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
#if UNITY_EDITOR
using UnityEditor;
#endif
@@ -13,7 +14,7 @@ namespace UI.CardSystem
/// <summary>
/// Displays a single card using the new visual system with frames, overlays, backgrounds, and zone shapes.
/// </summary>
public class CardDisplay : MonoBehaviour
public class CardDisplay : MonoBehaviour, IPointerClickHandler
{
[Header("UI Elements")]
[SerializeField] private TextMeshProUGUI cardNameText;
@@ -36,6 +37,10 @@ namespace UI.CardSystem
// Events
public event Action<CardDisplay> OnCardClicked;
// Preview mode tracking for click forwarding
private bool _isPreviewMode;
private AlbumCardSlot _previewSlot;
/// <summary>
/// Sets up the card display with the given card data
@@ -82,6 +87,47 @@ namespace UI.CardSystem
Logging.Debug($"[CardDisplay] Updated visuals for card: {cardData.Name} (Rarity: {cardData.Rarity}, Zone: {cardData.Zone})");
}
/// <summary>
/// Apply preview visuals - black tint to card image and question marks for name
/// Used for empty slot previews to show locked/unknown cards
/// </summary>
public void SetPreviewVisuals()
{
// Set card name to question marks
if (cardNameText != null)
{
cardNameText.text = "??????";
}
// Apply black non-opaque tint to card image
if (cardImage != null)
{
cardImage.color = Color.black;
}
Logging.Debug($"[CardDisplay] Applied preview visuals (black tint and ?????? name)");
}
/// <summary>
/// Reset preview visuals back to normal
/// </summary>
public void ClearPreviewVisuals()
{
// Restore normal card name
if (cardData != null && cardNameText != null)
{
cardNameText.text = cardData.Name ?? "Unknown Card";
}
// Reset card image color to white (normal)
if (cardImage != null)
{
cardImage.color = Color.white;
}
Logging.Debug($"[CardDisplay] Cleared preview visuals");
}
/// <summary>
/// Updates the card name text
@@ -234,32 +280,76 @@ namespace UI.CardSystem
}
}
/// <summary>
/// Enable preview mode - when clicked, forwards click to the associated slot
/// </summary>
public void SetPreviewMode(bool isEnabled, AlbumCardSlot slot = null)
{
_isPreviewMode = isEnabled;
_previewSlot = slot;
// Enable raycast targets on images so this CardDisplay can receive clicks
if (cardImage != null) cardImage.raycastTarget = isEnabled;
if (frameImage != null) frameImage.raycastTarget = isEnabled;
if (overlayImage != null) overlayImage.raycastTarget = isEnabled;
if (backgroundImage != null) backgroundImage.raycastTarget = isEnabled;
if (zoneShapeImage != null) zoneShapeImage.raycastTarget = isEnabled;
Logging.Debug($"[CardDisplay] Preview mode {(isEnabled ? "enabled" : "disabled")}, slot: {(slot != null ? slot.name : "NULL")}");
}
/// <summary>
/// Handle click on CardDisplay - forward to preview slot if in preview mode
/// </summary>
public void OnPointerClick(PointerEventData eventData)
{
Logging.Debug($"[CLICK-TRACE-CARDDISPLAY] OnPointerClick on {name}, _isPreviewMode={_isPreviewMode}, _previewSlot={((_previewSlot != null) ? _previewSlot.name : "NULL")}");
if (_isPreviewMode && _previewSlot != null)
{
Logging.Debug($"[CLICK-TRACE-CARDDISPLAY] {name} - In preview mode, calling DismissPreview on slot: {_previewSlot.name}");
_previewSlot.DismissPreview();
}
else
{
// Not in preview mode - forward click to parent AlbumCard (if it exists)
AlbumCard parentAlbumCard = GetComponentInParent<AlbumCard>();
if (parentAlbumCard != null)
{
Logging.Debug($"[CLICK-TRACE-CARDDISPLAY] {name} - Forwarding click to parent AlbumCard");
parentAlbumCard.OnPointerClick(eventData);
}
else
{
Logging.Debug($"[CLICK-TRACE-CARDDISPLAY] {name} - No parent AlbumCard, firing OnCardClicked event");
OnCardClicked?.Invoke(this);
}
}
}
#if UNITY_EDITOR
/// <summary>
/// Editor-only: Creates card data from the assigned definition and displays it
/// Editor-only: Preview a card from the assigned definition
/// </summary>
public void PreviewFromDefinition()
{
if (editorCardDefinition == null)
{
Logging.Warning("[CardDisplay] Cannot preview: No card definition assigned in editor");
UnityEngine.Debug.LogWarning("[CardDisplay] No Card Definition assigned in Editor Tools.");
return;
}
cardData = editorCardDefinition.CreateCardData();
UpdateCardVisuals();
Logging.Debug($"[CardDisplay] Previewing card from definition: {cardData.Name}");
CardData previewData = editorCardDefinition.CreateCardData();
SetupCard(previewData);
}
/// <summary>
/// Editor-only: Clears the preview
/// Editor-only: Clear the preview
/// </summary>
public void ClearPreview()
{
cardData = null;
ClearCard();
Logging.Debug("[CardDisplay] Preview cleared");
}
#endif
}
@@ -300,4 +390,3 @@ namespace UI.CardSystem
}
#endif
}

View File

@@ -192,6 +192,8 @@ namespace UI.CardSystem
{
base.OnPointerUpHook(longPress);
Debug.Log($"[CLICK-TRACE-PLACEMENT] OnPointerUpHook on {name}, _wasDragged={_wasDragged}, _isRevealed={_isRevealed}, _waitingForPlacementTap={_waitingForPlacementTap}, longPress={longPress}");
_isHolding = false;
// Cancel hold timer if running
@@ -206,23 +208,34 @@ namespace UI.CardSystem
{
if (!_isRevealed)
{
Debug.Log($"[CLICK-TRACE-PLACEMENT] {name} - First tap, revealing card");
// First tap: reveal the card
RevealCard();
_waitingForPlacementTap = true;
}
else if (_waitingForPlacementTap)
{
Debug.Log($"[CLICK-TRACE-PLACEMENT] {name} - Second tap, snapping to slot");
// Second tap: snap to slot
_waitingForPlacementTap = false;
SnapToAlbumSlot();
}
else
{
Debug.Log($"[CLICK-TRACE-PLACEMENT] {name} - Tap after reveal but not waiting for placement tap");
}
}
else if (_isDragRevealing)
{
Debug.Log($"[CLICK-TRACE-PLACEMENT] {name} - Was drag-revealed, auto-snapping");
// Was drag-revealed, auto-snap on release
_isDragRevealing = false;
SnapToAlbumSlot();
}
else
{
Debug.Log($"[CLICK-TRACE-PLACEMENT] {name} - Was dragged but no special handling");
}
}
/// <summary>

View File

@@ -2,6 +2,7 @@
using Data.CardSystem;
using UI.DragAndDrop.Core;
using UnityEngine;
using UnityEngine.EventSystems;
namespace UI.CardSystem
{
@@ -9,15 +10,34 @@ namespace UI.CardSystem
/// Specialized slot for album pages that only accepts a specific card.
/// Validates cards based on their CardDefinition.
/// Self-populates with owned cards when enabled.
/// Shows preview of target card when empty slot is tapped.
/// </summary>
public class AlbumCardSlot : DraggableSlot
public class AlbumCardSlot : DraggableSlot, IPointerClickHandler
{
[Header("Album Slot Configuration")]
[SerializeField] private CardDefinition targetCardDefinition; // Which card this slot accepts
[SerializeField] private GameObject albumCardPrefab; // Prefab to spawn when card is owned
[Header("Preview Card (for empty slots)")]
[SerializeField] private CardDisplay previewCardDisplay; // Nested CardDisplay showing greyed-out preview
[SerializeField] private float previewEnlargedScale = 2.5f;
[SerializeField] private float previewScaleDuration = 0.3f;
private bool _isOccupiedPermanently = false;
private AlbumCard _placedCard;
private bool _isPreviewShowing = false;
private Vector3 _previewOriginalScale;
private void Awake()
{
// Store original scale of preview card
if (previewCardDisplay != null)
{
_previewOriginalScale = previewCardDisplay.transform.localScale;
// Hide preview card by default
previewCardDisplay.gameObject.SetActive(false);
}
}
/// <summary>
/// Set the target card this slot should accept
@@ -80,6 +100,40 @@ namespace UI.CardSystem
{
// Check if we should spawn a card for this slot
CheckAndSpawnOwnedCard();
// Setup preview card display if slot is empty
SetupPreviewCard();
}
/// <summary>
/// Setup the preview card display to show target card with preview visuals
/// Preview stays hidden until user taps to show it
/// </summary>
private void SetupPreviewCard()
{
if (previewCardDisplay == null || targetCardDefinition == null)
return;
// Only setup preview if slot is empty
if (_isOccupiedPermanently || _placedCard != null)
{
// Hide preview if slot is occupied
previewCardDisplay.gameObject.SetActive(false);
return;
}
// Setup preview card data
CardData previewData = targetCardDefinition.CreateCardData();
previewData.Rarity = CardRarity.Normal; // Show as normal rarity
previewCardDisplay.SetupCard(previewData);
// Apply preview visuals (black tint and ?????? name)
previewCardDisplay.SetPreviewVisuals();
// Keep preview hidden - it'll show when user taps to enlarge
previewCardDisplay.gameObject.SetActive(false);
Debug.Log($"[AlbumCardSlot] Setup preview card for {targetCardDefinition.Name} (hidden until tap)");
}
/// <summary>
@@ -154,6 +208,140 @@ namespace UI.CardSystem
}
}
/// <summary>
/// Get the target card definition for this slot
/// </summary>
public CardDefinition GetTargetCardDefinition()
{
return targetCardDefinition;
}
/// <summary>
/// Handle click on slot - show/hide preview if empty
/// </summary>
public void OnPointerClick(PointerEventData eventData)
{
Debug.Log($"[CLICK-TRACE-SLOT] OnPointerClick on {name}, _isOccupiedPermanently={_isOccupiedPermanently}, _placedCard={((_placedCard != null) ? _placedCard.name : "NULL")}, _isPreviewShowing={_isPreviewShowing}, position={eventData.position}");
// Only handle clicks if slot is empty
if (_isOccupiedPermanently || _placedCard != null)
{
Debug.Log($"[CLICK-TRACE-SLOT] {name} - Slot is occupied, ignoring");
return;
}
// Only handle if we have a preview card setup
if (previewCardDisplay == null || targetCardDefinition == null)
{
Debug.Log($"[CLICK-TRACE-SLOT] {name} - No preview setup, ignoring");
return;
}
if (_isPreviewShowing)
{
Debug.Log($"[CLICK-TRACE-SLOT] {name} - Preview is showing, hiding it");
HidePreview();
}
else
{
Debug.Log($"[CLICK-TRACE-SLOT] {name} - Preview is hidden, showing it");
ShowPreview();
}
}
/// <summary>
/// Show enlarged preview of target card
/// </summary>
private void ShowPreview()
{
if (_isPreviewShowing || previewCardDisplay == null)
return;
_isPreviewShowing = true;
// Show the preview card (already has preview visuals applied)
previewCardDisplay.gameObject.SetActive(true);
// Enable preview mode so clicks on CardDisplay forward to this slot
previewCardDisplay.SetPreviewMode(true, this);
// Reset to normal scale before enlarging
previewCardDisplay.transform.localScale = _previewOriginalScale;
// Get AlbumViewPage to show backdrop and reparent
AlbumViewPage albumPage = FindObjectOfType<AlbumViewPage>();
if (albumPage != null)
{
albumPage.ShowSlotPreview(this, previewCardDisplay.transform);
}
// Scale up preview card
Pixelplacement.Tween.LocalScale(previewCardDisplay.transform, _previewOriginalScale * previewEnlargedScale,
previewScaleDuration, 0f, Pixelplacement.Tween.EaseOutBack);
Debug.Log($"[AlbumCardSlot] Showing preview for {targetCardDefinition.Name}");
}
/// <summary>
/// Hide preview and return to normal
/// </summary>
private void HidePreview()
{
if (!_isPreviewShowing || previewCardDisplay == null)
return;
_isPreviewShowing = false;
// Disable preview mode on CardDisplay
previewCardDisplay.SetPreviewMode(false, null);
// Get AlbumViewPage to hide backdrop
AlbumViewPage albumPage = FindObjectOfType<AlbumViewPage>();
if (albumPage != null)
{
albumPage.HideSlotPreview(this, previewCardDisplay.transform, () =>
{
// After shrink completes, reparent back to slot
previewCardDisplay.transform.SetParent(transform, false);
// Reset RectTransform properties
RectTransform previewRect = previewCardDisplay.transform as RectTransform;
if (previewRect != null)
{
// Set anchors to stretch in all directions (matching original setup)
previewRect.anchorMin = Vector2.zero; // (0, 0)
previewRect.anchorMax = Vector2.one; // (1, 1)
// Reset offsets to zero (left, right, top, bottom all = 0)
previewRect.offsetMin = Vector2.zero; // Sets left and bottom to 0
previewRect.offsetMax = Vector2.zero; // Sets right and top to 0 (note: these are negative values internally)
previewRect.pivot = new Vector2(0.5f, 0.5f);
}
previewCardDisplay.transform.localPosition = Vector3.zero;
previewCardDisplay.transform.localRotation = Quaternion.identity;
previewCardDisplay.transform.localScale = _previewOriginalScale;
// Hide the preview card after returning to slot
previewCardDisplay.gameObject.SetActive(false);
Debug.Log($"[AlbumCardSlot] Preview hidden and reset for {targetCardDefinition.Name}");
});
}
Debug.Log($"[AlbumCardSlot] Hiding preview for {targetCardDefinition.Name}");
}
/// <summary>
/// Public method to dismiss preview - can be called by CardDisplay when clicked
/// </summary>
public void DismissPreview()
{
Debug.Log($"[CLICK-TRACE-SLOT] DismissPreview called on {name}");
HidePreview();
}
/// <summary>
/// Get the target card definition for this slot
/// </summary>

View File

@@ -1,4 +1,4 @@
using System;
using System;
using AppleHills.Data.CardSystem;
using Pixelplacement;
using Pixelplacement.TweenSystem;
@@ -260,9 +260,12 @@ namespace UI.CardSystem
public void OnPointerClick(PointerEventData eventData)
{
Debug.Log($"[CLICK-TRACE-FLIPPABLE] OnPointerClick on {name}, _isClickable={_isClickable}, _isWaitingForTap={_isWaitingForTap}, _isFlipped={_isFlipped}, position={eventData.position}");
// If not clickable, notify and return
if (!_isClickable)
{
Debug.Log($"[CLICK-TRACE-FLIPPABLE] {name} - Not clickable, firing OnClickedWhileInactive");
OnClickedWhileInactive?.Invoke(this);
return;
}
@@ -270,14 +273,19 @@ namespace UI.CardSystem
// If waiting for tap after reveal, handle that
if (_isWaitingForTap)
{
Debug.Log($"[CLICK-TRACE-FLIPPABLE] {name} - Waiting for tap, dismissing enlarged state");
OnCardTappedAfterReveal?.Invoke(this);
_isWaitingForTap = false;
return;
}
if (_isFlipped || _isFlipping)
{
Debug.Log($"[CLICK-TRACE-FLIPPABLE] {name} - Ignoring click (flipped={_isFlipped}, flipping={_isFlipping})");
return;
}
Debug.Log($"[CLICK-TRACE-FLIPPABLE] {name} - Processing click, starting flip");
// Flip on click
FlipToReveal();
}