New card UI, new visual config, new card definitions, new working editor window for authoring!

This commit is contained in:
Michal Pikulski
2025-11-05 23:50:15 +01:00
parent 0dc3f3e803
commit 50c0a12391
65 changed files with 2784 additions and 12389 deletions

View File

@@ -30,7 +30,7 @@ namespace UI.CardSystem
// Runtime references
private CardSystemManager _cardManager;
private List<CardUIElement> _displayedCards = new List<CardUIElement>();
private List<CardDisplay> _displayedCards = new List<CardDisplay>();
private void Awake()
{
@@ -98,12 +98,13 @@ namespace UI.CardSystem
GameObject cardObj = Instantiate(cardPrefab, albumGrid.transform);
// Configure the card UI with the card data
CardUIElement cardUI = cardObj.GetComponent<CardUIElement>();
if (cardUI != null)
{
cardUI.SetupCard(cardData);
_displayedCards.Add(cardUI);
}
// TODO: Update this to use your actual CardDisplay component
// CardUIElement cardUI = cardObj.GetComponent<CardUIElement>();
// if (cardUI != null)
// {
// cardUI.SetupCard(cardData);
// _displayedCards.Add(cardUI);
// }
}
}

View File

@@ -1,186 +0,0 @@
using Pixelplacement;
using Pixelplacement.TweenSystem;
using TMPro;
using UnityEngine;
namespace UI.CardSystem
{
/// <summary>
/// Manages a notification dot that displays a count (e.g., booster packs)
/// Can be reused across different UI elements that need to show numeric notifications
/// </summary>
public class BoosterNotificationDot : MonoBehaviour
{
[Header("UI References")]
[SerializeField] private GameObject dotBackground;
[SerializeField] private TextMeshProUGUI countText;
[Header("Settings")]
[SerializeField] private bool hideWhenZero = true;
[SerializeField] private bool useAnimation = false;
[SerializeField] private string textPrefix = "";
[SerializeField] private string textSuffix = "";
[SerializeField] private Color textColor = Color.white;
[Header("Animation")]
[SerializeField] private bool useTween = true;
[SerializeField] private float pulseDuration = 0.3f;
[SerializeField] private float pulseScale = 1.2f;
// Optional animator reference
[SerializeField] private Animator animator;
[SerializeField] private string animationTrigger = "Update";
// Current count value
private int _currentCount;
private Vector3 _originalScale;
private TweenBase _activeTween;
private void Awake()
{
// Store original scale for pulse animation
if (dotBackground != null)
{
_originalScale = dotBackground.transform.localScale;
}
// Apply text color
if (countText != null)
{
countText.color = textColor;
}
// Initial setup based on current count
SetCount(_currentCount);
}
/// <summary>
/// Sets the count displayed on the notification dot
/// Also handles visibility based on settings
/// </summary>
public void SetCount(int count)
{
bool countChanged = count != _currentCount;
_currentCount = count;
// Update text
if (countText != null)
{
countText.text = textPrefix + count.ToString() + textSuffix;
}
// Handle visibility
if (hideWhenZero)
{
SetVisibility(count > 0);
}
// Play animation if value changed and animation is enabled
if (countChanged && count > 0)
{
if (useAnimation)
{
Animate();
}
}
}
/// <summary>
/// Gets the current count value
/// </summary>
public int GetCount()
{
return _currentCount;
}
/// <summary>
/// Set text formatting options
/// </summary>
public void SetFormatting(string prefix, string suffix, Color color)
{
textPrefix = prefix;
textSuffix = suffix;
textColor = color;
if (countText != null)
{
countText.color = color;
// Update text with new formatting
countText.text = textPrefix + _currentCount.ToString() + textSuffix;
}
}
/// <summary>
/// Explicitly control the notification dot visibility
/// </summary>
public void SetVisibility(bool isVisible)
{
if (dotBackground != null)
{
dotBackground.SetActive(isVisible);
}
if (countText != null)
{
countText.gameObject.SetActive(isVisible);
}
}
/// <summary>
/// Show the notification dot
/// </summary>
public void Show()
{
SetVisibility(true);
}
/// <summary>
/// Hide the notification dot
/// </summary>
public void Hide()
{
SetVisibility(false);
}
/// <summary>
/// Play animation manually - either using Animator or Tween
/// </summary>
public void Animate()
{
if (useAnimation)
{
if (animator != null)
{
animator.SetTrigger(animationTrigger);
}
else if (useTween && dotBackground != null)
{
// Cancel any existing tweens on this transform
_activeTween.Cancel();
// Reset to original scale
dotBackground.transform.localScale = _originalScale;
// Pulse animation using Tween
_activeTween = Tween.LocalScale(dotBackground.transform,
_originalScale * pulseScale,
pulseDuration/2,
0,
Tween.EaseOut,
Tween.LoopType.None,
null,
() => {
// Scale back to original size
Tween.LocalScale(dotBackground.transform,
_originalScale,
pulseDuration/2,
0,
Tween.EaseIn);
},
obeyTimescale: false);
}
}
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: ed8cced1478640229c5a61e3c6bd42df
timeCreated: 1760710148

View File

@@ -1,626 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using AppleHills.Data.CardSystem;
using Core;
using Data.CardSystem;
using Pixelplacement;
using UI.Core;
using UnityEngine;
using UnityEngine.UI;
namespace UI.CardSystem
{
/// <summary>
/// UI page for opening booster packs and displaying the cards obtained.
/// </summary>
public class BoosterOpeningPage : UIPage
{
[Header("UI Elements")]
[SerializeField] private GameObject boosterPackObject;
[SerializeField] private RectTransform cardRevealContainer; // This should have a HorizontalLayoutGroup component with pre-populated card backs
[SerializeField] private GameObject cardPrefab;
[SerializeField] private Button openBoosterButton;
[SerializeField] private Button continueButton;
[SerializeField] private CanvasGroup canvasGroup;
[Header("Navigation")]
[SerializeField] private Button backButton;
[Header("Animation Settings")]
[SerializeField] private float cardRevealDelay = 0.3f;
[SerializeField] private float flipAnimationDuration = 0.5f;
// State tracking
private enum OpeningState
{
BoosterReady,
CardBacksVisible,
CardsRevealing,
CardsRevealed,
MovingToBackpack,
Completed
}
private OpeningState _currentState = OpeningState.BoosterReady;
private List<CardUIElement> _revealedCards = new List<CardUIElement>();
private List<Button> _cardBackButtons = new List<Button>();
private List<CardData> _boosterCards = new List<CardData>();
private int _revealedCardCount = 0;
private CardSystemManager _cardManager;
private CardAlbumUI _cardAlbumUI;
private Coroutine _moveToBackpackCoroutine;
private void Awake()
{
_cardManager = CardSystemManager.Instance;
_cardAlbumUI = FindFirstObjectByType<CardAlbumUI>();
// Set up button listeners
if (openBoosterButton != null)
{
openBoosterButton.onClick.AddListener(OnOpenBoosterClicked);
}
if (continueButton != null)
{
continueButton.onClick.AddListener(OnContinueClicked);
continueButton.gameObject.SetActive(false);
}
// Set up back button
if (backButton != null)
{
backButton.onClick.AddListener(OnBackButtonClicked);
}
// Make sure we have a CanvasGroup for transitions
if (canvasGroup == null)
canvasGroup = GetComponent<CanvasGroup>();
if (canvasGroup == null)
canvasGroup = gameObject.AddComponent<CanvasGroup>();
// Cache card back buttons from container
CacheCardBackButtons();
// Initially hide all card backs
HideAllCardBacks();
}
/// <summary>
/// Cache all card back buttons from the container
/// </summary>
private void CacheCardBackButtons()
{
_cardBackButtons.Clear();
if (cardRevealContainer != null)
{
// Get all buttons in the container (these are our card backs)
Button[] buttonsInContainer = cardRevealContainer.GetComponentsInChildren<Button>(true);
_cardBackButtons.AddRange(buttonsInContainer);
Debug.Log($"[BoosterOpeningPage] Found {_cardBackButtons.Count} card back buttons in container");
}
else
{
Debug.LogError("[BoosterOpeningPage] Card reveal container is null, can't find card backs!");
}
}
/// <summary>
/// Hides all card backs in the container
/// </summary>
private void HideAllCardBacks()
{
foreach (var cardBack in _cardBackButtons)
{
if (cardBack != null && cardBack.gameObject != null)
{
cardBack.gameObject.SetActive(false);
}
}
}
private void OnDestroy()
{
// Clean up button listeners
if (openBoosterButton != null)
{
openBoosterButton.onClick.RemoveListener(OnOpenBoosterClicked);
}
if (continueButton != null)
{
continueButton.onClick.RemoveListener(OnContinueClicked);
}
if (backButton != null)
{
backButton.onClick.RemoveListener(OnBackButtonClicked);
}
// Stop any running coroutines
if (_moveToBackpackCoroutine != null)
StopCoroutine(_moveToBackpackCoroutine);
}
/// <summary>
/// Handles click on the back button
/// </summary>
private void OnBackButtonClicked()
{
// Don't allow going back during animations or card reveals
if (_currentState == OpeningState.CardsRevealing ||
_currentState == OpeningState.MovingToBackpack)
{
return;
}
// Use the UIPageController to go back to the previous page
UIPageController pageController = UIPageController.Instance;
if (pageController != null)
{
pageController.PopPage();
}
}
/// <summary>
/// Resets the page to its initial state when it becomes active
/// </summary>
public override void TransitionIn()
{
base.TransitionIn();
ResetState();
}
/// <summary>
/// Resets the state of the booster opening process
/// </summary>
private void ResetState()
{
// Clear any previously revealed cards
foreach (var card in _revealedCards)
{
if (card != null && card.gameObject != null)
Destroy(card.gameObject);
}
_revealedCards.Clear();
// Re-cache card backs in case they changed
CacheCardBackButtons();
// Reset all card backs - both visibility and scale
foreach (var cardBack in _cardBackButtons)
{
if (cardBack != null && cardBack.gameObject != null)
{
cardBack.gameObject.SetActive(false);
cardBack.transform.localScale = Vector3.one; // Reset scale
cardBack.transform.localRotation = Quaternion.identity; // Reset rotation
}
}
// Reset state
_currentState = OpeningState.BoosterReady;
_revealedCardCount = 0;
_boosterCards.Clear();
// Show booster pack, show open button, hide continue button
if (boosterPackObject != null)
{
boosterPackObject.SetActive(true);
boosterPackObject.transform.localScale = Vector3.one; // Reset scale
boosterPackObject.transform.localRotation = Quaternion.identity; // Reset rotation
}
if (openBoosterButton != null)
{
openBoosterButton.gameObject.SetActive(true);
}
if (continueButton != null)
{
continueButton.gameObject.SetActive(false);
continueButton.transform.localScale = Vector3.one; // Reset scale
}
// Make back button visible
if (backButton != null)
{
backButton.gameObject.SetActive(true);
}
Debug.Log("[BoosterOpeningPage] State reset complete, all scales and rotations reset to defaults");
}
/// <summary>
/// Handles click on the booster pack to open it
/// </summary>
private void OnOpenBoosterClicked()
{
if (_currentState != OpeningState.BoosterReady) return;
_currentState = OpeningState.CardBacksVisible;
// Open the booster pack and get the cards
_boosterCards = _cardManager.OpenBoosterPack();
if (_boosterCards.Count > 0)
{
// Hide the booster pack and open button
if (boosterPackObject != null)
{
// Animate the booster pack opening
Tween.LocalScale(boosterPackObject.transform, Vector3.zero, 0.3f, 0f, Tween.EaseInBack, Tween.LoopType.None, null, () => {
boosterPackObject.SetActive(false);
}, obeyTimescale: false);
}
if (openBoosterButton != null)
{
openBoosterButton.gameObject.SetActive(false);
}
// Show card backs first
StartCoroutine(ShowCardBacks());
}
else
{
Logging.Warning("[BoosterOpeningPage] No cards were obtained from the booster pack.");
UIPageController.Instance.PopPage();
}
}
/// <summary>
/// Shows card backs in the reveal positions
/// </summary>
private IEnumerator ShowCardBacks()
{
// Wait a short delay before showing card backs
yield return new WaitForSeconds(0.5f);
// Check if we have proper container setup
if (cardRevealContainer == null)
{
Debug.LogError("[BoosterOpeningPage] Card reveal container is null!");
yield break;
}
// Check if we found any card backs
if (_cardBackButtons.Count == 0)
{
Debug.LogError("[BoosterOpeningPage] No card back buttons found in container!");
yield break;
}
// Determine how many cards to show based on the booster cards and available card backs
int cardsToShow = Mathf.Min(_boosterCards.Count, _cardBackButtons.Count);
// Activate and animate the card backs
for (int i = 0; i < cardsToShow; i++)
{
Button cardBack = _cardBackButtons[i];
if (cardBack == null) continue;
GameObject cardBackObj = cardBack.gameObject;
// Ensure the card back is active
cardBackObj.SetActive(true);
// Store the index for later reference when clicked
int cardIndex = i;
// Configure the button
cardBack.onClick.RemoveAllListeners(); // Clear any previous listeners
cardBack.onClick.AddListener(() => OnCardBackClicked(cardIndex));
// Set initial scale to zero for animation
cardBackObj.transform.localScale = Vector3.zero;
Debug.Log($"[BoosterOpeningPage] Card back {i} activated");
// Play reveal animation using Pixelplacement.Tween
Tween.LocalScale(cardBackObj.transform, Vector3.one, 0.5f, 0f, Tween.EaseOutBack, obeyTimescale: false);
// Wait for animation delay
yield return new WaitForSeconds(cardRevealDelay);
}
// Update state
_currentState = OpeningState.CardBacksVisible;
Debug.Log($"[BoosterOpeningPage] All {cardsToShow} card backs should now be visible");
}
/// <summary>
/// Handles click on a card back to reveal the card
/// </summary>
private void OnCardBackClicked(int cardIndex)
{
Logging.Debug($"[BoosterOpeningPage] Card back clicked at index {cardIndex}");
// Only respond to clicks when in the appropriate state
if (_currentState != OpeningState.CardBacksVisible)
{
Logging.Warning($"[BoosterOpeningPage] Card clicked in wrong state: {_currentState}");
return;
}
// Ensure the index is valid
if (cardIndex < 0 || cardIndex >= _boosterCards.Count || cardIndex >= _cardBackButtons.Count)
{
Debug.LogError($"[BoosterOpeningPage] Invalid card index: {cardIndex}");
return;
}
// Get the card data and card back
CardData cardData = _boosterCards[cardIndex];
Button cardBack = _cardBackButtons[cardIndex];
// Start the reveal animation for this specific card
StartCoroutine(RevealCard(cardIndex, cardData, cardBack.gameObject));
}
/// <summary>
/// Reveals an individual card with animation
/// </summary>
private IEnumerator RevealCard(int cardIndex, CardData cardData, GameObject cardBack)
{
if (cardBack == null)
yield break;
// Start flip animation
Transform cardBackTransform = cardBack.transform;
// Step 1: Flip the card 90 degrees (showing the edge)
Tween.LocalRotation(cardBackTransform, new Vector3(0, 90, 0), flipAnimationDuration * 0.5f, 0, obeyTimescale: false);
// Wait for half the flip duration
yield return new WaitForSeconds(flipAnimationDuration * 0.5f);
// Step 2: Hide the card back and show the actual card
cardBack.SetActive(false);
// Instantiate the card prefab at the same position
if (cardPrefab != null)
{
// Instantiate the card in the same parent as the card back and at the same position
GameObject cardObj = Instantiate(cardPrefab, cardBack.transform.parent);
cardObj.transform.SetSiblingIndex(cardBackTransform.GetSiblingIndex()); // Keep the same order in hierarchy
cardObj.transform.position = cardBackTransform.position; // Same world position
// Set initial rotation to continue the flip animation
cardObj.transform.localRotation = Quaternion.Euler(0, 90, 0);
// Configure the card UI with the card data
CardUIElement cardUI = cardObj.GetComponent<CardUIElement>();
if (cardUI != null)
{
cardUI.SetupCard(cardData);
_revealedCards.Add(cardUI);
// Play special effects based on card rarity
PlayRevealEffect(cardObj, cardData.Rarity);
}
// Step 3: Finish the flip animation (from 90 degrees to 0)
Tween.LocalRotation(cardObj.transform, Vector3.zero, flipAnimationDuration * 0.5f, 0, obeyTimescale: false);
// Increment counter of revealed cards
_revealedCardCount++;
// Update state if all cards are revealed
if (_revealedCardCount >= _boosterCards.Count)
{
_currentState = OpeningState.CardsRevealed;
// Show continue button after a short delay
StartCoroutine(ShowContinueButton());
}
}
}
/// <summary>
/// Plays reveal effect for a card based on its rarity
/// </summary>
private void PlayRevealEffect(GameObject cardObject, CardRarity rarity)
{
// Add visual effect based on rarity
if (rarity >= CardRarity.Rare)
{
// For rare cards and above, add a particle effect
var particleSystem = cardObject.GetComponentInChildren<ParticleSystem>();
if (particleSystem != null)
{
particleSystem.Play();
}
// Scale up and down for emphasis
Transform cardTransform = cardObject.transform;
Vector3 originalScale = cardTransform.localScale;
// Sequence: Scale up slightly, then back to normal
Tween.LocalScale(cardTransform, originalScale * 1.2f, 0.2f, 0.1f, Tween.EaseOutBack, obeyTimescale: false);
Tween.LocalScale(cardTransform, originalScale, 0.15f, 0.3f, Tween.EaseIn, obeyTimescale: false);
// Play sound effect based on rarity (if available)
// This would require audio source components to be set up
}
}
/// <summary>
/// Shows the continue button after all cards are revealed
/// </summary>
private IEnumerator ShowContinueButton()
{
// Wait for a moment to let the user see all cards
yield return new WaitForSeconds(1.0f);
if (continueButton != null)
{
// Show the continue button with a nice animation
continueButton.gameObject.SetActive(true);
continueButton.transform.localScale = Vector3.zero;
Tween.LocalScale(continueButton.transform, Vector3.one, 0.3f, 0f, Tween.EaseOutBack, obeyTimescale: false);
}
}
/// <summary>
/// Handles click on the continue button
/// </summary>
private void OnContinueClicked()
{
if (_currentState != OpeningState.CardsRevealed) return;
_currentState = OpeningState.MovingToBackpack;
// Hide continue button
if (continueButton != null)
{
continueButton.gameObject.SetActive(false);
}
// Hide back button during transition
if (backButton != null)
{
backButton.gameObject.SetActive(false);
}
// Start animation to move cards to backpack
_moveToBackpackCoroutine = StartCoroutine(MoveCardsToBackpack());
}
/// <summary>
/// Animates cards moving to the backpack icon
/// </summary>
private IEnumerator MoveCardsToBackpack()
{
// Find the backpack button GameObject
GameObject backpackButton = null;
Transform backpackTransform = null;
if (_cardAlbumUI != null && _cardAlbumUI.BackpackIcon != null)
{
// Get the backpack icon
GameObject backpackIcon = _cardAlbumUI.BackpackIcon;
backpackTransform = backpackIcon.transform;
// Find the parent button that controls visibility
backpackButton = backpackIcon.transform.parent.gameObject;
// Make sure the backpack button is visible for the animation
if (backpackButton != null)
{
backpackButton.SetActive(true);
Debug.Log("[BoosterOpeningPage] Made backpack button visible for animation");
}
}
if (backpackTransform == null)
{
// If no backpack is found, just return to the menu
UIPageController.Instance.PopPage();
yield break;
}
// Speed up the animation by reducing the delay
float animationDuration = 0.3f; // Faster animation duration
float cardDelay = 0.15f; // Even shorter delay between cards
// Move each card to the backpack with slight delay between cards
for (int i = 0; i < _revealedCards.Count; i++)
{
CardUIElement card = _revealedCards[i];
if (card != null)
{
// Get the world position of the backpack
Vector3 backpackWorldPos = backpackTransform.position;
// Convert to local space of the card's parent for Tween
Vector3 targetPos = card.transform.parent.InverseTransformPoint(backpackWorldPos);
// Start the move animation - ensure no cancellation between animations
Tween.LocalPosition(card.transform, targetPos, animationDuration, cardDelay * i, Tween.EaseInOut, obeyTimescale: false);
Tween.LocalScale(card.transform, Vector3.zero, animationDuration, cardDelay * i, Tween.EaseIn, obeyTimescale: false);
Debug.Log($"[BoosterOpeningPage] Starting animation for card {i}");
}
// Only wait after starting each animation (don't wait after the last one)
if (i < _revealedCards.Count - 1)
{
yield return new WaitForSeconds(cardDelay);
}
}
// Calculate total animation time and wait for it to complete
float totalAnimationTime = cardDelay * (_revealedCards.Count - 1) + animationDuration;
yield return new WaitForSeconds(totalAnimationTime + 0.1f); // Small buffer to ensure animations complete
// The backpack visibility will be handled by CardAlbumUI's OnPageChanged after popping this page
// We don't need to explicitly hide it here as the system will handle it properly
// Update state
_currentState = OpeningState.Completed;
// Return to the menu
UIPageController.Instance.PopPage();
}
/// <summary>
/// Override for transition in animation using Pixelplacement.Tween
/// </summary>
protected override void DoTransitionIn(System.Action onComplete)
{
// Simple fade in animation
if (canvasGroup != null)
{
canvasGroup.alpha = 0f;
Tween.Value(0f, 1f, (value) => canvasGroup.alpha = value, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete, obeyTimescale: false);
}
else
{
// Fallback if no CanvasGroup
onComplete?.Invoke();
}
}
/// <summary>
/// Override for transition out animation using Pixelplacement.Tween
/// </summary>
protected override void DoTransitionOut(System.Action onComplete)
{
// Simple fade out animation
if (canvasGroup != null)
{
Tween.Value(canvasGroup.alpha, 0f, (value) => canvasGroup.alpha = value, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete, obeyTimescale: false);
}
else
{
// Fallback if no CanvasGroup
onComplete?.Invoke();
}
}
/// <summary>
/// OnEnable override to ensure proper initialization
/// </summary>
private void OnEnable()
{
if (_cardManager == null)
{
_cardManager = CardSystemManager.Instance;
}
if (_cardAlbumUI == null)
{
_cardAlbumUI = FindFirstObjectByType<CardAlbumUI>();
}
// Re-cache card backs in case they changed while disabled
CacheCardBackButtons();
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: f64698442ba344e0a466ee3c530797c7
timeCreated: 1759923862

View File

@@ -1,340 +0,0 @@
using AppleHills.Data.CardSystem;
using Bootstrap;
using Core;
using Data.CardSystem;
using Pixelplacement;
using UI.Core;
using UnityEngine;
using UnityEngine.UI;
namespace UI.CardSystem
{
/// <summary>
/// Main UI controller for the card album system.
/// Manages the backpack icon and navigation between card system pages.
/// </summary>
public class CardAlbumUI : MonoBehaviour
{
[Header("UI References")]
[SerializeField] private GameObject backpackIcon;
[SerializeField] private UIPage mainMenuPage;
[SerializeField] private UIPage albumViewPage;
[SerializeField] private UIPage boosterOpeningPage;
[Header("UI Elements")]
[SerializeField] private Button backpackButton;
[SerializeField] private BoosterNotificationDot boosterNotificationDot;
[Header("Notification Settings")]
[SerializeField] private AudioSource notificationSound;
// Public property to access the backpack icon for animations
public GameObject BackpackIcon => backpackIcon;
private UIPageController PageController => UIPageController.Instance;
private CardSystemManager _cardManager;
private bool _hasUnseenCards;
private void Awake()
{
// Set up backpack button
if (backpackButton != null)
{
backpackButton.onClick.AddListener(OnBackpackButtonClicked);
}
// Hide notification dot initially
if (boosterNotificationDot != null)
boosterNotificationDot.gameObject.SetActive(false);
// Register for post-boot initialization
BootCompletionService.RegisterInitAction(InitializePostBoot);
}
private void InitializePostBoot()
{
// Initially show only the backpack icon
ShowOnlyBackpackIcon();
// Initialize pages and hide them
InitializePages();
// React to global UI hide/show events (top-page only) by toggling this GameObject
if (UIPageController.Instance != null)
{
UIPageController.Instance.OnAllUIHidden += HandleAllUIHidden;
UIPageController.Instance.OnAllUIShown += HandleAllUIShown;
}
}
private void Start()
{
// Get card manager
_cardManager = CardSystemManager.Instance;
// Subscribe to events
if (_cardManager != null)
{
_cardManager.OnBoosterCountChanged += UpdateBoosterCount;
_cardManager.OnBoosterOpened += HandleBoosterOpened;
_cardManager.OnCardCollected += HandleCardCollected;
_cardManager.OnCardRarityUpgraded += HandleCardRarityUpgraded;
// Initialize UI with current values
UpdateBoosterCount(_cardManager.GetBoosterPackCount());
}
}
private void OnDestroy()
{
// Unsubscribe from events
if (_cardManager != null)
{
_cardManager.OnBoosterCountChanged -= UpdateBoosterCount;
_cardManager.OnBoosterOpened -= HandleBoosterOpened;
_cardManager.OnCardCollected -= HandleCardCollected;
_cardManager.OnCardRarityUpgraded -= HandleCardRarityUpgraded;
}
// Clean up button listeners
if (backpackButton != null)
{
backpackButton.onClick.RemoveListener(OnBackpackButtonClicked);
}
// Unsubscribe from page controller events
if (PageController != null)
{
PageController.OnPageChanged -= OnPageChanged;
}
// Unsubscribe from global UI hide/show events
if (UIPageController.Instance != null)
{
UIPageController.Instance.OnAllUIHidden -= HandleAllUIHidden;
UIPageController.Instance.OnAllUIShown -= HandleAllUIShown;
}
}
/// <summary>
/// Initializes all UI pages and sets them up with proper callbacks
/// </summary>
private void InitializePages()
{
// Ensure all pages are inactive at start
if (mainMenuPage != null)
{
mainMenuPage.gameObject.SetActive(false);
}
if (albumViewPage != null)
{
albumViewPage.gameObject.SetActive(false);
}
if (boosterOpeningPage != null)
{
boosterOpeningPage.gameObject.SetActive(false);
}
// Set up page changed callback
if (PageController != null)
{
PageController.OnPageChanged += OnPageChanged;
}
}
/// <summary>
/// Handles click on the backpack icon
/// </summary>
private void OnBackpackButtonClicked()
{
// Play button sound if available
if (notificationSound != null)
notificationSound.Play();
PageController.PushPage(mainMenuPage);
// Clear notification for unseen cards when opening menu
if (_hasUnseenCards)
{
_hasUnseenCards = false;
}
// Hide the backpack button when entering menu
if (backpackButton != null)
{
backpackButton.gameObject.SetActive(false);
}
GameManager.Instance.RequestPause(this);
}
/// <summary>
/// Handles changes to the current page
/// </summary>
private void OnPageChanged(UIPage newPage)
{
// Hide/show backpack icon based on current page
if (newPage == null)
{
ShowOnlyBackpackIcon();
GameManager.Instance.ReleasePause(this);
}
else
{
// Check if any page in the stack has "Card" or "Album" in the name
bool hasCardOrAlbumPage = false;
if (PageController != null && PageController.PageStack != null)
{
foreach (var page in PageController.PageStack)
{
if (page != null && page.PageName != null)
{
if (page.PageName.Contains("Card") || page.PageName.Contains("Album"))
{
hasCardOrAlbumPage = true;
break;
}
}
}
}
// Hide backpack button if there's a card/album page in the stack
if (backpackButton != null)
{
backpackButton.gameObject.SetActive(!hasCardOrAlbumPage);
}
}
// Update menu if it's the main menu page
if (newPage == mainMenuPage && mainMenuPage is CardMenuPage menuPage)
{
// Force UI refresh when returning to main menu
menuPage.RefreshUI();
}
}
/// <summary>
/// Shows only the backpack icon, hiding all other UI elements
/// </summary>
private void ShowOnlyBackpackIcon()
{
if (backpackButton != null)
{
backpackButton.gameObject.SetActive(true);
// Update notification visibility based on booster count
bool hasBooters = _cardManager != null && _cardManager.GetBoosterPackCount() > 0;
// Show notification dot if there are boosters or unseen cards
if (boosterNotificationDot != null)
{
boosterNotificationDot.gameObject.SetActive(hasBooters || _hasUnseenCards);
}
}
}
/// <summary>
/// Opens the album view page
/// </summary>
public void OpenAlbumView()
{
PageController.PushPage(albumViewPage);
}
/// <summary>
/// Opens the booster opening page if boosters are available
/// </summary>
public void OpenBoosterPack()
{
if (_cardManager != null && _cardManager.GetBoosterPackCount() > 0)
{
PageController.PushPage(boosterOpeningPage);
}
else
{
Logging.Debug("[CardAlbumUI] No booster packs available");
}
}
/// <summary>
/// Updates the booster count display
/// </summary>
private void UpdateBoosterCount(int count)
{
if (boosterNotificationDot != null)
{
boosterNotificationDot.SetCount(count);
// Animate the notification dot for feedback
boosterNotificationDot.transform.localScale = Vector3.one * 1.2f;
Tween.LocalScale(boosterNotificationDot.transform, Vector3.one, 0.3f, 0f, obeyTimescale: false);
// Update visibility based on count
UpdateBoosterVisibility();
}
}
/// <summary>
/// Updates the visibility of the booster notification dot based on current state
/// </summary>
private void UpdateBoosterVisibility()
{
if (boosterNotificationDot != null)
{
// Show dot if there are boosters or unseen cards
bool hasBooters = _cardManager != null && _cardManager.GetBoosterPackCount() > 0;
boosterNotificationDot.gameObject.SetActive(hasBooters || _hasUnseenCards);
}
}
/// <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;
UpdateBoosterVisibility();
}
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)
{
// Just log the upgrade event without showing a notification
Logging.Debug($"[CardAlbumUI] Card upgraded: {card.Name} to {card.Rarity}");
}
// Handlers for UI controller hide/show events — toggle this GameObject active state
private void HandleAllUIHidden()
{
// Ensure UI returns to backpack-only state before deactivating so we don't leave the game paused
ShowOnlyBackpackIcon();
backpackButton.gameObject.SetActive(false);
}
private void HandleAllUIShown()
{
backpackButton.gameObject.SetActive(true);
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: fe5ff32f529d4f24a2064ee1dfa07758
timeCreated: 1759923763

View File

@@ -0,0 +1,303 @@
using System;
using AppleHills.Data.CardSystem;
using Core;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
#if UNITY_EDITOR
using UnityEditor;
#endif
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
{
[Header("UI Elements")]
[SerializeField] private TextMeshProUGUI cardNameText;
[SerializeField] private Image cardImage;
[SerializeField] private Image frameImage;
[SerializeField] private Image overlayImage;
[SerializeField] private Image backgroundImage;
[SerializeField] private Image zoneShapeImage;
[Header("Card Data")]
[SerializeField] private CardData cardData;
[Header("Visual Settings")]
[SerializeField] private CardVisualConfig visualConfig;
#if UNITY_EDITOR
[Header("Editor Tools")]
[SerializeField] private CardDefinition editorCardDefinition;
#endif
// Events
public event Action<CardDisplay> OnCardClicked;
/// <summary>
/// Sets up the card display with the given card data
/// </summary>
public void SetupCard(CardData data)
{
if (data == null)
{
Logging.Warning("[CardDisplay] Attempted to setup card with null data");
return;
}
cardData = data;
UpdateCardVisuals();
}
/// <summary>
/// Updates all visual elements based on current card data
/// </summary>
private void UpdateCardVisuals()
{
if (cardData == null)
{
ClearCard();
return;
}
if (visualConfig == null)
{
Logging.Warning("[CardDisplay] No CardVisualConfig assigned. Visuals may not display correctly.");
}
// Update text
UpdateCardName();
// Update main card image
UpdateCardImage();
// Update rarity-based visuals (frame and overlay)
UpdateRarityVisuals();
// Update zone-based visuals (background and shape)
UpdateZoneVisuals();
Logging.Debug($"[CardDisplay] Updated visuals for card: {cardData.Name} (Rarity: {cardData.Rarity}, Zone: {cardData.Zone})");
}
/// <summary>
/// Updates the card name text
/// </summary>
private void UpdateCardName()
{
if (cardNameText != null)
{
cardNameText.text = cardData.Name ?? "Unknown Card";
}
}
/// <summary>
/// Updates the main card image
/// </summary>
private void UpdateCardImage()
{
if (cardImage != null)
{
if (cardData.CardImage != null)
{
cardImage.sprite = cardData.CardImage;
cardImage.enabled = true;
}
else
{
cardImage.sprite = null;
cardImage.enabled = false;
}
}
}
/// <summary>
/// Updates frame and overlay based on card rarity
/// </summary>
private void UpdateRarityVisuals()
{
if (visualConfig == null) return;
// Update frame
if (frameImage != null)
{
Sprite frameSprite = visualConfig.GetRarityFrame(cardData.Rarity);
if (frameSprite != null)
{
frameImage.sprite = frameSprite;
frameImage.enabled = true;
}
else
{
frameImage.enabled = false;
}
}
// Update overlay (can be null for some rarities)
if (overlayImage != null)
{
Sprite overlaySprite = visualConfig.GetRarityOverlay(cardData.Rarity);
if (overlaySprite != null)
{
overlayImage.sprite = overlaySprite;
overlayImage.enabled = true;
}
else
{
overlayImage.enabled = false;
}
}
}
/// <summary>
/// Updates background and zone shape based on card zone and rarity
/// Special handling for Legendary cards
/// </summary>
private void UpdateZoneVisuals()
{
if (visualConfig == null) return;
// Update background
// Legendary cards get special background, others get zone background
if (backgroundImage != null)
{
Sprite bgSprite = visualConfig.GetBackground(cardData.Zone, cardData.Rarity);
if (bgSprite != null)
{
backgroundImage.sprite = bgSprite;
backgroundImage.enabled = true;
}
else
{
backgroundImage.enabled = false;
}
}
// Update zone shape
// Legendary cards don't show shapes
if (zoneShapeImage != null)
{
Sprite shapeSprite = visualConfig.GetZoneShape(cardData.Zone, cardData.Rarity);
if (shapeSprite != null)
{
zoneShapeImage.sprite = shapeSprite;
zoneShapeImage.enabled = true;
}
else
{
zoneShapeImage.enabled = false;
}
}
}
/// <summary>
/// Clears all visual elements
/// </summary>
private void ClearCard()
{
if (cardNameText != null) cardNameText.text = "";
if (cardImage != null) cardImage.enabled = false;
if (frameImage != null) frameImage.enabled = false;
if (overlayImage != null) overlayImage.enabled = false;
if (backgroundImage != null) backgroundImage.enabled = false;
if (zoneShapeImage != null) zoneShapeImage.enabled = false;
}
/// <summary>
/// Called when the card is clicked
/// </summary>
public void OnClick()
{
OnCardClicked?.Invoke(this);
}
/// <summary>
/// Returns the card data associated with this display
/// </summary>
public CardData GetCardData()
{
return cardData;
}
/// <summary>
/// Updates the visual config reference
/// </summary>
public void SetVisualConfig(CardVisualConfig config)
{
visualConfig = config;
if (cardData != null)
{
UpdateCardVisuals();
}
}
#if UNITY_EDITOR
/// <summary>
/// Editor-only: Creates card data from the assigned definition and displays it
/// </summary>
public void PreviewFromDefinition()
{
if (editorCardDefinition == null)
{
Logging.Warning("[CardDisplay] Cannot preview: No card definition assigned in editor");
return;
}
cardData = editorCardDefinition.CreateCardData();
UpdateCardVisuals();
Logging.Debug($"[CardDisplay] Previewing card from definition: {cardData.Name}");
}
/// <summary>
/// Editor-only: Clears the preview
/// </summary>
public void ClearPreview()
{
cardData = null;
ClearCard();
Logging.Debug("[CardDisplay] Preview cleared");
}
#endif
}
#if UNITY_EDITOR
[CustomEditor(typeof(CardDisplay))]
public class CardDisplayEditor : Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();
CardDisplay display = (CardDisplay)target;
EditorGUILayout.Space();
EditorGUILayout.LabelField("Editor Preview Tools", EditorStyles.boldLabel);
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Preview Card"))
{
display.PreviewFromDefinition();
EditorUtility.SetDirty(display);
}
if (GUILayout.Button("Clear Preview"))
{
display.ClearPreview();
EditorUtility.SetDirty(display);
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
EditorGUILayout.HelpBox(
"Assign a Card Definition in 'Editor Tools' section, then click 'Preview Card' to see how it will look at runtime.",
MessageType.Info
);
}
}
#endif
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 72cb26621865420aa763a66c06eb7f6d
timeCreated: 1762380447

View File

@@ -1,204 +0,0 @@
using Core;
using Data.CardSystem;
using Pixelplacement;
using UI.Core;
using UnityEngine;
using UnityEngine.UI;
namespace UI.CardSystem
{
/// <summary>
/// UI page for the main menu of the card system.
/// Shows options to open boosters, view album, etc.
/// </summary>
public class CardMenuPage : UIPage
{
[Header("Menu Options")]
[SerializeField] private Button openBoosterButton;
[SerializeField] private Button viewAlbumButton;
[SerializeField] private Button changeClothesButton;
[SerializeField] private Button backButton; // Added back button field
[Header("UI Elements")]
[SerializeField] private BoosterNotificationDot boosterNotificationDot; // Changed to BoosterNotificationDot
[SerializeField] private CanvasGroup canvasGroup;
private CardAlbumUI _cardAlbumUI;
private CardSystemManager _cardManager;
private void Awake()
{
// Get references
_cardAlbumUI = FindAnyObjectByType<CardAlbumUI>();
_cardManager = CardSystemManager.Instance;
// Make sure we have a CanvasGroup
if (canvasGroup == null)
canvasGroup = GetComponent<CanvasGroup>();
if (canvasGroup == null)
canvasGroup = gameObject.AddComponent<CanvasGroup>();
// Set up button listeners
if (openBoosterButton != null)
{
openBoosterButton.onClick.AddListener(OnOpenBoosterClicked);
}
if (viewAlbumButton != null)
{
viewAlbumButton.onClick.AddListener(OnViewAlbumClicked);
}
if (changeClothesButton != null)
{
changeClothesButton.onClick.AddListener(OnChangeClothesClicked);
// Disable "Coming Soon" feature
changeClothesButton.interactable = false;
}
if (backButton != null) // Set up back button listener
{
backButton.onClick.AddListener(OnBackButtonClicked);
}
}
private void OnEnable()
{
UpdateUI();
}
private void OnDestroy()
{
// Clean up button listeners
if (openBoosterButton != null)
{
openBoosterButton.onClick.RemoveListener(OnOpenBoosterClicked);
}
if (viewAlbumButton != null)
{
viewAlbumButton.onClick.RemoveListener(OnViewAlbumClicked);
}
if (changeClothesButton != null)
{
changeClothesButton.onClick.RemoveListener(OnChangeClothesClicked);
}
if (backButton != null) // Clean up back button listener
{
backButton.onClick.RemoveListener(OnBackButtonClicked);
}
}
/// <summary>
/// Public method to refresh UI state when returning to this page
/// </summary>
public void RefreshUI()
{
UpdateUI();
}
/// <summary>
/// Updates the UI elements based on current state
/// </summary>
private void UpdateUI()
{
if (_cardManager == null) return;
int boosterCount = _cardManager.GetBoosterPackCount();
// Update booster count text using the notification dot
if (boosterNotificationDot != null)
{
boosterNotificationDot.SetCount(boosterCount);
}
// Enable/disable open booster button based on availability
if (openBoosterButton != null)
{
openBoosterButton.interactable = boosterCount > 0;
}
}
/// <summary>
/// Handles click on the Open Booster button
/// </summary>
private void OnOpenBoosterClicked()
{
if (_cardAlbumUI != null)
{
_cardAlbumUI.OpenBoosterPack();
}
}
/// <summary>
/// Handles click on the View Album button
/// </summary>
private void OnViewAlbumClicked()
{
if (_cardAlbumUI != null)
{
_cardAlbumUI.OpenAlbumView();
}
}
/// <summary>
/// Handles click on the Change Clothes button (coming soon)
/// </summary>
private void OnChangeClothesClicked()
{
Logging.Debug("[CardMenuPage] Change Clothes feature coming soon!");
// No implementation yet - "Coming soon" feature
}
/// <summary>
/// Handles click on the Back button
/// </summary>
private void OnBackButtonClicked()
{
// Use the UIPageController to pop this page
// This will hide the card menu and return to the game
if (UIPageController.Instance != null)
{
UIPageController.Instance.PopPage();
Logging.Debug("[CardMenuPage] Exiting card menu back to game");
}
}
/// <summary>
/// Override for transition in animation using Pixelplacement.Tween
/// </summary>
protected override void DoTransitionIn(System.Action onComplete)
{
// Simple fade in animation
if (canvasGroup != null)
{
canvasGroup.alpha = 0f;
Tween.Value(0f, 1f, (value) => canvasGroup.alpha = value, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete, obeyTimescale: false);
}
else
{
// Fallback if no CanvasGroup
onComplete?.Invoke();
}
}
/// <summary>
/// Override for transition out animation using Pixelplacement.Tween
/// </summary>
protected override void DoTransitionOut(System.Action onComplete)
{
// Simple fade out animation
if (canvasGroup != null)
{
Tween.Value(canvasGroup.alpha, 0f, (value) => canvasGroup.alpha = value, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete, obeyTimescale: false);
}
else
{
// Fallback if no CanvasGroup
onComplete?.Invoke();
}
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: a81af156ae284925a1f004d08f0bb364
timeCreated: 1759923823

View File

@@ -1,87 +0,0 @@
using Bootstrap;
using Core;
using UnityEngine;
// TODO: Yeet this class
namespace UI.CardSystem
{
/// <summary>
/// One-off helper that shows/hides the Card System root based on scene loads.
/// Attach this to your Card System root GameObject. It subscribes to SceneManagerService.SceneLoadCompleted
/// and applies visibility: hidden in "StartingScene" (configurable), visible in all other gameplay scenes.
/// </summary>
public class CardSystemSceneVisibility : MonoBehaviour
{
[Header("Target Root")]
[Tooltip("The GameObject to show/hide. Defaults to this GameObject if not assigned.")]
[SerializeField] private GameObject targetRoot;
private void Awake()
{
if (targetRoot == null)
targetRoot = gameObject;
// Defer subscription to after boot so SceneManagerService is guaranteed ready.
BootCompletionService.RegisterInitAction(InitializePostBoot, priority: 95, name: "CardSystem Scene Visibility Init");
}
private void InitializePostBoot()
{
var sceneSvc = SceneManagerService.Instance;
if (sceneSvc == null)
{
Debug.LogWarning("[CardSystemSceneVisibility] SceneManagerService.Instance is null post-boot.");
return;
}
// Subscribe to scene load completion notifications
sceneSvc.SceneLoadCompleted += OnSceneLoaded;
// Apply initial state based on current gameplay scene
ApplyVisibility(sceneSvc.CurrentGameplayScene);
}
private void OnDestroy()
{
var sceneSvc = SceneManagerService.Instance;
if (sceneSvc != null)
{
sceneSvc.SceneLoadCompleted -= OnSceneLoaded;
}
}
private void OnSceneLoaded(string sceneName)
{
ApplyVisibility(sceneName);
}
private void ApplyVisibility(string sceneName)
{
// TODO: Implement actual visibility logic based on sceneName
SetActiveSafe(true);
// if (targetRoot == null)
// return;
//
// if (string.IsNullOrEmpty(sceneName))
// return;
//
// if (hideInBootstrapScene && sceneName == "BootstrapScene")
// {
// SetActiveSafe(false);
// return;
// }
//
// bool shouldShow = sceneName != startingSceneName;
// SetActiveSafe(shouldShow);
}
private void SetActiveSafe(bool active)
{
if (targetRoot.activeSelf != active)
{
targetRoot.SetActive(active);
}
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: bd47485d27c34e138bbc5fbd894a3dea
timeCreated: 1761053493

View File

@@ -1,253 +0,0 @@
using System;
using AppleHills.Data.CardSystem;
using Core;
using TMPro;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
namespace UI.CardSystem
{
/// <summary>
/// Handles displaying and interacting with a single card in the UI.
/// </summary>
public class CardUIElement : MonoBehaviour
{
[Header("UI Elements")]
[SerializeField] private TextMeshProUGUI cardNameText;
[SerializeField] private Image cardImage;
[SerializeField] private Image frameImage;
[SerializeField] private Image backgroundImage;
[SerializeField] private Image backgroundShape;
[Header("Card Data")]
[SerializeField] private CardDefinition cardDefinition;
[SerializeField] private CardData cardData;
[Header("Visual Settings")]
[SerializeField] private CardVisualConfig visualConfig;
// Events
public event Action<CardUIElement> OnCardClicked;
/// <summary>
/// Sets up the card UI with the given card data
/// </summary>
public void SetupCard(CardData cardData)
{
Logging.Debug($"[CardUIElement] Setting up card with data: {cardData}");
this.cardData = cardData;
if (cardData == null)
{
Debug.LogError("[CardUIElement] Attempted to setup card with null data");
return;
}
UpdateCardVisuals();
}
/// <summary>
/// Updates the card visuals based on the current card data
/// </summary>
private void UpdateCardVisuals()
{
if (cardData == null) return;
// Set basic text information
if (cardNameText != null) cardNameText.text = cardData.Name;
// Set the card image
if (cardImage != null)
{
if (cardData.CardImage != null)
{
cardImage.sprite = cardData.CardImage;
cardImage.enabled = true;
}
else
{
cardImage.sprite = null;
cardImage.enabled = false;
// Don't log warnings for missing images - this is expected for new cards
// and causes console spam in the editor
}
}
// Update frame color based on rarity
UpdateFrameByRarity(cardData.Rarity);
// Update background color and shape based on zone
UpdateBackgroundByZone(cardData.Zone);
}
/// <summary>
/// Updates the frame color based on card rarity
/// </summary>
private void UpdateFrameByRarity(CardRarity rarity)
{
if (frameImage == null) return;
// Get color from config if available, otherwise use default colors
Color frameColor = visualConfig != null
? visualConfig.GetRarityColor(rarity)
: GetDefaultRarityColor(rarity);
frameImage.color = frameColor;
}
/// <summary>
/// Updates the background color and shape based on card zone
/// </summary>
private void UpdateBackgroundByZone(CardZone zone)
{
// Update background color
if (backgroundImage != null)
{
Color bgColor = visualConfig != null
? visualConfig.GetZoneColor(zone)
: GetDefaultZoneColor(zone);
backgroundImage.color = bgColor;
}
// Update background shape
if (backgroundShape != null && visualConfig != null)
{
Sprite shapeSprite = visualConfig.GetZoneShape(zone);
if (shapeSprite != null)
{
backgroundShape.sprite = shapeSprite;
backgroundShape.gameObject.SetActive(true);
}
else
{
backgroundShape.gameObject.SetActive(false);
}
}
}
/// <summary>
/// Returns default color for rarity if no config is available
/// </summary>
private Color GetDefaultRarityColor(CardRarity rarity)
{
switch (rarity)
{
case CardRarity.Common:
return Color.gray;
case CardRarity.Uncommon:
return Color.green;
case CardRarity.Rare:
return Color.blue;
case CardRarity.Epic:
return new Color(0.5f, 0, 0.5f); // Purple
case CardRarity.Legendary:
return Color.yellow;
default:
return Color.white;
}
}
/// <summary>
/// Returns default color for zone if no config is available
/// </summary>
private Color GetDefaultZoneColor(CardZone zone)
{
// Default zone colors from CardDefinition
switch (zone)
{
case CardZone.AppleHills:
return new Color(0.8f, 0.9f, 0.8f); // Light green
case CardZone.Quarry:
return new Color(0.85f, 0.8f, 0.7f); // Sandy brown
case CardZone.Forest:
return new Color(0.6f, 0.8f, 0.6f); // Forest green
case CardZone.Mountain:
return new Color(0.7f, 0.7f, 0.9f); // Bluish
case CardZone.Beach:
return new Color(0.9f, 0.85f, 0.7f); // Sandy yellow
default:
return Color.white;
}
}
/// <summary>
/// Called when the card is clicked
/// </summary>
public void OnClick()
{
OnCardClicked?.Invoke(this);
}
/// <summary>
/// Returns the card data associated with this UI element
/// </summary>
public CardData GetCardData()
{
return cardData;
}
// Animation methods that can be called from UI events
/// <summary>
/// Called when the card is revealed from a booster pack
/// </summary>
public void OnShowAnimation()
{
// Stub for card reveal animation
Logging.Debug($"[CardUIElement] Showing card: {cardData?.Name}");
// Could add animation code or call Animation Trigger here
}
/// <summary>
/// Called when the card moves to the backpack after being revealed
/// </summary>
public void OnMoveToBackpackAnimation()
{
// Stub for animation when card moves to backpack
Logging.Debug($"[CardUIElement] Moving card to backpack: {cardData?.Name}");
// Could add animation code or call Animation Trigger here
}
#if UNITY_EDITOR
/// <summary>
/// Create card data from definition and update the UI
/// </summary>
public void CreateFromDefinition()
{
if (cardDefinition == null)
{
Logging.Warning("[CardUIElement] Cannot create card data: No card definition assigned");
return;
}
cardData = cardDefinition.CreateCardData();
UpdateCardVisuals();
Logging.Debug($"[CardUIElement] Created card from definition: {cardData.Name}");
}
#endif
}
#if UNITY_EDITOR
[CustomEditor(typeof(CardUIElement))]
public class CardUIElementEditor : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();
CardUIElement cardUI = (CardUIElement)target;
EditorGUILayout.Space();
if (GUILayout.Button("Create From Definition"))
{
cardUI.CreateFromDefinition();
EditorUtility.SetDirty(cardUI);
}
}
}
#endif
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: aed7c581bdb84200a05dd8a7df409ab0
timeCreated: 1759923795