First go at the card UI
This commit is contained in:
committed by
Michal Adam Pikulski
parent
7f3dccf1ea
commit
ed9f2d6c6d
@@ -20,6 +20,12 @@ namespace AppleHills.UI.CardSystem
|
|||||||
[SerializeField] private GameObject cardSlotPrefab;
|
[SerializeField] private GameObject cardSlotPrefab;
|
||||||
[SerializeField] private GameObject cardPrefab;
|
[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
|
// Runtime references
|
||||||
private CardSystemManager _cardManager;
|
private CardSystemManager _cardManager;
|
||||||
private List<CardUIElement> _displayedCards = new List<CardUIElement>();
|
private List<CardUIElement> _displayedCards = new List<CardUIElement>();
|
||||||
@@ -32,6 +38,12 @@ namespace AppleHills.UI.CardSystem
|
|||||||
private void Awake()
|
private void Awake()
|
||||||
{
|
{
|
||||||
_cardManager = CardSystemManager.Instance;
|
_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>
|
/// <summary>
|
||||||
@@ -53,6 +65,9 @@ namespace AppleHills.UI.CardSystem
|
|||||||
// Clear any previous setup
|
// Clear any previous setup
|
||||||
ClearAlbum();
|
ClearAlbum();
|
||||||
|
|
||||||
|
// Setup filter UI
|
||||||
|
InitializeFilters();
|
||||||
|
|
||||||
// Get all collected cards
|
// Get all collected cards
|
||||||
List<CardData> collectedCards = _cardManager.GetAllCollectedCards();
|
List<CardData> collectedCards = _cardManager.GetAllCollectedCards();
|
||||||
|
|
||||||
@@ -160,28 +175,15 @@ namespace AppleHills.UI.CardSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void SetupCardDragHandlers(CardUIElement cardUI)
|
private void SetupCardDragHandlers(CardUIElement cardUI)
|
||||||
{
|
{
|
||||||
// // Get drag handler component (you might need to implement this)
|
// Add click listener to handle card clicks
|
||||||
// DragHandler dragHandler = cardUI.GetComponent<DragHandler>();
|
Button cardButton = cardUI.GetComponent<Button>();
|
||||||
// if (dragHandler == null)
|
if (cardButton != null)
|
||||||
// {
|
{
|
||||||
// // This is a stub for the drag handler
|
cardButton.onClick.AddListener(() => OnCardClicked(cardUI));
|
||||||
// // In a real implementation, you'd have a proper drag handler component
|
}
|
||||||
// // For now, we'll just add click listeners
|
|
||||||
//
|
// Subscribe to the card's own click event
|
||||||
// // Add click listener
|
cardUI.OnCardClicked += OnCardClicked;
|
||||||
// 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>
|
/// <summary>
|
||||||
@@ -198,148 +200,225 @@ namespace AppleHills.UI.CardSystem
|
|||||||
PlaceCardInSlot(cardUI, slot);
|
PlaceCardInSlot(cardUI, slot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles the start of a card drag operation
|
/// Places a card in a specific album slot
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnBeginDragCard(CardUIElement cardUI)
|
private void PlaceCardInSlot(CardUIElement cardUI, Transform slotTransform)
|
||||||
{
|
{
|
||||||
_currentlyDraggedCard = cardUI;
|
if (cardUI == null || slotTransform == null) return;
|
||||||
_cardOriginalPosition = cardUI.transform.position;
|
|
||||||
|
|
||||||
// Bring the card to the front
|
// Save original parent to revert if needed
|
||||||
cardUI.transform.SetAsLastSibling();
|
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>
|
/// <summary>
|
||||||
/// Handles the dragging of a card
|
/// Clears all cards from the album
|
||||||
/// </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>
|
/// </summary>
|
||||||
private void ClearAlbum()
|
private void ClearAlbum()
|
||||||
{
|
{
|
||||||
// Clear displayed cards
|
// Clear card UI elements
|
||||||
foreach (var card in _displayedCards)
|
foreach (var card in _displayedCards)
|
||||||
{
|
{
|
||||||
Destroy(card.gameObject);
|
if (card != null && card.gameObject != null)
|
||||||
|
{
|
||||||
|
Destroy(card.gameObject);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_displayedCards.Clear();
|
_displayedCards.Clear();
|
||||||
|
|
||||||
// Clear album slots
|
// 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();
|
_albumSlots.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Override for transition in animation using Pixelplacement.Tween
|
/// Initialize filtering UI and set up listeners
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected override void DoTransitionIn(System.Action onComplete)
|
private void InitializeFilters()
|
||||||
{
|
{
|
||||||
// Simple slide in animation
|
// Setup zone filter
|
||||||
RectTransform rt = GetComponent<RectTransform>();
|
if (zoneFilterDropdown != null)
|
||||||
if (rt != null)
|
|
||||||
{
|
{
|
||||||
// Store the end position
|
zoneFilterDropdown.ClearOptions();
|
||||||
Vector2 endPosition = rt.anchoredPosition;
|
|
||||||
|
|
||||||
// Set initial position (off-screen to the right)
|
// Add "All Zones" option
|
||||||
rt.anchoredPosition = new Vector2(Screen.width, endPosition.y);
|
List<string> zoneOptions = new List<string> { "All Zones" };
|
||||||
|
|
||||||
// Animate to end position
|
// Add each zone
|
||||||
Tween.AnchoredPosition(rt, endPosition, transitionDuration, 0f,
|
foreach (CardZone zone in System.Enum.GetValues(typeof(CardZone)))
|
||||||
Tween.EaseOutStrong, Tween.LoopType.None, null, onComplete);
|
{
|
||||||
|
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>
|
/// <summary>
|
||||||
/// Override for transition out animation using Pixelplacement.Tween
|
/// Called when zone filter dropdown changes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected override void DoTransitionOut(System.Action onComplete)
|
private void OnZoneFilterChanged(int index)
|
||||||
{
|
{
|
||||||
// Simple slide out animation
|
ApplyFilters();
|
||||||
RectTransform rt = GetComponent<RectTransform>();
|
}
|
||||||
if (rt != null)
|
|
||||||
{
|
/// <summary>
|
||||||
// Animate to off-screen position (to the left)
|
/// Called when rarity filter dropdown changes
|
||||||
Vector2 offScreenPosition = new Vector2(-Screen.width, rt.anchoredPosition.y);
|
/// </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,
|
if (rarityFilterDropdown != null)
|
||||||
Tween.EaseInOutStrong, Tween.LoopType.None, null, onComplete);
|
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
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,22 +20,32 @@ namespace AppleHills.UI.CardSystem
|
|||||||
[SerializeField] private GameObject cardPrefab;
|
[SerializeField] private GameObject cardPrefab;
|
||||||
[SerializeField] private Button openBoosterButton;
|
[SerializeField] private Button openBoosterButton;
|
||||||
[SerializeField] private Button continueButton;
|
[SerializeField] private Button continueButton;
|
||||||
|
[SerializeField] private CanvasGroup canvasGroup;
|
||||||
|
|
||||||
[Header("Animation Settings")]
|
[Header("Animation Settings")]
|
||||||
[SerializeField] private float cardRevealDelay = 0.5f;
|
[SerializeField] private float cardRevealDelay = 0.5f;
|
||||||
[SerializeField] private float cardMoveToBackpackDelay = 1.0f;
|
[SerializeField] private float cardMoveToBackpackDelay = 1.0f;
|
||||||
|
[SerializeField] private Transform backpackTargetTransform;
|
||||||
|
[SerializeField] private AudioSource cardRevealSound;
|
||||||
|
[SerializeField] private AudioSource rareCardSound;
|
||||||
|
[SerializeField] private ParticleSystem cardRevealParticles;
|
||||||
|
[SerializeField] private ParticleSystem rareCardParticles;
|
||||||
|
|
||||||
// State tracking
|
// State tracking
|
||||||
private enum OpeningState
|
private enum OpeningState
|
||||||
{
|
{
|
||||||
BoosterReady,
|
BoosterReady,
|
||||||
|
CardsRevealing,
|
||||||
CardsRevealed,
|
CardsRevealed,
|
||||||
|
MovingToBackpack,
|
||||||
Completed
|
Completed
|
||||||
}
|
}
|
||||||
|
|
||||||
private OpeningState _currentState = OpeningState.BoosterReady;
|
private OpeningState _currentState = OpeningState.BoosterReady;
|
||||||
private List<CardUIElement> _revealedCards = new List<CardUIElement>();
|
private List<CardUIElement> _revealedCards = new List<CardUIElement>();
|
||||||
private CardSystemManager _cardManager;
|
private CardSystemManager _cardManager;
|
||||||
|
private Coroutine _revealCoroutine;
|
||||||
|
private Coroutine _moveToBackpackCoroutine;
|
||||||
|
|
||||||
private void Awake()
|
private void Awake()
|
||||||
{
|
{
|
||||||
@@ -52,6 +62,12 @@ namespace AppleHills.UI.CardSystem
|
|||||||
continueButton.onClick.AddListener(OnContinueClicked);
|
continueButton.onClick.AddListener(OnContinueClicked);
|
||||||
continueButton.gameObject.SetActive(false);
|
continueButton.gameObject.SetActive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure we have a CanvasGroup for transitions
|
||||||
|
if (canvasGroup == null)
|
||||||
|
canvasGroup = GetComponent<CanvasGroup>();
|
||||||
|
if (canvasGroup == null)
|
||||||
|
canvasGroup = gameObject.AddComponent<CanvasGroup>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDestroy()
|
private void OnDestroy()
|
||||||
@@ -66,6 +82,13 @@ namespace AppleHills.UI.CardSystem
|
|||||||
{
|
{
|
||||||
continueButton.onClick.RemoveListener(OnContinueClicked);
|
continueButton.onClick.RemoveListener(OnContinueClicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stop any running coroutines
|
||||||
|
if (_revealCoroutine != null)
|
||||||
|
StopCoroutine(_revealCoroutine);
|
||||||
|
|
||||||
|
if (_moveToBackpackCoroutine != null)
|
||||||
|
StopCoroutine(_moveToBackpackCoroutine);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -86,7 +109,8 @@ namespace AppleHills.UI.CardSystem
|
|||||||
// Clear any previously revealed cards
|
// Clear any previously revealed cards
|
||||||
foreach (var card in _revealedCards)
|
foreach (var card in _revealedCards)
|
||||||
{
|
{
|
||||||
Destroy(card.gameObject);
|
if (card != null && card.gameObject != null)
|
||||||
|
Destroy(card.gameObject);
|
||||||
}
|
}
|
||||||
_revealedCards.Clear();
|
_revealedCards.Clear();
|
||||||
|
|
||||||
@@ -117,6 +141,8 @@ namespace AppleHills.UI.CardSystem
|
|||||||
{
|
{
|
||||||
if (_currentState != OpeningState.BoosterReady) return;
|
if (_currentState != OpeningState.BoosterReady) return;
|
||||||
|
|
||||||
|
_currentState = OpeningState.CardsRevealing;
|
||||||
|
|
||||||
// Open the booster pack and get the cards
|
// Open the booster pack and get the cards
|
||||||
List<CardData> newCards = _cardManager.OpenBoosterPack();
|
List<CardData> newCards = _cardManager.OpenBoosterPack();
|
||||||
|
|
||||||
@@ -125,7 +151,10 @@ namespace AppleHills.UI.CardSystem
|
|||||||
// Hide the booster pack and open button
|
// Hide the booster pack and open button
|
||||||
if (boosterPackObject != null)
|
if (boosterPackObject != null)
|
||||||
{
|
{
|
||||||
boosterPackObject.SetActive(false);
|
// Animate the booster pack opening
|
||||||
|
Tween.LocalScale(boosterPackObject.transform, Vector3.zero, 0.3f, 0f, Tween.EaseInBack, Tween.LoopType.None, null, () => {
|
||||||
|
boosterPackObject.SetActive(false);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (openBoosterButton != null)
|
if (openBoosterButton != null)
|
||||||
@@ -134,7 +163,7 @@ namespace AppleHills.UI.CardSystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start revealing cards
|
// Start revealing cards
|
||||||
StartCoroutine(RevealCards(newCards));
|
_revealCoroutine = StartCoroutine(RevealCards(newCards));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -173,6 +202,38 @@ namespace AppleHills.UI.CardSystem
|
|||||||
// Call card's show animation
|
// Call card's show animation
|
||||||
cardUI.OnShowAnimation();
|
cardUI.OnShowAnimation();
|
||||||
|
|
||||||
|
// Play appropriate sound and particles based on rarity
|
||||||
|
if (cardData.Rarity >= CardRarity.Rare)
|
||||||
|
{
|
||||||
|
// Play rare card sound
|
||||||
|
if (rareCardSound != null)
|
||||||
|
{
|
||||||
|
rareCardSound.Play();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Play rare card particles
|
||||||
|
if (rareCardParticles != null)
|
||||||
|
{
|
||||||
|
rareCardParticles.transform.position = cardObj.transform.position;
|
||||||
|
rareCardParticles.Play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Play regular card sound
|
||||||
|
if (cardRevealSound != null)
|
||||||
|
{
|
||||||
|
cardRevealSound.Play();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Play regular particles
|
||||||
|
if (cardRevealParticles != null)
|
||||||
|
{
|
||||||
|
cardRevealParticles.transform.position = cardObj.transform.position;
|
||||||
|
cardRevealParticles.Play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Wait for animation delay
|
// Wait for animation delay
|
||||||
yield return new WaitForSeconds(cardRevealDelay);
|
yield return new WaitForSeconds(cardRevealDelay);
|
||||||
}
|
}
|
||||||
@@ -183,6 +244,10 @@ namespace AppleHills.UI.CardSystem
|
|||||||
if (continueButton != null)
|
if (continueButton != null)
|
||||||
{
|
{
|
||||||
continueButton.gameObject.SetActive(true);
|
continueButton.gameObject.SetActive(true);
|
||||||
|
|
||||||
|
// Animate button appearance
|
||||||
|
continueButton.transform.localScale = Vector3.zero;
|
||||||
|
Tween.LocalScale(continueButton.transform, Vector3.one, 0.3f, 0f, Tween.EaseOutBack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,8 +258,15 @@ namespace AppleHills.UI.CardSystem
|
|||||||
{
|
{
|
||||||
if (_currentState != OpeningState.CardsRevealed) return;
|
if (_currentState != OpeningState.CardsRevealed) return;
|
||||||
|
|
||||||
|
_currentState = OpeningState.MovingToBackpack;
|
||||||
|
|
||||||
|
if (continueButton != null)
|
||||||
|
{
|
||||||
|
continueButton.gameObject.SetActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
// Start moving cards to backpack animation
|
// Start moving cards to backpack animation
|
||||||
StartCoroutine(MoveCardsToBackpack());
|
_moveToBackpackCoroutine = StartCoroutine(MoveCardsToBackpack());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -202,48 +274,46 @@ namespace AppleHills.UI.CardSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private IEnumerator MoveCardsToBackpack()
|
private IEnumerator MoveCardsToBackpack()
|
||||||
{
|
{
|
||||||
// Hide continue button
|
// If no backpack target, use a default position (lower-right corner)
|
||||||
if (continueButton != null)
|
Vector3 targetPosition = (backpackTargetTransform != null)
|
||||||
|
? backpackTargetTransform.position
|
||||||
|
: new Vector3(Screen.width * 0.9f, Screen.height * 0.1f, 0f);
|
||||||
|
|
||||||
|
// Move each card to backpack with animation
|
||||||
|
foreach (var cardUI in _revealedCards)
|
||||||
{
|
{
|
||||||
continueButton.gameObject.SetActive(false);
|
if (cardUI != null)
|
||||||
|
{
|
||||||
|
// Call card's move to backpack animation
|
||||||
|
cardUI.OnMoveToBackpackAnimation();
|
||||||
|
|
||||||
|
// Animate movement to backpack
|
||||||
|
Tween.Position(cardUI.transform, targetPosition, 0.5f, 0f, Tween.EaseInBack);
|
||||||
|
Tween.LocalScale(cardUI.transform, Vector3.zero, 0.5f, 0f, Tween.EaseInBack);
|
||||||
|
|
||||||
|
// Wait for delay between cards
|
||||||
|
yield return new WaitForSeconds(0.2f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get corner position for backpack (bottom left)
|
// Wait for final animation
|
||||||
Vector3 cornerPosition = new Vector3(-Screen.width/2 + 50, -Screen.height/2 + 50, 0);
|
yield return new WaitForSeconds(0.5f);
|
||||||
|
|
||||||
// Animate each card moving to the backpack
|
// Update state to completed
|
||||||
foreach (var card in _revealedCards)
|
|
||||||
{
|
|
||||||
// Play move to backpack animation using Pixelplacement.Tween
|
|
||||||
Tween.Position(card.transform, cornerPosition, 0.5f, 0f, Tween.EaseInBack);
|
|
||||||
Tween.LocalScale(card.transform, Vector3.zero, 0.5f, 0f, Tween.EaseInBack);
|
|
||||||
|
|
||||||
// Call card's move to backpack animation
|
|
||||||
card.OnMoveToBackpackAnimation();
|
|
||||||
|
|
||||||
// Wait for animation delay
|
|
||||||
yield return new WaitForSeconds(cardMoveToBackpackDelay);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait a moment before completing
|
|
||||||
yield return new WaitForSeconds(0.3f);
|
|
||||||
|
|
||||||
// Complete the process and return to previous page
|
|
||||||
_currentState = OpeningState.Completed;
|
_currentState = OpeningState.Completed;
|
||||||
|
|
||||||
|
// Return to previous page
|
||||||
UIPageController.Instance.PopPage();
|
UIPageController.Instance.PopPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
// Override for transition animations
|
||||||
/// Override for transition in animation using Pixelplacement.Tween
|
|
||||||
/// </summary>
|
|
||||||
protected override void DoTransitionIn(System.Action onComplete)
|
protected override void DoTransitionIn(System.Action onComplete)
|
||||||
{
|
{
|
||||||
// Scale in animation for the booster pack
|
// Simple fade in animation
|
||||||
if (boosterPackObject != null)
|
if (canvasGroup != null)
|
||||||
{
|
{
|
||||||
boosterPackObject.transform.localScale = Vector3.zero;
|
canvasGroup.alpha = 0f;
|
||||||
Tween.LocalScale(boosterPackObject.transform, Vector3.one, transitionDuration, 0f,
|
Tween.Value(0f, 1f, (value) => canvasGroup.alpha = value, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete);
|
||||||
Tween.EaseOutBack, Tween.LoopType.None, null, onComplete);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -251,17 +321,12 @@ namespace AppleHills.UI.CardSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Override for transition out animation using Pixelplacement.Tween
|
|
||||||
/// </summary>
|
|
||||||
protected override void DoTransitionOut(System.Action onComplete)
|
protected override void DoTransitionOut(System.Action onComplete)
|
||||||
{
|
{
|
||||||
// Fade out animation using a CanvasGroup if available
|
// Simple fade out animation
|
||||||
CanvasGroup canvasGroup = GetComponent<CanvasGroup>();
|
|
||||||
if (canvasGroup != null)
|
if (canvasGroup != null)
|
||||||
{
|
{
|
||||||
Tween.Value(canvasGroup.alpha, 0f, (value) => canvasGroup.alpha = value,
|
Tween.Value(canvasGroup.alpha, 0f, (value) => canvasGroup.alpha = value, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete);
|
||||||
transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using AppleHills.Data.CardSystem;
|
using AppleHills.Data.CardSystem;
|
||||||
using Core;
|
using Core;
|
||||||
using Data.CardSystem;
|
using Data.CardSystem;
|
||||||
|
using Pixelplacement;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
|
|
||||||
@@ -22,10 +24,19 @@ namespace AppleHills.UI.CardSystem
|
|||||||
[Header("UI Elements")]
|
[Header("UI Elements")]
|
||||||
[SerializeField] private Button backpackButton;
|
[SerializeField] private Button backpackButton;
|
||||||
[SerializeField] private Text boosterCountText;
|
[SerializeField] private Text boosterCountText;
|
||||||
|
[SerializeField] private GameObject notificationDot;
|
||||||
|
[SerializeField] private GameObject backpackAnimationTarget;
|
||||||
|
[SerializeField] private GameObject newCardNotification;
|
||||||
|
|
||||||
|
[Header("Notification Settings")]
|
||||||
|
[SerializeField] private float notificationDuration = 3f;
|
||||||
|
[SerializeField] private AudioSource notificationSound;
|
||||||
|
|
||||||
private UIPageController _pageController;
|
private UIPageController _pageController;
|
||||||
private CardSystemManager _cardManager;
|
private CardSystemManager _cardManager;
|
||||||
private bool _isInitialized = false;
|
private bool _isInitialized = false;
|
||||||
|
private bool _hasUnseenCards = false;
|
||||||
|
private Coroutine _notificationCoroutine;
|
||||||
|
|
||||||
private void Awake()
|
private void Awake()
|
||||||
{
|
{
|
||||||
@@ -49,6 +60,13 @@ namespace AppleHills.UI.CardSystem
|
|||||||
|
|
||||||
// Initially show only the backpack icon
|
// Initially show only the backpack icon
|
||||||
ShowOnlyBackpackIcon();
|
ShowOnlyBackpackIcon();
|
||||||
|
|
||||||
|
// Hide notifications initially
|
||||||
|
if (notificationDot != null)
|
||||||
|
notificationDot.SetActive(false);
|
||||||
|
|
||||||
|
if (newCardNotification != null)
|
||||||
|
newCardNotification.SetActive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Start()
|
private void Start()
|
||||||
@@ -60,6 +78,11 @@ namespace AppleHills.UI.CardSystem
|
|||||||
if (_cardManager != null)
|
if (_cardManager != null)
|
||||||
{
|
{
|
||||||
_cardManager.OnBoosterCountChanged += UpdateBoosterCount;
|
_cardManager.OnBoosterCountChanged += UpdateBoosterCount;
|
||||||
|
_cardManager.OnBoosterOpened += HandleBoosterOpened;
|
||||||
|
_cardManager.OnCardCollected += HandleCardCollected;
|
||||||
|
_cardManager.OnCardRarityUpgraded += HandleCardRarityUpgraded;
|
||||||
|
|
||||||
|
// Initialize UI with current values
|
||||||
UpdateBoosterCount(_cardManager.GetBoosterPackCount());
|
UpdateBoosterCount(_cardManager.GetBoosterPackCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,6 +95,9 @@ namespace AppleHills.UI.CardSystem
|
|||||||
if (_cardManager != null)
|
if (_cardManager != null)
|
||||||
{
|
{
|
||||||
_cardManager.OnBoosterCountChanged -= UpdateBoosterCount;
|
_cardManager.OnBoosterCountChanged -= UpdateBoosterCount;
|
||||||
|
_cardManager.OnBoosterOpened -= HandleBoosterOpened;
|
||||||
|
_cardManager.OnCardCollected -= HandleCardCollected;
|
||||||
|
_cardManager.OnCardRarityUpgraded -= HandleCardRarityUpgraded;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up button listeners
|
// Clean up button listeners
|
||||||
@@ -79,6 +105,10 @@ namespace AppleHills.UI.CardSystem
|
|||||||
{
|
{
|
||||||
backpackButton.onClick.RemoveListener(OnBackpackButtonClicked);
|
backpackButton.onClick.RemoveListener(OnBackpackButtonClicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stop any coroutines
|
||||||
|
if (_notificationCoroutine != null)
|
||||||
|
StopCoroutine(_notificationCoroutine);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -114,10 +144,20 @@ namespace AppleHills.UI.CardSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnBackpackButtonClicked()
|
private void OnBackpackButtonClicked()
|
||||||
{
|
{
|
||||||
|
// Play button sound if available
|
||||||
|
if (notificationSound != null)
|
||||||
|
notificationSound.Play();
|
||||||
|
|
||||||
// If no pages are open, push the main menu
|
// If no pages are open, push the main menu
|
||||||
if (_pageController.CurrentPage == null)
|
if (_pageController.CurrentPage == null)
|
||||||
{
|
{
|
||||||
_pageController.PushPage(mainMenuPage);
|
_pageController.PushPage(mainMenuPage);
|
||||||
|
|
||||||
|
// Clear notification
|
||||||
|
if (notificationDot != null)
|
||||||
|
notificationDot.SetActive(false);
|
||||||
|
|
||||||
|
_hasUnseenCards = false;
|
||||||
}
|
}
|
||||||
else if (_pageController.CurrentPage == mainMenuPage)
|
else if (_pageController.CurrentPage == mainMenuPage)
|
||||||
{
|
{
|
||||||
@@ -170,10 +210,60 @@ namespace AppleHills.UI.CardSystem
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logging.Debug("[CardAlbumUI] No booster packs available");
|
Logging.Debug("[CardAlbumUI] No booster packs available");
|
||||||
// TODO: Show "no boosters available" message
|
ShowNoBoostersNotification();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shows a notification that no booster packs are available
|
||||||
|
/// </summary>
|
||||||
|
private void ShowNoBoostersNotification()
|
||||||
|
{
|
||||||
|
if (newCardNotification != null)
|
||||||
|
{
|
||||||
|
// Set notification text
|
||||||
|
Text notificationText = newCardNotification.GetComponentInChildren<Text>();
|
||||||
|
if (notificationText != null)
|
||||||
|
notificationText.text = "No booster packs available!";
|
||||||
|
|
||||||
|
// Show and animate the notification
|
||||||
|
ShowTemporaryNotification(newCardNotification);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shows a notification temporarily and then hides it
|
||||||
|
/// </summary>
|
||||||
|
private void ShowTemporaryNotification(GameObject notification)
|
||||||
|
{
|
||||||
|
if (notification == null) return;
|
||||||
|
|
||||||
|
// Stop any existing notification coroutine
|
||||||
|
if (_notificationCoroutine != null)
|
||||||
|
StopCoroutine(_notificationCoroutine);
|
||||||
|
|
||||||
|
// Start new notification coroutine
|
||||||
|
_notificationCoroutine = StartCoroutine(ShowNotificationCoroutine(notification));
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerator ShowNotificationCoroutine(GameObject notification)
|
||||||
|
{
|
||||||
|
// Show notification
|
||||||
|
notification.SetActive(true);
|
||||||
|
notification.transform.localScale = Vector3.zero;
|
||||||
|
|
||||||
|
// Animate in
|
||||||
|
Tween.LocalScale(notification.transform, Vector3.one, 0.3f, 0f, Tween.EaseOutBack);
|
||||||
|
|
||||||
|
// Wait for duration
|
||||||
|
yield return new WaitForSeconds(notificationDuration);
|
||||||
|
|
||||||
|
// Animate out
|
||||||
|
Tween.LocalScale(notification.transform, Vector3.zero, 0.3f, 0f, Tween.EaseInBack, Tween.LoopType.None, null, () => {
|
||||||
|
notification.SetActive(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the booster count display
|
/// Updates the booster count display
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -182,7 +272,58 @@ namespace AppleHills.UI.CardSystem
|
|||||||
if (boosterCountText != null)
|
if (boosterCountText != null)
|
||||||
{
|
{
|
||||||
boosterCountText.text = count.ToString();
|
boosterCountText.text = count.ToString();
|
||||||
|
|
||||||
|
// Animate the text for feedback
|
||||||
|
boosterCountText.transform.localScale = Vector3.one * 1.2f;
|
||||||
|
Tween.LocalScale(boosterCountText.transform, Vector3.one, 0.3f, 0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles event when a booster pack is opened
|
||||||
|
/// </summary>
|
||||||
|
private void HandleBoosterOpened(System.Collections.Generic.List<CardData> cards)
|
||||||
|
{
|
||||||
|
Logging.Debug($"[CardAlbumUI] Booster opened with {cards.Count} cards");
|
||||||
|
// The booster opening page handles the UI for this event
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles event when a new card is collected
|
||||||
|
/// </summary>
|
||||||
|
private void HandleCardCollected(CardData card)
|
||||||
|
{
|
||||||
|
// If we're not in the album view or booster opening view,
|
||||||
|
// show a notification dot on the backpack
|
||||||
|
if (_pageController.CurrentPage != albumViewPage &&
|
||||||
|
_pageController.CurrentPage != boosterOpeningPage)
|
||||||
|
{
|
||||||
|
_hasUnseenCards = true;
|
||||||
|
if (notificationDot != null)
|
||||||
|
notificationDot.SetActive(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logging.Debug($"[CardAlbumUI] New card collected: {card.Name}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles event when a card is upgraded to a higher rarity
|
||||||
|
/// </summary>
|
||||||
|
private void HandleCardRarityUpgraded(CardData card)
|
||||||
|
{
|
||||||
|
// Show a special notification for rarity upgrade
|
||||||
|
if (newCardNotification != null)
|
||||||
|
{
|
||||||
|
// Set notification text
|
||||||
|
Text notificationText = newCardNotification.GetComponentInChildren<Text>();
|
||||||
|
if (notificationText != null)
|
||||||
|
notificationText.text = $"{card.Name} upgraded to {card.Rarity}!";
|
||||||
|
|
||||||
|
// Show and animate the notification
|
||||||
|
ShowTemporaryNotification(newCardNotification);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logging.Debug($"[CardAlbumUI] Card upgraded: {card.Name} to {card.Rarity}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
306
docs/card_system_ui_setup_guide.md
Normal file
306
docs/card_system_ui_setup_guide.md
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
# Card System UI Setup Guide
|
||||||
|
|
||||||
|
This guide provides detailed instructions for setting up the Card System UI in Unity, organized into prefabs that can be easily maintained and modified.
|
||||||
|
|
||||||
|
## Prefab Structure Overview
|
||||||
|
|
||||||
|
The card system UI should be structured with a modular prefab approach:
|
||||||
|
|
||||||
|
1. **Main Card System Prefab** - Contains the CardAlbumUI component and core structure
|
||||||
|
2. **Individual UI Page Prefabs** - Each page as its own prefab
|
||||||
|
3. **Card UI Prefabs** - For cards and card slots
|
||||||
|
|
||||||
|
## Detailed Prefab Structure
|
||||||
|
|
||||||
|
### Main CardSystem Prefab
|
||||||
|
|
||||||
|
```
|
||||||
|
CardSystem (with CardAlbumUI component)
|
||||||
|
├── BackpackIcon (GameObject)
|
||||||
|
│ ├── BackpackImage (Image)
|
||||||
|
│ ├── BoosterCountText (Text)
|
||||||
|
│ └── NotificationDot (GameObject with Image)
|
||||||
|
├── UIPageController (automatically added by CardAlbumUI if not present)
|
||||||
|
└── Notifications (GameObject)
|
||||||
|
└── NewCardNotification (GameObject)
|
||||||
|
├── Background (Image)
|
||||||
|
└── Text (Text)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Page Prefabs
|
||||||
|
|
||||||
|
**1. MainMenuPage Prefab:**
|
||||||
|
```
|
||||||
|
MainMenuPage (with CardMenuPage component & CanvasGroup)
|
||||||
|
├── Background (Image)
|
||||||
|
├── Title (Text)
|
||||||
|
├── OpenBoosterButton (Button)
|
||||||
|
│ └── Text (Text)
|
||||||
|
├── ViewAlbumButton (Button)
|
||||||
|
│ └── Text (Text)
|
||||||
|
├── ChangeClothesButton (Button)
|
||||||
|
│ └── Text (Text)
|
||||||
|
└── NoBoostersMessage (GameObject)
|
||||||
|
└── Text (Text)
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. AlbumViewPage Prefab:**
|
||||||
|
```
|
||||||
|
AlbumViewPage (with AlbumViewPage component & CanvasGroup)
|
||||||
|
├── Background (Image)
|
||||||
|
├── FilterPanel (GameObject)
|
||||||
|
│ ├── ZoneFilterDropdown (Dropdown)
|
||||||
|
│ │ ├── Label (Text)
|
||||||
|
│ │ └── Arrow (Image)
|
||||||
|
│ ├── RarityFilterDropdown (Dropdown)
|
||||||
|
│ │ ├── Label (Text)
|
||||||
|
│ │ └── Arrow (Image)
|
||||||
|
│ └── ResetFiltersButton (Button)
|
||||||
|
│ └── Text (Text)
|
||||||
|
├── AlbumScrollView (ScrollRect)
|
||||||
|
│ └── AlbumGrid (GridLayoutGroup)
|
||||||
|
├── CardStackContainer (RectTransform)
|
||||||
|
└── EmptyAlbumMessage (GameObject)
|
||||||
|
└── Text (Text)
|
||||||
|
```
|
||||||
|
|
||||||
|
**3. BoosterOpeningPage Prefab:**
|
||||||
|
```
|
||||||
|
BoosterOpeningPage (with BoosterOpeningPage component & CanvasGroup)
|
||||||
|
├── Background (Image)
|
||||||
|
├── BoosterPackObject (GameObject)
|
||||||
|
│ └── BoosterImage (Image)
|
||||||
|
├── CardRevealTransform (Transform)
|
||||||
|
├── OpenBoosterButton (Button)
|
||||||
|
│ └── Text (Text)
|
||||||
|
├── ContinueButton (Button)
|
||||||
|
│ └── Text (Text)
|
||||||
|
├── CardRevealSound (AudioSource)
|
||||||
|
├── RareCardSound (AudioSource)
|
||||||
|
├── CardRevealParticles (ParticleSystem)
|
||||||
|
└── RareCardParticles (ParticleSystem)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Card-Related Prefabs
|
||||||
|
|
||||||
|
**1. CardSlotPrefab:**
|
||||||
|
```
|
||||||
|
CardSlot (GameObject)
|
||||||
|
├── Background (Image)
|
||||||
|
└── SlotLabel (Text)
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. CardPrefab:**
|
||||||
|
```
|
||||||
|
Card (with CardUIElement component & Button)
|
||||||
|
├── CardBackground (Image)
|
||||||
|
├── CardFrame (Image)
|
||||||
|
├── CardImage (Image)
|
||||||
|
├── CardNameText (Text)
|
||||||
|
├── CardDescriptionText (Text)
|
||||||
|
├── ZoneLabel (Text)
|
||||||
|
└── RarityIndicator (Image)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Component Setup Guide
|
||||||
|
|
||||||
|
### CardAlbumUI Component Setup
|
||||||
|
|
||||||
|
This is the central controller for the card system:
|
||||||
|
|
||||||
|
```
|
||||||
|
CardAlbumUI Component Inspector:
|
||||||
|
- UI References:
|
||||||
|
- Backpack Icon: [BackpackIcon GameObject]
|
||||||
|
- Main Menu Page: [MainMenuPage Prefab]
|
||||||
|
- Album View Page: [AlbumViewPage Prefab]
|
||||||
|
- Booster Opening Page: [BoosterOpeningPage Prefab]
|
||||||
|
- UI Elements:
|
||||||
|
- Backpack Button: [BackpackIcon Button Component]
|
||||||
|
- Booster Count Text: [BoosterCountText Component]
|
||||||
|
- Notification Dot: [NotificationDot GameObject]
|
||||||
|
- Backpack Animation Target: [BackpackIcon Transform]
|
||||||
|
- New Card Notification: [NewCardNotification GameObject]
|
||||||
|
- Notification Settings:
|
||||||
|
- Notification Duration: 3 seconds (adjustable)
|
||||||
|
- Notification Sound: [AudioSource Component]
|
||||||
|
```
|
||||||
|
|
||||||
|
### CardMenuPage Component Setup
|
||||||
|
|
||||||
|
```
|
||||||
|
CardMenuPage Component Inspector:
|
||||||
|
- Menu Options:
|
||||||
|
- Open Booster Button: [OpenBoosterButton]
|
||||||
|
- View Album Button: [ViewAlbumButton]
|
||||||
|
- Change Clothes Button: [ChangeClothesButton]
|
||||||
|
- UI Elements:
|
||||||
|
- Booster Count Text: [BoosterCountText]
|
||||||
|
- No Boosters Message: [NoBoostersMessage]
|
||||||
|
- Canvas Group: [CanvasGroup on this GameObject]
|
||||||
|
```
|
||||||
|
|
||||||
|
### AlbumViewPage Component Setup
|
||||||
|
|
||||||
|
```
|
||||||
|
AlbumViewPage Component Inspector:
|
||||||
|
- Album UI Elements:
|
||||||
|
- Album Grid: [AlbumGrid Component]
|
||||||
|
- Card Stack Container: [CardStackContainer Transform]
|
||||||
|
- Empty Album Message: [EmptyAlbumMessage GameObject]
|
||||||
|
- Card Slot Prefab: [CardSlotPrefab Asset]
|
||||||
|
- Card Prefab: [CardPrefab Asset]
|
||||||
|
- Filter UI:
|
||||||
|
- Zone Filter Dropdown: [ZoneFilterDropdown]
|
||||||
|
- Rarity Filter Dropdown: [RarityFilterDropdown]
|
||||||
|
- Reset Filters Button: [ResetFiltersButton]
|
||||||
|
- Canvas Group: [CanvasGroup on this GameObject]
|
||||||
|
```
|
||||||
|
|
||||||
|
### BoosterOpeningPage Component Setup
|
||||||
|
|
||||||
|
```
|
||||||
|
BoosterOpeningPage Component Inspector:
|
||||||
|
- UI Elements:
|
||||||
|
- Booster Pack Object: [BoosterPackObject]
|
||||||
|
- Card Reveal Transform: [CardRevealTransform]
|
||||||
|
- Card Prefab: [CardPrefab Asset]
|
||||||
|
- Open Booster Button: [OpenBoosterButton]
|
||||||
|
- Continue Button: [ContinueButton]
|
||||||
|
- Canvas Group: [CanvasGroup on this GameObject]
|
||||||
|
- Animation Settings:
|
||||||
|
- Card Reveal Delay: 0.5 (adjustable)
|
||||||
|
- Card Move To Backpack Delay: 1.0 (adjustable)
|
||||||
|
- Backpack Target Transform: [BackpackIcon Transform]
|
||||||
|
- Card Reveal Sound: [CardRevealSound Component]
|
||||||
|
- Rare Card Sound: [RareCardSound Component]
|
||||||
|
- Card Reveal Particles: [CardRevealParticles Component]
|
||||||
|
- Rare Card Particles: [RareCardParticles Component]
|
||||||
|
```
|
||||||
|
|
||||||
|
### CardUIElement Component Setup
|
||||||
|
|
||||||
|
```
|
||||||
|
CardUIElement Component Inspector:
|
||||||
|
- Card UI Elements:
|
||||||
|
- Card Background Image: [CardBackground Image]
|
||||||
|
- Card Frame Image: [CardFrame Image]
|
||||||
|
- Card Image: [CardImage]
|
||||||
|
- Card Name Text: [CardNameText]
|
||||||
|
- Card Description Text: [CardDescriptionText]
|
||||||
|
- Zone Label: [ZoneLabel Text]
|
||||||
|
- Rarity Label: [RarityIndicator Image]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Prefab Creation Process
|
||||||
|
|
||||||
|
### 1. Create Card-Related Prefabs First
|
||||||
|
|
||||||
|
Start by creating the card prefabs since other prefabs will reference them:
|
||||||
|
|
||||||
|
1. **Create CardSlotPrefab**:
|
||||||
|
- Create GameObject → UI → Image
|
||||||
|
- Add Text component for slot label
|
||||||
|
- Adjust visual appearance for an empty slot
|
||||||
|
- Save as prefab
|
||||||
|
|
||||||
|
2. **Create CardPrefab**:
|
||||||
|
- Create GameObject → UI → Image (for background)
|
||||||
|
- Add child Images for frame and card art
|
||||||
|
- Add Text components for name, description, zone
|
||||||
|
- Add CardUIElement script
|
||||||
|
- Configure Inspector references
|
||||||
|
- Add Button component
|
||||||
|
- Save as prefab
|
||||||
|
|
||||||
|
### 2. Create UI Page Prefabs
|
||||||
|
|
||||||
|
Create each page prefab individually:
|
||||||
|
|
||||||
|
1. **Create MainMenuPage Prefab**:
|
||||||
|
- Set up UI elements as shown in structure
|
||||||
|
- Add CardMenuPage script
|
||||||
|
- Add CanvasGroup component
|
||||||
|
- Configure all Inspector references
|
||||||
|
- Save as prefab
|
||||||
|
|
||||||
|
2. **Create AlbumViewPage Prefab**:
|
||||||
|
- Set up UI elements as shown in structure
|
||||||
|
- Add AlbumViewPage script
|
||||||
|
- Add CanvasGroup component
|
||||||
|
- Configure all Inspector references
|
||||||
|
- Assign CardSlotPrefab and CardPrefab
|
||||||
|
- Save as prefab
|
||||||
|
|
||||||
|
3. **Create BoosterOpeningPage Prefab**:
|
||||||
|
- Set up UI elements as shown in structure
|
||||||
|
- Add BoosterOpeningPage script
|
||||||
|
- Add CanvasGroup component
|
||||||
|
- Add audio sources and particle systems
|
||||||
|
- Configure all Inspector references
|
||||||
|
- Assign CardPrefab
|
||||||
|
- Save as prefab
|
||||||
|
|
||||||
|
### 3. Create Main CardSystem Prefab
|
||||||
|
|
||||||
|
Finally, create the main controller prefab:
|
||||||
|
|
||||||
|
1. **Create CardSystem GameObject**:
|
||||||
|
- Add CardAlbumUI script
|
||||||
|
- Set up BackpackIcon and Notifications as shown in structure
|
||||||
|
- Assign references to page prefabs (not instances)
|
||||||
|
- Configure all Inspector references
|
||||||
|
- Save as prefab
|
||||||
|
|
||||||
|
## Scene Setup Instructions
|
||||||
|
|
||||||
|
### 1. Add CardSystem to Your Scene
|
||||||
|
|
||||||
|
1. Drag the CardSystem prefab into your scene
|
||||||
|
2. Make sure it's on the UI layer
|
||||||
|
3. Verify it has a Canvas component if needed (or is under a Canvas)
|
||||||
|
|
||||||
|
### 2. Configure the CardSystemManager
|
||||||
|
|
||||||
|
1. Create a GameObject named "CardSystemManager" if not already present
|
||||||
|
2. Add the CardSystemManager script
|
||||||
|
3. Populate it with some test card definitions
|
||||||
|
4. Ensure it's marked as DontDestroyOnLoad if needed
|
||||||
|
|
||||||
|
### 3. Test the System
|
||||||
|
|
||||||
|
1. Enter Play mode
|
||||||
|
2. Test clicking the backpack icon
|
||||||
|
3. Add test booster packs: `CardSystemManager.Instance.AddBoosterPack(3)`
|
||||||
|
4. Test opening boosters and viewing the album
|
||||||
|
|
||||||
|
## Additional Tips
|
||||||
|
|
||||||
|
1. **Canvas Settings**:
|
||||||
|
- Set your Canvas to Screen Space - Overlay
|
||||||
|
- Use Scale With Screen Size with reference resolution 1920x1080
|
||||||
|
- Configure the Canvas Scaler for proper UI scaling
|
||||||
|
|
||||||
|
2. **UI Navigation**:
|
||||||
|
- Configure button navigation for keyboard/controller support
|
||||||
|
- Set tab order for accessibility
|
||||||
|
|
||||||
|
3. **Audio Setup**:
|
||||||
|
- Keep audio sources on the respective UI elements
|
||||||
|
- Adjust spatial blend to 0 (2D) for UI sounds
|
||||||
|
- Use appropriate volume for notification sounds
|
||||||
|
|
||||||
|
4. **Animation Considerations**:
|
||||||
|
- All animations use Pixelplacement.Tween
|
||||||
|
- Adjust animation durations in Inspector for fine-tuning
|
||||||
|
- Consider creating animation presets for consistent feel
|
||||||
|
|
||||||
|
5. **Testing on Different Devices**:
|
||||||
|
- Test the UI on different aspect ratios
|
||||||
|
- Ensure UI elements are anchored properly for different resolutions
|
||||||
|
- Use the Device Simulator to test mobile layouts if targeting mobile
|
||||||
|
|
||||||
|
6. **Performance Tips**:
|
||||||
|
- Consider object pooling for cards in large collections
|
||||||
|
- Disable raycast targets on non-interactive elements
|
||||||
|
- Use sprite atlases for card images
|
||||||
Reference in New Issue
Block a user