First go at the card UI

This commit is contained in:
Michal Pikulski
2025-10-15 09:22:13 +02:00
committed by Michal Adam Pikulski
parent 7f3dccf1ea
commit ed9f2d6c6d
4 changed files with 758 additions and 167 deletions

View File

@@ -20,6 +20,12 @@ namespace AppleHills.UI.CardSystem
[SerializeField] private GameObject cardSlotPrefab;
[SerializeField] private GameObject cardPrefab;
[Header("Filter UI")]
[SerializeField] private Dropdown zoneFilterDropdown;
[SerializeField] private Dropdown rarityFilterDropdown;
[SerializeField] private Button resetFiltersButton;
[SerializeField] private CanvasGroup canvasGroup;
// Runtime references
private CardSystemManager _cardManager;
private List<CardUIElement> _displayedCards = new List<CardUIElement>();
@@ -32,6 +38,12 @@ namespace AppleHills.UI.CardSystem
private void Awake()
{
_cardManager = CardSystemManager.Instance;
// Make sure we have a CanvasGroup for transitions
if (canvasGroup == null)
canvasGroup = GetComponent<CanvasGroup>();
if (canvasGroup == null)
canvasGroup = gameObject.AddComponent<CanvasGroup>();
}
/// <summary>
@@ -53,6 +65,9 @@ namespace AppleHills.UI.CardSystem
// Clear any previous setup
ClearAlbum();
// Setup filter UI
InitializeFilters();
// Get all collected cards
List<CardData> collectedCards = _cardManager.GetAllCollectedCards();
@@ -160,28 +175,15 @@ namespace AppleHills.UI.CardSystem
/// </summary>
private void SetupCardDragHandlers(CardUIElement cardUI)
{
// // Get drag handler component (you might need to implement this)
// DragHandler dragHandler = cardUI.GetComponent<DragHandler>();
// if (dragHandler == null)
// {
// // This is a stub for the drag handler
// // In a real implementation, you'd have a proper drag handler component
// // For now, we'll just add click listeners
//
// // Add click listener
// Button cardButton = cardUI.GetComponent<Button>();
// if (cardButton != null)
// {
// cardButton.onClick.AddListener(() => OnCardClicked(cardUI));
// }
// }
// else
// {
// // Set up the drag handler events
// dragHandler.OnBeginDrag.AddListener(() => OnBeginDragCard(cardUI));
// dragHandler.OnDrag.AddListener((position) => OnDragCard(cardUI, position));
// dragHandler.OnEndDrag.AddListener(() => OnEndDragCard(cardUI));
// }
// Add click listener to handle card clicks
Button cardButton = cardUI.GetComponent<Button>();
if (cardButton != null)
{
cardButton.onClick.AddListener(() => OnCardClicked(cardUI));
}
// Subscribe to the card's own click event
cardUI.OnCardClicked += OnCardClicked;
}
/// <summary>
@@ -198,148 +200,225 @@ namespace AppleHills.UI.CardSystem
PlaceCardInSlot(cardUI, slot);
}
}
/// <summary>
/// Handles the start of a card drag operation
/// Places a card in a specific album slot
/// </summary>
private void OnBeginDragCard(CardUIElement cardUI)
private void PlaceCardInSlot(CardUIElement cardUI, Transform slotTransform)
{
_currentlyDraggedCard = cardUI;
_cardOriginalPosition = cardUI.transform.position;
if (cardUI == null || slotTransform == null) return;
// Bring the card to the front
cardUI.transform.SetAsLastSibling();
// Save original parent to revert if needed
Transform originalParent = cardUI.transform.parent;
Vector3 originalPosition = cardUI.transform.position;
Vector3 originalScale = cardUI.transform.localScale;
// Animate card moving to slot
cardUI.transform.SetParent(slotTransform);
// Use tween to animate the placement
Tween.Position(cardUI.transform, slotTransform.position, 0.3f, 0f);
Tween.LocalScale(cardUI.transform, Vector3.one, 0.3f, 0f);
// Update the card's internal state (if needed)
CardData cardData = cardUI.GetCardData();
Logging.Debug($"[AlbumViewPage] Placed card {cardData.Name} in slot {cardData.CollectionIndex}");
}
/// <summary>
/// Handles the dragging of a card
/// </summary>
private void OnDragCard(CardUIElement cardUI, Vector3 position)
{
cardUI.transform.position = position;
}
/// <summary>
/// Handles the end of a card drag operation
/// </summary>
private void OnEndDragCard(CardUIElement cardUI)
{
// Check if the card is over a valid slot
Transform closestSlot = FindClosestSlot(cardUI.transform.position);
if (closestSlot != null)
{
// Place the card in the slot
PlaceCardInSlot(cardUI, closestSlot);
}
else
{
// Return the card to its original position
cardUI.transform.position = _cardOriginalPosition;
}
_currentlyDraggedCard = null;
}
/// <summary>
/// Places a card in an album slot
/// </summary>
private void PlaceCardInSlot(CardUIElement cardUI, Transform slot)
{
// Reparent the card to the slot
cardUI.transform.SetParent(slot);
// Animate card to center of slot using Pixelplacement.Tween
Tween.LocalPosition(cardUI.transform, Vector3.zero, 0.25f, 0f, Tween.EaseOutBack);
Logging.Debug($"[AlbumViewPage] Placed card '{cardUI.GetCardData().Name}' in album slot");
}
/// <summary>
/// Finds the closest album slot to a given position
/// </summary>
private Transform FindClosestSlot(Vector3 position)
{
Transform closest = null;
float closestDistance = 100f; // Large initial value
foreach (var slot in _albumSlots.Values)
{
float distance = Vector3.Distance(position, slot.position);
if (distance < closestDistance && distance < 50f) // Only if within reasonable range
{
closestDistance = distance;
closest = slot;
}
}
return closest;
}
/// <summary>
/// Clears the album UI
/// Clears all cards from the album
/// </summary>
private void ClearAlbum()
{
// Clear displayed cards
// Clear card UI elements
foreach (var card in _displayedCards)
{
Destroy(card.gameObject);
if (card != null && card.gameObject != null)
{
Destroy(card.gameObject);
}
}
_displayedCards.Clear();
// Clear album slots
foreach (Transform child in albumGrid.transform)
foreach (var slotPair in _albumSlots)
{
Destroy(child.gameObject);
if (slotPair.Value != null && slotPair.Value.gameObject != null)
{
Destroy(slotPair.Value.gameObject);
}
}
_albumSlots.Clear();
}
/// <summary>
/// Override for transition in animation using Pixelplacement.Tween
/// Initialize filtering UI and set up listeners
/// </summary>
protected override void DoTransitionIn(System.Action onComplete)
private void InitializeFilters()
{
// Simple slide in animation
RectTransform rt = GetComponent<RectTransform>();
if (rt != null)
// Setup zone filter
if (zoneFilterDropdown != null)
{
// Store the end position
Vector2 endPosition = rt.anchoredPosition;
zoneFilterDropdown.ClearOptions();
// Set initial position (off-screen to the right)
rt.anchoredPosition = new Vector2(Screen.width, endPosition.y);
// Add "All Zones" option
List<string> zoneOptions = new List<string> { "All Zones" };
// Animate to end position
Tween.AnchoredPosition(rt, endPosition, transitionDuration, 0f,
Tween.EaseOutStrong, Tween.LoopType.None, null, onComplete);
// Add each zone
foreach (CardZone zone in System.Enum.GetValues(typeof(CardZone)))
{
zoneOptions.Add(zone.ToString());
}
zoneFilterDropdown.AddOptions(zoneOptions);
zoneFilterDropdown.onValueChanged.AddListener(OnZoneFilterChanged);
}
else
// Setup rarity filter
if (rarityFilterDropdown != null)
{
onComplete?.Invoke();
rarityFilterDropdown.ClearOptions();
// Add "All Rarities" option
List<string> rarityOptions = new List<string> { "All Rarities" };
// Add each rarity
foreach (CardRarity rarity in System.Enum.GetValues(typeof(CardRarity)))
{
rarityOptions.Add(rarity.ToString());
}
rarityFilterDropdown.AddOptions(rarityOptions);
rarityFilterDropdown.onValueChanged.AddListener(OnRarityFilterChanged);
}
// Setup reset button
if (resetFiltersButton != null)
{
resetFiltersButton.onClick.AddListener(ResetFilters);
}
}
/// <summary>
/// Override for transition out animation using Pixelplacement.Tween
/// Called when zone filter dropdown changes
/// </summary>
protected override void DoTransitionOut(System.Action onComplete)
private void OnZoneFilterChanged(int index)
{
// Simple slide out animation
RectTransform rt = GetComponent<RectTransform>();
if (rt != null)
{
// Animate to off-screen position (to the left)
Vector2 offScreenPosition = new Vector2(-Screen.width, rt.anchoredPosition.y);
ApplyFilters();
}
/// <summary>
/// Called when rarity filter dropdown changes
/// </summary>
private void OnRarityFilterChanged(int index)
{
ApplyFilters();
}
/// <summary>
/// Reset all filters to default values
/// </summary>
private void ResetFilters()
{
if (zoneFilterDropdown != null)
zoneFilterDropdown.value = 0;
Tween.AnchoredPosition(rt, offScreenPosition, transitionDuration, 0f,
Tween.EaseInOutStrong, Tween.LoopType.None, null, onComplete);
if (rarityFilterDropdown != null)
rarityFilterDropdown.value = 0;
ApplyFilters();
}
/// <summary>
/// Apply current filter settings to the displayed cards
/// </summary>
private void ApplyFilters()
{
if (_cardManager == null) return;
// Get all cards
List<CardData> allCards = _cardManager.GetAllCollectedCards();
List<CardData> filteredCards = new List<CardData>(allCards);
// Apply zone filter
if (zoneFilterDropdown != null && zoneFilterDropdown.value > 0)
{
CardZone selectedZone = (CardZone)(zoneFilterDropdown.value - 1);
filteredCards = filteredCards.FindAll(card => card.Zone == selectedZone);
}
// Apply rarity filter
if (rarityFilterDropdown != null && rarityFilterDropdown.value > 0)
{
CardRarity selectedRarity = (CardRarity)(rarityFilterDropdown.value - 1);
filteredCards = filteredCards.FindAll(card => card.Rarity == selectedRarity);
}
// Update the displayed cards
ClearAlbum();
SetupAlbumSlots();
CreateCardStack(filteredCards);
}
// Override for transition animations
protected override void DoTransitionIn(System.Action onComplete)
{
// Reset the canvas group
if (canvasGroup != null)
{
canvasGroup.alpha = 0f;
Tween.Value(0f, 1f, (value) => canvasGroup.alpha = value, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete);
}
else
{
onComplete?.Invoke();
// Simple scale animation if no canvas group
transform.localScale = Vector3.zero;
Tween.LocalScale(transform, Vector3.one, transitionDuration, 0f, Tween.EaseOutBack, Tween.LoopType.None, null, onComplete);
}
}
protected override void DoTransitionOut(System.Action onComplete)
{
// Simple fade animation
if (canvasGroup != null)
{
Tween.Value(canvasGroup.alpha, 0f, (value) => canvasGroup.alpha = value, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete);
}
else
{
Tween.LocalScale(transform, Vector3.zero, transitionDuration, 0f, Tween.EaseInBack, Tween.LoopType.None, null, onComplete);
}
}
private void OnDestroy()
{
// Clean up filter listeners
if (zoneFilterDropdown != null)
zoneFilterDropdown.onValueChanged.RemoveListener(OnZoneFilterChanged);
if (rarityFilterDropdown != null)
rarityFilterDropdown.onValueChanged.RemoveListener(OnRarityFilterChanged);
if (resetFiltersButton != null)
resetFiltersButton.onClick.RemoveListener(ResetFilters);
// Clean up card listeners
foreach (var card in _displayedCards)
{
if (card != null)
{
// Unsubscribe from card events
card.OnCardClicked -= OnCardClicked;
// Remove button listeners
Button cardButton = card.GetComponent<Button>();
if (cardButton != null)
{
cardButton.onClick.RemoveAllListeners();
}
}
}
}
}
}