Add backbone for card creation and implement Camera minigame mechanics
This commit is contained in:
343
Assets/Scripts/UI/CardSystem/AlbumViewPage.cs
Normal file
343
Assets/Scripts/UI/CardSystem/AlbumViewPage.cs
Normal file
@@ -0,0 +1,343 @@
|
||||
using System.Collections.Generic;
|
||||
using AppleHills.Data.CardSystem;
|
||||
using Pixelplacement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace AppleHills.UI.CardSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// UI page for viewing and organizing the player's card collection in an album.
|
||||
/// </summary>
|
||||
public class AlbumViewPage : UIPage
|
||||
{
|
||||
[Header("Album UI Elements")]
|
||||
[SerializeField] private GridLayoutGroup albumGrid;
|
||||
[SerializeField] private RectTransform cardStackContainer;
|
||||
[SerializeField] private GameObject emptyAlbumMessage;
|
||||
[SerializeField] private GameObject cardSlotPrefab;
|
||||
[SerializeField] private GameObject cardPrefab;
|
||||
|
||||
// Runtime references
|
||||
private CardSystemManager _cardManager;
|
||||
private List<CardUIElement> _displayedCards = new List<CardUIElement>();
|
||||
private Dictionary<int, Transform> _albumSlots = new Dictionary<int, Transform>();
|
||||
|
||||
// Drag and drop handling
|
||||
private CardUIElement _currentlyDraggedCard = null;
|
||||
private Vector3 _cardOriginalPosition;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_cardManager = CardSystemManager.Instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets up the album when the page becomes active
|
||||
/// </summary>
|
||||
public override void TransitionIn()
|
||||
{
|
||||
base.TransitionIn();
|
||||
|
||||
// Initialize the album when the page becomes active
|
||||
InitializeAlbum();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the album with card slots and the player's collection
|
||||
/// </summary>
|
||||
private void InitializeAlbum()
|
||||
{
|
||||
// Clear any previous setup
|
||||
ClearAlbum();
|
||||
|
||||
// Get all collected cards
|
||||
List<CardData> collectedCards = _cardManager.GetAllCollectedCards();
|
||||
|
||||
// Show/hide empty message based on collection
|
||||
if (emptyAlbumMessage != null)
|
||||
{
|
||||
emptyAlbumMessage.SetActive(collectedCards.Count == 0);
|
||||
}
|
||||
|
||||
if (collectedCards.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up the album slots
|
||||
SetupAlbumSlots();
|
||||
|
||||
// Create card UI elements for the stack
|
||||
CreateCardStack(collectedCards);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets up empty slots in the album grid
|
||||
/// </summary>
|
||||
private void SetupAlbumSlots()
|
||||
{
|
||||
if (albumGrid == null || cardSlotPrefab == null) return;
|
||||
|
||||
// Create predefined slots in the album
|
||||
// For a simple implementation, we'll create a 5x5 grid of slots
|
||||
int slotsPerZone = 5; // 5 slots per zone (one row)
|
||||
int totalZones = System.Enum.GetValues(typeof(CardZone)).Length;
|
||||
|
||||
for (int zone = 0; zone < totalZones; zone++)
|
||||
{
|
||||
for (int i = 0; i < slotsPerZone; i++)
|
||||
{
|
||||
// Create a slot at this position
|
||||
GameObject slotObj = Instantiate(cardSlotPrefab, albumGrid.transform);
|
||||
|
||||
// Calculate the collection index for this slot
|
||||
int collectionIndex = zone * 100 + i; // Zone*100 + position to ensure unique indices
|
||||
|
||||
// Store the slot reference
|
||||
_albumSlots[collectionIndex] = slotObj.transform;
|
||||
|
||||
// Set the slot label (optional)
|
||||
Text slotLabel = slotObj.GetComponentInChildren<Text>();
|
||||
if (slotLabel != null)
|
||||
{
|
||||
CardZone zoneEnum = (CardZone)zone;
|
||||
slotLabel.text = $"{zoneEnum} #{i+1}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates UI elements for the player's collected cards
|
||||
/// </summary>
|
||||
private void CreateCardStack(List<CardData> cards)
|
||||
{
|
||||
if (cardStackContainer == null || cardPrefab == null) return;
|
||||
|
||||
// Stack offset for visual effect
|
||||
Vector3 stackOffset = new Vector3(5f, -5f, 0f);
|
||||
Vector3 basePosition = Vector3.zero;
|
||||
|
||||
// Sort cards by collection index
|
||||
cards.Sort((a, b) => a.CollectionIndex.CompareTo(b.CollectionIndex));
|
||||
|
||||
// Create card UI elements
|
||||
for (int i = 0; i < cards.Count; i++)
|
||||
{
|
||||
GameObject cardObj = Instantiate(cardPrefab, cardStackContainer);
|
||||
CardUIElement cardUI = cardObj.GetComponent<CardUIElement>();
|
||||
|
||||
if (cardUI != null)
|
||||
{
|
||||
// Position in stack
|
||||
cardObj.GetComponent<RectTransform>().anchoredPosition = basePosition + (stackOffset * i);
|
||||
|
||||
// Set up card data
|
||||
cardUI.SetupCard(cards[i]);
|
||||
|
||||
// Add drag handlers
|
||||
SetupCardDragHandlers(cardUI);
|
||||
|
||||
// Add to tracked cards
|
||||
_displayedCards.Add(cardUI);
|
||||
|
||||
// Check if this card should be placed in a slot already
|
||||
int collectionIndex = cards[i].CollectionIndex;
|
||||
if (_albumSlots.TryGetValue(collectionIndex, out Transform slot))
|
||||
{
|
||||
// Card has a designated slot, place it there
|
||||
PlaceCardInSlot(cardUI, slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets up drag and drop handlers for a card
|
||||
/// </summary>
|
||||
private void SetupCardDragHandlers(CardUIElement cardUI)
|
||||
{
|
||||
// // Get drag handler component (you might need to implement this)
|
||||
// DragHandler dragHandler = cardUI.GetComponent<DragHandler>();
|
||||
// if (dragHandler == null)
|
||||
// {
|
||||
// // This is a stub for the drag handler
|
||||
// // In a real implementation, you'd have a proper drag handler component
|
||||
// // For now, we'll just add click listeners
|
||||
//
|
||||
// // Add click listener
|
||||
// Button cardButton = cardUI.GetComponent<Button>();
|
||||
// if (cardButton != null)
|
||||
// {
|
||||
// cardButton.onClick.AddListener(() => OnCardClicked(cardUI));
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // Set up the drag handler events
|
||||
// dragHandler.OnBeginDrag.AddListener(() => OnBeginDragCard(cardUI));
|
||||
// dragHandler.OnDrag.AddListener((position) => OnDragCard(cardUI, position));
|
||||
// dragHandler.OnEndDrag.AddListener(() => OnEndDragCard(cardUI));
|
||||
// }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles when a card is clicked (simplistic alternative to drag and drop)
|
||||
/// </summary>
|
||||
private void OnCardClicked(CardUIElement cardUI)
|
||||
{
|
||||
CardData cardData = cardUI.GetCardData();
|
||||
|
||||
// Find the slot for this card based on collection index
|
||||
if (_albumSlots.TryGetValue(cardData.CollectionIndex, out Transform slot))
|
||||
{
|
||||
// Place the card in its slot
|
||||
PlaceCardInSlot(cardUI, slot);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the start of a card drag operation
|
||||
/// </summary>
|
||||
private void OnBeginDragCard(CardUIElement cardUI)
|
||||
{
|
||||
_currentlyDraggedCard = cardUI;
|
||||
_cardOriginalPosition = cardUI.transform.position;
|
||||
|
||||
// Bring the card to the front
|
||||
cardUI.transform.SetAsLastSibling();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the dragging of a card
|
||||
/// </summary>
|
||||
private void OnDragCard(CardUIElement cardUI, Vector3 position)
|
||||
{
|
||||
cardUI.transform.position = position;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the end of a card drag operation
|
||||
/// </summary>
|
||||
private void OnEndDragCard(CardUIElement cardUI)
|
||||
{
|
||||
// Check if the card is over a valid slot
|
||||
Transform closestSlot = FindClosestSlot(cardUI.transform.position);
|
||||
|
||||
if (closestSlot != null)
|
||||
{
|
||||
// Place the card in the slot
|
||||
PlaceCardInSlot(cardUI, closestSlot);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return the card to its original position
|
||||
cardUI.transform.position = _cardOriginalPosition;
|
||||
}
|
||||
|
||||
_currentlyDraggedCard = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Places a card in an album slot
|
||||
/// </summary>
|
||||
private void PlaceCardInSlot(CardUIElement cardUI, Transform slot)
|
||||
{
|
||||
// Reparent the card to the slot
|
||||
cardUI.transform.SetParent(slot);
|
||||
|
||||
// Animate card to center of slot using Pixelplacement.Tween
|
||||
Tween.LocalPosition(cardUI.transform, Vector3.zero, 0.25f, 0f, Tween.EaseOutBack);
|
||||
|
||||
Debug.Log($"[AlbumViewPage] Placed card '{cardUI.GetCardData().Name}' in album slot");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the closest album slot to a given position
|
||||
/// </summary>
|
||||
private Transform FindClosestSlot(Vector3 position)
|
||||
{
|
||||
Transform closest = null;
|
||||
float closestDistance = 100f; // Large initial value
|
||||
|
||||
foreach (var slot in _albumSlots.Values)
|
||||
{
|
||||
float distance = Vector3.Distance(position, slot.position);
|
||||
if (distance < closestDistance && distance < 50f) // Only if within reasonable range
|
||||
{
|
||||
closestDistance = distance;
|
||||
closest = slot;
|
||||
}
|
||||
}
|
||||
|
||||
return closest;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the album UI
|
||||
/// </summary>
|
||||
private void ClearAlbum()
|
||||
{
|
||||
// Clear displayed cards
|
||||
foreach (var card in _displayedCards)
|
||||
{
|
||||
Destroy(card.gameObject);
|
||||
}
|
||||
_displayedCards.Clear();
|
||||
|
||||
// Clear album slots
|
||||
foreach (Transform child in albumGrid.transform)
|
||||
{
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
_albumSlots.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override for transition in animation using Pixelplacement.Tween
|
||||
/// </summary>
|
||||
protected override void DoTransitionIn(System.Action onComplete)
|
||||
{
|
||||
// Simple slide in animation
|
||||
RectTransform rt = GetComponent<RectTransform>();
|
||||
if (rt != null)
|
||||
{
|
||||
// Store the end position
|
||||
Vector2 endPosition = rt.anchoredPosition;
|
||||
|
||||
// Set initial position (off-screen to the right)
|
||||
rt.anchoredPosition = new Vector2(Screen.width, endPosition.y);
|
||||
|
||||
// Animate to end position
|
||||
Tween.AnchoredPosition(rt, endPosition, transitionDuration, 0f,
|
||||
Tween.EaseOutStrong, Tween.LoopType.None, null, onComplete);
|
||||
}
|
||||
else
|
||||
{
|
||||
onComplete?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override for transition out animation using Pixelplacement.Tween
|
||||
/// </summary>
|
||||
protected override void DoTransitionOut(System.Action onComplete)
|
||||
{
|
||||
// Simple slide out animation
|
||||
RectTransform rt = GetComponent<RectTransform>();
|
||||
if (rt != null)
|
||||
{
|
||||
// Animate to off-screen position (to the left)
|
||||
Vector2 offScreenPosition = new Vector2(-Screen.width, rt.anchoredPosition.y);
|
||||
|
||||
Tween.AnchoredPosition(rt, offScreenPosition, transitionDuration, 0f,
|
||||
Tween.EaseInOutStrong, Tween.LoopType.None, null, onComplete);
|
||||
}
|
||||
else
|
||||
{
|
||||
onComplete?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/UI/CardSystem/AlbumViewPage.cs.meta
Normal file
3
Assets/Scripts/UI/CardSystem/AlbumViewPage.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 59ff936424a34ce3937299c66232bf7a
|
||||
timeCreated: 1759923921
|
||||
270
Assets/Scripts/UI/CardSystem/BoosterOpeningPage.cs
Normal file
270
Assets/Scripts/UI/CardSystem/BoosterOpeningPage.cs
Normal file
@@ -0,0 +1,270 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using AppleHills.Data.CardSystem;
|
||||
using Pixelplacement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace AppleHills.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 Transform cardRevealTransform;
|
||||
[SerializeField] private GameObject cardPrefab;
|
||||
[SerializeField] private Button openBoosterButton;
|
||||
[SerializeField] private Button continueButton;
|
||||
|
||||
[Header("Animation Settings")]
|
||||
[SerializeField] private float cardRevealDelay = 0.5f;
|
||||
[SerializeField] private float cardMoveToBackpackDelay = 1.0f;
|
||||
|
||||
// State tracking
|
||||
private enum OpeningState
|
||||
{
|
||||
BoosterReady,
|
||||
CardsRevealed,
|
||||
Completed
|
||||
}
|
||||
|
||||
private OpeningState _currentState = OpeningState.BoosterReady;
|
||||
private List<CardUIElement> _revealedCards = new List<CardUIElement>();
|
||||
private CardSystemManager _cardManager;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_cardManager = CardSystemManager.Instance;
|
||||
|
||||
// Set up button listeners
|
||||
if (openBoosterButton != null)
|
||||
{
|
||||
openBoosterButton.onClick.AddListener(OnOpenBoosterClicked);
|
||||
}
|
||||
|
||||
if (continueButton != null)
|
||||
{
|
||||
continueButton.onClick.AddListener(OnContinueClicked);
|
||||
continueButton.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
// Clean up button listeners
|
||||
if (openBoosterButton != null)
|
||||
{
|
||||
openBoosterButton.onClick.RemoveListener(OnOpenBoosterClicked);
|
||||
}
|
||||
|
||||
if (continueButton != null)
|
||||
{
|
||||
continueButton.onClick.RemoveListener(OnContinueClicked);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
Destroy(card.gameObject);
|
||||
}
|
||||
_revealedCards.Clear();
|
||||
|
||||
// Reset state
|
||||
_currentState = OpeningState.BoosterReady;
|
||||
|
||||
// Show booster pack, hide continue button
|
||||
if (boosterPackObject != null)
|
||||
{
|
||||
boosterPackObject.SetActive(true);
|
||||
}
|
||||
|
||||
if (openBoosterButton != null)
|
||||
{
|
||||
openBoosterButton.gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
if (continueButton != null)
|
||||
{
|
||||
continueButton.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles click on the booster pack to open it
|
||||
/// </summary>
|
||||
private void OnOpenBoosterClicked()
|
||||
{
|
||||
if (_currentState != OpeningState.BoosterReady) return;
|
||||
|
||||
// Open the booster pack and get the cards
|
||||
List<CardData> newCards = _cardManager.OpenBoosterPack();
|
||||
|
||||
if (newCards.Count > 0)
|
||||
{
|
||||
// Hide the booster pack and open button
|
||||
if (boosterPackObject != null)
|
||||
{
|
||||
boosterPackObject.SetActive(false);
|
||||
}
|
||||
|
||||
if (openBoosterButton != null)
|
||||
{
|
||||
openBoosterButton.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
// Start revealing cards
|
||||
StartCoroutine(RevealCards(newCards));
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("[BoosterOpeningPage] No cards were obtained from the booster pack.");
|
||||
UIPageController.Instance.PopPage();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reveals cards one by one with animation
|
||||
/// </summary>
|
||||
private IEnumerator RevealCards(List<CardData> cards)
|
||||
{
|
||||
// Wait a short delay before revealing cards
|
||||
yield return new WaitForSeconds(0.5f);
|
||||
|
||||
// Reveal each card
|
||||
foreach (var cardData in cards)
|
||||
{
|
||||
// Instantiate card UI element
|
||||
GameObject cardObj = Instantiate(cardPrefab, cardRevealTransform);
|
||||
CardUIElement cardUI = cardObj.GetComponent<CardUIElement>();
|
||||
|
||||
if (cardUI != null)
|
||||
{
|
||||
// Set up the card data
|
||||
cardUI.SetupCard(cardData);
|
||||
_revealedCards.Add(cardUI);
|
||||
|
||||
// Set initial scale to zero for animation
|
||||
cardObj.transform.localScale = Vector3.zero;
|
||||
|
||||
// Play reveal animation using Pixelplacement.Tween
|
||||
Tween.LocalScale(cardObj.transform, Vector3.one, 0.5f, 0f, Tween.EaseOutBack);
|
||||
|
||||
// Call card's show animation
|
||||
cardUI.OnShowAnimation();
|
||||
|
||||
// Wait for animation delay
|
||||
yield return new WaitForSeconds(cardRevealDelay);
|
||||
}
|
||||
}
|
||||
|
||||
// Update state and show continue button
|
||||
_currentState = OpeningState.CardsRevealed;
|
||||
if (continueButton != null)
|
||||
{
|
||||
continueButton.gameObject.SetActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles click on the continue button after cards are revealed
|
||||
/// </summary>
|
||||
private void OnContinueClicked()
|
||||
{
|
||||
if (_currentState != OpeningState.CardsRevealed) return;
|
||||
|
||||
// Start moving cards to backpack animation
|
||||
StartCoroutine(MoveCardsToBackpack());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Animates cards moving to the backpack
|
||||
/// </summary>
|
||||
private IEnumerator MoveCardsToBackpack()
|
||||
{
|
||||
// Hide continue button
|
||||
if (continueButton != null)
|
||||
{
|
||||
continueButton.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
// Get corner position for backpack (bottom left)
|
||||
Vector3 cornerPosition = new Vector3(-Screen.width/2 + 50, -Screen.height/2 + 50, 0);
|
||||
|
||||
// Animate each card moving to the backpack
|
||||
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;
|
||||
UIPageController.Instance.PopPage();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override for transition in animation using Pixelplacement.Tween
|
||||
/// </summary>
|
||||
protected override void DoTransitionIn(System.Action onComplete)
|
||||
{
|
||||
// Scale in animation for the booster pack
|
||||
if (boosterPackObject != null)
|
||||
{
|
||||
boosterPackObject.transform.localScale = Vector3.zero;
|
||||
Tween.LocalScale(boosterPackObject.transform, Vector3.one, transitionDuration, 0f,
|
||||
Tween.EaseOutBack, Tween.LoopType.None, null, onComplete);
|
||||
}
|
||||
else
|
||||
{
|
||||
onComplete?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override for transition out animation using Pixelplacement.Tween
|
||||
/// </summary>
|
||||
protected override void DoTransitionOut(System.Action onComplete)
|
||||
{
|
||||
// Fade out animation using a CanvasGroup if available
|
||||
CanvasGroup canvasGroup = GetComponent<CanvasGroup>();
|
||||
if (canvasGroup != null)
|
||||
{
|
||||
Tween.Value(canvasGroup.alpha, 0f, (value) => canvasGroup.alpha = value,
|
||||
transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete);
|
||||
}
|
||||
else
|
||||
{
|
||||
onComplete?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/UI/CardSystem/BoosterOpeningPage.cs.meta
Normal file
3
Assets/Scripts/UI/CardSystem/BoosterOpeningPage.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f64698442ba344e0a466ee3c530797c7
|
||||
timeCreated: 1759923862
|
||||
186
Assets/Scripts/UI/CardSystem/CardAlbumUI.cs
Normal file
186
Assets/Scripts/UI/CardSystem/CardAlbumUI.cs
Normal file
@@ -0,0 +1,186 @@
|
||||
using System;
|
||||
using AppleHills.Data.CardSystem;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace AppleHills.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 Text boosterCountText;
|
||||
|
||||
private UIPageController _pageController;
|
||||
private CardSystemManager _cardManager;
|
||||
private bool _isInitialized = false;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
// Get or create a UI page controller
|
||||
_pageController = FindAnyObjectByType<UIPageController>();
|
||||
if (_pageController == null)
|
||||
{
|
||||
GameObject controllerObj = new GameObject("UIPageController");
|
||||
controllerObj.transform.SetParent(transform);
|
||||
_pageController = controllerObj.AddComponent<UIPageController>();
|
||||
}
|
||||
|
||||
// Initialize pages and hide them
|
||||
InitializePages();
|
||||
|
||||
// Set up backpack button
|
||||
if (backpackButton != null)
|
||||
{
|
||||
backpackButton.onClick.AddListener(OnBackpackButtonClicked);
|
||||
}
|
||||
|
||||
// Initially show only the backpack icon
|
||||
ShowOnlyBackpackIcon();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// Get card manager
|
||||
_cardManager = CardSystemManager.Instance;
|
||||
|
||||
// Subscribe to events
|
||||
if (_cardManager != null)
|
||||
{
|
||||
_cardManager.OnBoosterCountChanged += UpdateBoosterCount;
|
||||
UpdateBoosterCount(_cardManager.GetBoosterPackCount());
|
||||
}
|
||||
|
||||
_isInitialized = true;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
// Unsubscribe from events
|
||||
if (_cardManager != null)
|
||||
{
|
||||
_cardManager.OnBoosterCountChanged -= UpdateBoosterCount;
|
||||
}
|
||||
|
||||
// Clean up button listeners
|
||||
if (backpackButton != null)
|
||||
{
|
||||
backpackButton.onClick.RemoveListener(OnBackpackButtonClicked);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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()
|
||||
{
|
||||
// If no pages are open, push the main menu
|
||||
if (_pageController.CurrentPage == null)
|
||||
{
|
||||
_pageController.PushPage(mainMenuPage);
|
||||
}
|
||||
else if (_pageController.CurrentPage == mainMenuPage)
|
||||
{
|
||||
// If main menu is open, pop it
|
||||
_pageController.PopPage();
|
||||
}
|
||||
}
|
||||
|
||||
/// <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();
|
||||
}
|
||||
else
|
||||
{
|
||||
backpackIcon.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows only the backpack icon, hiding all other UI elements
|
||||
/// </summary>
|
||||
private void ShowOnlyBackpackIcon()
|
||||
{
|
||||
backpackIcon.SetActive(true);
|
||||
}
|
||||
|
||||
/// <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
|
||||
{
|
||||
Debug.Log("[CardAlbumUI] No booster packs available");
|
||||
// TODO: Show "no boosters available" message
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the booster count display
|
||||
/// </summary>
|
||||
private void UpdateBoosterCount(int count)
|
||||
{
|
||||
if (boosterCountText != null)
|
||||
{
|
||||
boosterCountText.text = count.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/UI/CardSystem/CardAlbumUI.cs.meta
Normal file
3
Assets/Scripts/UI/CardSystem/CardAlbumUI.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fe5ff32f529d4f24a2064ee1dfa07758
|
||||
timeCreated: 1759923763
|
||||
177
Assets/Scripts/UI/CardSystem/CardMenuPage.cs
Normal file
177
Assets/Scripts/UI/CardSystem/CardMenuPage.cs
Normal file
@@ -0,0 +1,177 @@
|
||||
using System.Collections.Generic;
|
||||
using AppleHills.Data.CardSystem;
|
||||
using Pixelplacement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace AppleHills.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;
|
||||
|
||||
[Header("UI Elements")]
|
||||
[SerializeField] private Text boosterCountText;
|
||||
[SerializeField] private GameObject noBoostersMessage;
|
||||
[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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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
|
||||
if (boosterCountText != null)
|
||||
{
|
||||
boosterCountText.text = $"Boosters: {boosterCount}";
|
||||
}
|
||||
|
||||
// Enable/disable open booster button based on availability
|
||||
if (openBoosterButton != null)
|
||||
{
|
||||
openBoosterButton.interactable = boosterCount > 0;
|
||||
}
|
||||
|
||||
// Show/hide no boosters message
|
||||
if (noBoostersMessage != null)
|
||||
{
|
||||
noBoostersMessage.SetActive(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()
|
||||
{
|
||||
Debug.Log("[CardMenuPage] Change Clothes feature coming soon!");
|
||||
// No implementation yet - "Coming soon" feature
|
||||
}
|
||||
|
||||
/// <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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback if no CanvasGroup
|
||||
onComplete?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/UI/CardSystem/CardMenuPage.cs.meta
Normal file
3
Assets/Scripts/UI/CardSystem/CardMenuPage.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a81af156ae284925a1f004d08f0bb364
|
||||
timeCreated: 1759923823
|
||||
255
Assets/Scripts/UI/CardSystem/CardUIElement.cs
Normal file
255
Assets/Scripts/UI/CardSystem/CardUIElement.cs
Normal file
@@ -0,0 +1,255 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AppleHills.Data.CardSystem;
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
using UnityEngine.UI;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace AppleHills.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)
|
||||
{
|
||||
Debug.Log($"[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
|
||||
Debug.Log($"[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
|
||||
Debug.Log($"[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)
|
||||
{
|
||||
Debug.LogWarning("[CardUIElement] Cannot create card data: No card definition assigned");
|
||||
return;
|
||||
}
|
||||
|
||||
cardData = cardDefinition.CreateCardData();
|
||||
UpdateCardVisuals();
|
||||
|
||||
Debug.Log($"[CardUIElement] Created card from definition: {cardData.Name}");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[CustomEditor(typeof(CardUIElement))]
|
||||
public class CardUIElementEditor : Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
DrawDefaultInspector();
|
||||
|
||||
CardUIElement cardUI = (CardUIElement)target;
|
||||
|
||||
EditorGUILayout.Space();
|
||||
if (GUILayout.Button("Create From Definition"))
|
||||
{
|
||||
cardUI.CreateFromDefinition();
|
||||
EditorUtility.SetDirty(cardUI);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
3
Assets/Scripts/UI/CardSystem/CardUIElement.cs.meta
Normal file
3
Assets/Scripts/UI/CardSystem/CardUIElement.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aed7c581bdb84200a05dd8a7df409ab0
|
||||
timeCreated: 1759923795
|
||||
92
Assets/Scripts/UI/CardSystem/UIPage.cs
Normal file
92
Assets/Scripts/UI/CardSystem/UIPage.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AppleHills.UI.CardSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for UI pages that can transition in and out.
|
||||
/// Extended by specific UI page implementations for the card system.
|
||||
/// </summary>
|
||||
public abstract class UIPage : MonoBehaviour
|
||||
{
|
||||
[Header("Page Settings")]
|
||||
public string PageName;
|
||||
|
||||
// Events using System.Action instead of UnityEvents
|
||||
public event Action OnTransitionInStarted;
|
||||
public event Action OnTransitionInCompleted;
|
||||
public event Action OnTransitionOutStarted;
|
||||
public event Action OnTransitionOutCompleted;
|
||||
|
||||
// Default duration for transitions
|
||||
[SerializeField] protected float transitionDuration = 0.3f;
|
||||
|
||||
// State flags
|
||||
protected bool _isTransitioning = false;
|
||||
protected bool _isVisible = false;
|
||||
|
||||
/// <summary>
|
||||
/// Called when the page is shown. Handles the transition in animation.
|
||||
/// </summary>
|
||||
public virtual void TransitionIn()
|
||||
{
|
||||
gameObject.SetActive(true);
|
||||
_isTransitioning = true;
|
||||
OnTransitionInStarted?.Invoke();
|
||||
|
||||
// Override in child classes for specific transition animations
|
||||
DoTransitionIn(() => {
|
||||
_isTransitioning = false;
|
||||
_isVisible = true;
|
||||
OnTransitionInCompleted?.Invoke();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the page is hidden. Handles the transition out animation.
|
||||
/// </summary>
|
||||
public virtual void TransitionOut()
|
||||
{
|
||||
_isTransitioning = true;
|
||||
OnTransitionOutStarted?.Invoke();
|
||||
|
||||
// Override in child classes for specific transition animations
|
||||
DoTransitionOut(() => {
|
||||
_isTransitioning = false;
|
||||
_isVisible = false;
|
||||
OnTransitionOutCompleted?.Invoke();
|
||||
gameObject.SetActive(false);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the back button is pressed while this page is active.
|
||||
/// Default implementation pops the page from the stack.
|
||||
/// </summary>
|
||||
public virtual void OnBackPressed()
|
||||
{
|
||||
if (!_isTransitioning)
|
||||
{
|
||||
UIPageController.Instance.PopPage();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implement transition in animation in child classes.
|
||||
/// </summary>
|
||||
protected virtual void DoTransitionIn(Action onComplete)
|
||||
{
|
||||
// Default implementation - instant transition
|
||||
onComplete?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implement transition out animation in child classes.
|
||||
/// </summary>
|
||||
protected virtual void DoTransitionOut(Action onComplete)
|
||||
{
|
||||
// Default implementation - instant transition
|
||||
onComplete?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/UI/CardSystem/UIPage.cs.meta
Normal file
3
Assets/Scripts/UI/CardSystem/UIPage.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 57fa26be941c43dc9331534ab59416b1
|
||||
timeCreated: 1759923734
|
||||
109
Assets/Scripts/UI/CardSystem/UIPageController.cs
Normal file
109
Assets/Scripts/UI/CardSystem/UIPageController.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AppleHills.UI.CardSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Manages UI page transitions and maintains a stack of active pages.
|
||||
/// Pages are pushed onto a stack for navigation and popped when going back.
|
||||
/// </summary>
|
||||
public class UIPageController : MonoBehaviour
|
||||
{
|
||||
private static UIPageController _instance;
|
||||
public static UIPageController Instance => _instance;
|
||||
|
||||
private Stack<UIPage> _pageStack = new Stack<UIPage>();
|
||||
public UIPage CurrentPage => _pageStack.Count > 0 ? _pageStack.Peek() : null;
|
||||
|
||||
// Event fired when the page stack changes
|
||||
public event Action<UIPage> OnPageChanged;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (_instance != null && _instance != this)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
_instance = this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushes a new page onto the stack, hiding the current page and showing the new one.
|
||||
/// </summary>
|
||||
public void PushPage(UIPage page)
|
||||
{
|
||||
if (page == null) return;
|
||||
|
||||
// Hide current page if there is one
|
||||
if (_pageStack.Count > 0)
|
||||
{
|
||||
UIPage currentPage = _pageStack.Peek();
|
||||
currentPage.TransitionOut();
|
||||
}
|
||||
|
||||
// Push and show new page
|
||||
_pageStack.Push(page);
|
||||
page.TransitionIn();
|
||||
|
||||
OnPageChanged?.Invoke(page);
|
||||
Debug.Log($"[UIPageController] Pushed page: {page.PageName}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pops the current page from the stack and shows the previous page.
|
||||
/// </summary>
|
||||
public void PopPage()
|
||||
{
|
||||
if (_pageStack.Count <= 0) return;
|
||||
|
||||
// Hide and pop current page
|
||||
UIPage currentPage = _pageStack.Pop();
|
||||
currentPage.TransitionOut();
|
||||
|
||||
// Show previous page if there is one
|
||||
if (_pageStack.Count > 0)
|
||||
{
|
||||
UIPage previousPage = _pageStack.Peek();
|
||||
previousPage.TransitionIn();
|
||||
OnPageChanged?.Invoke(previousPage);
|
||||
Debug.Log($"[UIPageController] Popped to previous page: {previousPage.PageName}");
|
||||
}
|
||||
else
|
||||
{
|
||||
OnPageChanged?.Invoke(null);
|
||||
Debug.Log("[UIPageController] Popped last page, no pages left in stack");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all pages from the stack.
|
||||
/// </summary>
|
||||
public void ClearStack()
|
||||
{
|
||||
if (_pageStack.Count <= 0) return;
|
||||
|
||||
// Hide current page
|
||||
UIPage currentPage = _pageStack.Peek();
|
||||
currentPage.TransitionOut();
|
||||
|
||||
// Clear stack
|
||||
_pageStack.Clear();
|
||||
OnPageChanged?.Invoke(null);
|
||||
Debug.Log("[UIPageController] Cleared page stack");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles back button input and navigates to the previous page if possible.
|
||||
/// </summary>
|
||||
private void Update()
|
||||
{
|
||||
if (UnityEngine.Input.GetKeyDown(KeyCode.Escape) && _pageStack.Count > 0)
|
||||
{
|
||||
_pageStack.Peek().OnBackPressed();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/UI/CardSystem/UIPageController.cs.meta
Normal file
3
Assets/Scripts/UI/CardSystem/UIPageController.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b1ae6c1745e44e22a0fa9209ebe45ee3
|
||||
timeCreated: 1759923720
|
||||
Reference in New Issue
Block a user