Files
AppleHillsProduction/Assets/Scripts/UI/CardSystem/AlbumViewPage.cs

346 lines
12 KiB
C#
Raw Normal View History

using System.Collections.Generic;
using AppleHills.Data.CardSystem;
using Core;
2025-10-14 14:57:50 +02:00
using Data.CardSystem;
using Pixelplacement;
using UnityEngine;
using UnityEngine.UI;
namespace AppleHills.UI.CardSystem
{
/// <summary>
/// UI page for viewing and organizing the player's card collection in an album.
/// </summary>
public class AlbumViewPage : UIPage
{
[Header("Album UI Elements")]
[SerializeField] private GridLayoutGroup albumGrid;
[SerializeField] private RectTransform cardStackContainer;
[SerializeField] private GameObject emptyAlbumMessage;
[SerializeField] private GameObject cardSlotPrefab;
[SerializeField] private GameObject cardPrefab;
// Runtime references
private CardSystemManager _cardManager;
private List<CardUIElement> _displayedCards = new List<CardUIElement>();
private Dictionary<int, Transform> _albumSlots = new Dictionary<int, Transform>();
// Drag and drop handling
private CardUIElement _currentlyDraggedCard = null;
private Vector3 _cardOriginalPosition;
private void Awake()
{
_cardManager = CardSystemManager.Instance;
}
/// <summary>
/// Sets up the album when the page becomes active
/// </summary>
public override void TransitionIn()
{
base.TransitionIn();
// Initialize the album when the page becomes active
InitializeAlbum();
}
/// <summary>
/// Initializes the album with card slots and the player's collection
/// </summary>
private void InitializeAlbum()
{
// Clear any previous setup
ClearAlbum();
// Get all collected cards
List<CardData> collectedCards = _cardManager.GetAllCollectedCards();
// Show/hide empty message based on collection
if (emptyAlbumMessage != null)
{
emptyAlbumMessage.SetActive(collectedCards.Count == 0);
}
if (collectedCards.Count == 0)
{
return;
}
// Set up the album slots
SetupAlbumSlots();
// Create card UI elements for the stack
CreateCardStack(collectedCards);
}
/// <summary>
/// Sets up empty slots in the album grid
/// </summary>
private void SetupAlbumSlots()
{
if (albumGrid == null || cardSlotPrefab == null) return;
// Create predefined slots in the album
// For a simple implementation, we'll create a 5x5 grid of slots
int slotsPerZone = 5; // 5 slots per zone (one row)
int totalZones = System.Enum.GetValues(typeof(CardZone)).Length;
for (int zone = 0; zone < totalZones; zone++)
{
for (int i = 0; i < slotsPerZone; i++)
{
// Create a slot at this position
GameObject slotObj = Instantiate(cardSlotPrefab, albumGrid.transform);
// Calculate the collection index for this slot
int collectionIndex = zone * 100 + i; // Zone*100 + position to ensure unique indices
// Store the slot reference
_albumSlots[collectionIndex] = slotObj.transform;
// Set the slot label (optional)
Text slotLabel = slotObj.GetComponentInChildren<Text>();
if (slotLabel != null)
{
CardZone zoneEnum = (CardZone)zone;
slotLabel.text = $"{zoneEnum} #{i+1}";
}
}
}
}
/// <summary>
/// Creates UI elements for the player's collected cards
/// </summary>
private void CreateCardStack(List<CardData> cards)
{
if (cardStackContainer == null || cardPrefab == null) return;
// Stack offset for visual effect
Vector3 stackOffset = new Vector3(5f, -5f, 0f);
Vector3 basePosition = Vector3.zero;
// Sort cards by collection index
cards.Sort((a, b) => a.CollectionIndex.CompareTo(b.CollectionIndex));
// Create card UI elements
for (int i = 0; i < cards.Count; i++)
{
GameObject cardObj = Instantiate(cardPrefab, cardStackContainer);
CardUIElement cardUI = cardObj.GetComponent<CardUIElement>();
if (cardUI != null)
{
// Position in stack
cardObj.GetComponent<RectTransform>().anchoredPosition = basePosition + (stackOffset * i);
// Set up card data
cardUI.SetupCard(cards[i]);
// Add drag handlers
SetupCardDragHandlers(cardUI);
// Add to tracked cards
_displayedCards.Add(cardUI);
// Check if this card should be placed in a slot already
int collectionIndex = cards[i].CollectionIndex;
if (_albumSlots.TryGetValue(collectionIndex, out Transform slot))
{
// Card has a designated slot, place it there
PlaceCardInSlot(cardUI, slot);
}
}
}
}
/// <summary>
/// Sets up drag and drop handlers for a card
/// </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));
// }
}
/// <summary>
/// Handles when a card is clicked (simplistic alternative to drag and drop)
/// </summary>
private void OnCardClicked(CardUIElement cardUI)
{
CardData cardData = cardUI.GetCardData();
// Find the slot for this card based on collection index
if (_albumSlots.TryGetValue(cardData.CollectionIndex, out Transform slot))
{
// Place the card in its slot
PlaceCardInSlot(cardUI, slot);
}
}
/// <summary>
/// Handles the start of a card drag operation
/// </summary>
private void OnBeginDragCard(CardUIElement cardUI)
{
_currentlyDraggedCard = cardUI;
_cardOriginalPosition = cardUI.transform.position;
// Bring the card to the front
cardUI.transform.SetAsLastSibling();
}
/// <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
/// </summary>
private void ClearAlbum()
{
// Clear displayed cards
foreach (var card in _displayedCards)
{
Destroy(card.gameObject);
}
_displayedCards.Clear();
// Clear album slots
foreach (Transform child in albumGrid.transform)
{
Destroy(child.gameObject);
}
_albumSlots.Clear();
}
/// <summary>
/// Override for transition in animation using Pixelplacement.Tween
/// </summary>
protected override void DoTransitionIn(System.Action onComplete)
{
// Simple slide in animation
RectTransform rt = GetComponent<RectTransform>();
if (rt != null)
{
// Store the end position
Vector2 endPosition = rt.anchoredPosition;
// Set initial position (off-screen to the right)
rt.anchoredPosition = new Vector2(Screen.width, endPosition.y);
// Animate to end position
Tween.AnchoredPosition(rt, endPosition, transitionDuration, 0f,
Tween.EaseOutStrong, Tween.LoopType.None, null, onComplete);
}
else
{
onComplete?.Invoke();
}
}
/// <summary>
/// Override for transition out animation using Pixelplacement.Tween
/// </summary>
protected override void DoTransitionOut(System.Action onComplete)
{
// 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);
Tween.AnchoredPosition(rt, offScreenPosition, transitionDuration, 0f,
Tween.EaseInOutStrong, Tween.LoopType.None, null, onComplete);
}
else
{
onComplete?.Invoke();
}
}
}
}