Semi-working rarity upgrades
This commit is contained in:
@@ -29,6 +29,14 @@ namespace UI.CardSystem
|
||||
[SerializeField] private float flipDuration = 0.6f;
|
||||
[SerializeField] private float flipScalePunch = 1.1f;
|
||||
|
||||
[Header("New/Repeat Card Display")]
|
||||
[SerializeField] private GameObject newCardText;
|
||||
[SerializeField] private GameObject newCardIdleText;
|
||||
[SerializeField] private GameObject repeatText;
|
||||
[SerializeField] private GameObject progressBarContainer;
|
||||
[SerializeField] private int cardsToUpgrade = 5;
|
||||
[SerializeField] private float enlargedScale = 1.5f;
|
||||
|
||||
// State
|
||||
private bool _isFlipped = false;
|
||||
private bool _isFlipping = false;
|
||||
@@ -36,12 +44,20 @@ namespace UI.CardSystem
|
||||
private TweenBase _idleHoverTween;
|
||||
private CardData _cardData;
|
||||
private Vector2 _originalPosition; // Track original spawn position
|
||||
private bool _isWaitingForTap = false; // Waiting for tap after reveal
|
||||
private bool _isNew = false; // Is this a new card
|
||||
private int _ownedCount = 0; // Owned count for repeat cards
|
||||
private bool _isClickable = true; // Can this card be clicked
|
||||
|
||||
// Events
|
||||
public event Action<FlippableCard, CardData> OnCardRevealed;
|
||||
public event Action<FlippableCard> OnCardTappedAfterReveal;
|
||||
public event Action<FlippableCard> OnClickedWhileInactive; // Fired when clicked but not clickable
|
||||
public event Action<FlippableCard> OnFlipStarted; // Fired when flip animation begins
|
||||
|
||||
public bool IsFlipped => _isFlipped;
|
||||
public CardData CardData => _cardData;
|
||||
public int CardsToUpgrade => cardsToUpgrade; // Expose upgrade threshold
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
@@ -51,11 +67,29 @@ namespace UI.CardSystem
|
||||
cardDisplay = cardFrontObject.GetComponent<CardDisplay>();
|
||||
}
|
||||
|
||||
// Start with back showing, front hidden
|
||||
// Card back: starts at 0° rotation (normal, facing camera, clickable)
|
||||
// Card front: starts at 180° rotation (flipped away, will rotate to 0° when revealed)
|
||||
if (cardBackObject != null)
|
||||
{
|
||||
cardBackObject.transform.localRotation = Quaternion.Euler(0, 0, 0);
|
||||
cardBackObject.SetActive(true);
|
||||
}
|
||||
|
||||
if (cardFrontObject != null)
|
||||
{
|
||||
cardFrontObject.transform.localRotation = Quaternion.Euler(0, 180, 0);
|
||||
cardFrontObject.SetActive(false);
|
||||
}
|
||||
|
||||
// Hide all new/repeat UI elements initially
|
||||
if (newCardText != null)
|
||||
newCardText.SetActive(false);
|
||||
if (newCardIdleText != null)
|
||||
newCardIdleText.SetActive(false);
|
||||
if (repeatText != null)
|
||||
repeatText.SetActive(false);
|
||||
if (progressBarContainer != null)
|
||||
progressBarContainer.SetActive(false);
|
||||
}
|
||||
|
||||
private void Start()
|
||||
@@ -98,40 +132,53 @@ namespace UI.CardSystem
|
||||
|
||||
_isFlipping = true;
|
||||
|
||||
// Fire flip started event IMMEDIATELY (before animations)
|
||||
OnFlipStarted?.Invoke(this);
|
||||
|
||||
// Stop idle hover
|
||||
StopIdleHover();
|
||||
|
||||
// Flip animation: rotate Y 0 -> 90 (hide back) -> 180 (show front)
|
||||
Transform cardTransform = transform;
|
||||
// Flip animation: Rotate the visual children (back from 0→90, front from 180→0)
|
||||
// ...existing code...
|
||||
// Card back: 0° → 90° (rotates away)
|
||||
// Card front: 180° → 90° → 0° (rotates into view)
|
||||
|
||||
// Phase 1: Flip to 90 degrees (edge view, hide back)
|
||||
Tween.LocalRotation(cardTransform, Quaternion.Euler(0, 90, 0), flipDuration * 0.5f, 0f, Tween.EaseInOut,
|
||||
completeCallback: () =>
|
||||
{
|
||||
// Switch visuals at the edge
|
||||
if (cardBackObject != null)
|
||||
cardBackObject.SetActive(false);
|
||||
if (cardFrontObject != null)
|
||||
cardFrontObject.SetActive(true);
|
||||
|
||||
// Phase 2: Flip from 90 to 180 (show front)
|
||||
Tween.LocalRotation(cardTransform, Quaternion.Euler(0, 180, 0), flipDuration * 0.5f, 0f, Tween.EaseInOut,
|
||||
completeCallback: () =>
|
||||
{
|
||||
_isFlipped = true;
|
||||
_isFlipping = false;
|
||||
|
||||
// Fire revealed event
|
||||
OnCardRevealed?.Invoke(this, _cardData);
|
||||
});
|
||||
});
|
||||
// Phase 1: Rotate both to 90 degrees (edge view)
|
||||
if (cardBackObject != null)
|
||||
{
|
||||
Tween.LocalRotation(cardBackObject.transform, Quaternion.Euler(0, 90, 0), flipDuration * 0.5f, 0f, Tween.EaseInOut);
|
||||
}
|
||||
|
||||
if (cardFrontObject != null)
|
||||
{
|
||||
Tween.LocalRotation(cardFrontObject.transform, Quaternion.Euler(0, 90, 0), flipDuration * 0.5f, 0f, Tween.EaseInOut,
|
||||
completeCallback: () =>
|
||||
{
|
||||
// At edge (90°), switch visibility
|
||||
if (cardBackObject != null)
|
||||
cardBackObject.SetActive(false);
|
||||
if (cardFrontObject != null)
|
||||
cardFrontObject.SetActive(true);
|
||||
|
||||
// Phase 2: Rotate front from 90 to 0 (show at correct orientation)
|
||||
Tween.LocalRotation(cardFrontObject.transform, Quaternion.Euler(0, 0, 0), flipDuration * 0.5f, 0f, Tween.EaseInOut,
|
||||
completeCallback: () =>
|
||||
{
|
||||
_isFlipped = true;
|
||||
_isFlipping = false;
|
||||
|
||||
// Fire revealed event
|
||||
OnCardRevealed?.Invoke(this, _cardData);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Scale punch during flip for extra juice
|
||||
Vector3 originalScale = cardTransform.localScale;
|
||||
Tween.LocalScale(cardTransform, originalScale * flipScalePunch, flipDuration * 0.5f, 0f, Tween.EaseOutBack,
|
||||
Vector3 originalScale = transform.localScale;
|
||||
Tween.LocalScale(transform, originalScale * flipScalePunch, flipDuration * 0.5f, 0f, Tween.EaseOutBack,
|
||||
completeCallback: () =>
|
||||
{
|
||||
Tween.LocalScale(cardTransform, originalScale, flipDuration * 0.5f, 0f, Tween.EaseInBack);
|
||||
Tween.LocalScale(transform, originalScale, flipDuration * 0.5f, 0f, Tween.EaseInBack);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -207,6 +254,21 @@ namespace UI.CardSystem
|
||||
|
||||
public void OnPointerClick(PointerEventData eventData)
|
||||
{
|
||||
// If not clickable, notify and return
|
||||
if (!_isClickable)
|
||||
{
|
||||
OnClickedWhileInactive?.Invoke(this);
|
||||
return;
|
||||
}
|
||||
|
||||
// If waiting for tap after reveal, handle that
|
||||
if (_isWaitingForTap)
|
||||
{
|
||||
OnCardTappedAfterReveal?.Invoke(this);
|
||||
_isWaitingForTap = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_isFlipped || _isFlipping)
|
||||
return;
|
||||
|
||||
@@ -216,6 +278,352 @@ namespace UI.CardSystem
|
||||
|
||||
#endregion
|
||||
|
||||
#region New/Repeat Card Display
|
||||
|
||||
/// <summary>
|
||||
/// Show this card as a new card (enlarge, show "NEW CARD" text, wait for tap)
|
||||
/// </summary>
|
||||
public void ShowAsNew()
|
||||
{
|
||||
_isNew = true;
|
||||
_isWaitingForTap = true;
|
||||
|
||||
// Show new card text
|
||||
if (newCardText != null)
|
||||
newCardText.SetActive(true);
|
||||
|
||||
// Enlarge the card
|
||||
EnlargeCard();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show this card as a repeat that will trigger an upgrade (enlarge, show progress, auto-transition to upgrade)
|
||||
/// </summary>
|
||||
/// <param name="ownedCount">Number of copies owned BEFORE this one</param>
|
||||
/// <param name="lowerRarityCard">The existing card data at lower rarity (for upgrade reference)</param>
|
||||
public void ShowAsRepeatWithUpgrade(int ownedCount, AppleHills.Data.CardSystem.CardData lowerRarityCard)
|
||||
{
|
||||
_isNew = false;
|
||||
_ownedCount = ownedCount;
|
||||
_isWaitingForTap = false; // Don't wait yet - upgrade will happen automatically
|
||||
|
||||
// Show repeat text
|
||||
if (repeatText != null)
|
||||
repeatText.SetActive(true);
|
||||
|
||||
// Enlarge the card
|
||||
EnlargeCard();
|
||||
|
||||
// Show progress bar with owned count, then auto-trigger upgrade
|
||||
ShowProgressBar(ownedCount, () =>
|
||||
{
|
||||
// Progress animation complete - trigger upgrade!
|
||||
TriggerUpgradeTransition(lowerRarityCard);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Trigger the upgrade transition (called after progress bar fills)
|
||||
/// </summary>
|
||||
private void TriggerUpgradeTransition(AppleHills.Data.CardSystem.CardData lowerRarityCard)
|
||||
{
|
||||
Debug.Log($"[FlippableCard] Triggering upgrade transition from {lowerRarityCard.Rarity}!");
|
||||
|
||||
AppleHills.Data.CardSystem.CardRarity oldRarity = lowerRarityCard.Rarity;
|
||||
AppleHills.Data.CardSystem.CardRarity newRarity = oldRarity + 1;
|
||||
|
||||
// Reset the lower rarity count to 0
|
||||
lowerRarityCard.CopiesOwned = 0;
|
||||
|
||||
// Create upgraded card data
|
||||
AppleHills.Data.CardSystem.CardData upgradedCardData = new AppleHills.Data.CardSystem.CardData(_cardData);
|
||||
upgradedCardData.Rarity = newRarity;
|
||||
upgradedCardData.CopiesOwned = 1;
|
||||
|
||||
// Check if we already have this card at the higher rarity
|
||||
bool isNewAtHigherRarity = Data.CardSystem.CardSystemManager.Instance.IsCardNew(upgradedCardData, out AppleHills.Data.CardSystem.CardData existingHigherRarity);
|
||||
|
||||
// Add the higher rarity card to inventory
|
||||
Data.CardSystem.CardSystemManager.Instance.GetCardInventory().AddCard(upgradedCardData);
|
||||
|
||||
// Update our displayed card data
|
||||
_cardData.Rarity = newRarity;
|
||||
|
||||
// Transition to appropriate display
|
||||
if (isNewAtHigherRarity || newRarity == AppleHills.Data.CardSystem.CardRarity.Legendary)
|
||||
{
|
||||
// Show as NEW at higher rarity
|
||||
TransitionToNewCardView(newRarity);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show progress for higher rarity, then transition to NEW
|
||||
int ownedAtHigherRarity = existingHigherRarity.CopiesOwned;
|
||||
ShowProgressBar(ownedAtHigherRarity, () =>
|
||||
{
|
||||
TransitionToNewCardView(newRarity);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show this card as a repeat (enlarge, show progress bar, wait for tap)
|
||||
/// </summary>
|
||||
/// <param name="ownedCount">Number of copies owned BEFORE this one</param>
|
||||
public void ShowAsRepeat(int ownedCount)
|
||||
{
|
||||
_isNew = false;
|
||||
_ownedCount = ownedCount;
|
||||
_isWaitingForTap = true;
|
||||
|
||||
// Show repeat text
|
||||
if (repeatText != null)
|
||||
repeatText.SetActive(true);
|
||||
|
||||
// Enlarge the card
|
||||
EnlargeCard();
|
||||
|
||||
// Show progress bar with owned count, then blink new element
|
||||
ShowProgressBar(ownedCount, () =>
|
||||
{
|
||||
// Progress animation complete
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show this card as upgraded (hide progress bar, show as new with upgraded rarity)
|
||||
/// </summary>
|
||||
public void ShowAsUpgraded(AppleHills.Data.CardSystem.CardRarity oldRarity, AppleHills.Data.CardSystem.CardRarity newRarity)
|
||||
{
|
||||
_isNew = true;
|
||||
_isWaitingForTap = true;
|
||||
|
||||
// Update the CardDisplay to show new rarity
|
||||
if (cardDisplay != null && _cardData != null)
|
||||
{
|
||||
_cardData.Rarity = newRarity;
|
||||
cardDisplay.SetupCard(_cardData);
|
||||
}
|
||||
|
||||
// Hide progress bar and repeat text
|
||||
if (progressBarContainer != null)
|
||||
progressBarContainer.SetActive(false);
|
||||
if (repeatText != null)
|
||||
repeatText.SetActive(false);
|
||||
|
||||
// Show new card text (it's now a "new" card at the higher rarity)
|
||||
if (newCardText != null)
|
||||
newCardText.SetActive(true);
|
||||
|
||||
Debug.Log($"[FlippableCard] Card upgraded from {oldRarity} to {newRarity}! Showing as NEW.");
|
||||
|
||||
// Card is already enlarged from the repeat display, so no need to enlarge again
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show this card as upgraded with progress bar (already have copies at higher rarity)
|
||||
/// </summary>
|
||||
public void ShowAsUpgradedWithProgress(AppleHills.Data.CardSystem.CardRarity oldRarity, AppleHills.Data.CardSystem.CardRarity newRarity, int ownedAtNewRarity)
|
||||
{
|
||||
_isNew = false;
|
||||
_isWaitingForTap = false; // Don't wait for tap yet, progress bar will complete first
|
||||
|
||||
// Hide new card text
|
||||
if (newCardText != null)
|
||||
newCardText.SetActive(false);
|
||||
|
||||
// Show repeat text (it's a repeat at the new rarity)
|
||||
if (repeatText != null)
|
||||
repeatText.SetActive(true);
|
||||
|
||||
// Show progress bar for the new rarity
|
||||
ShowProgressBar(ownedAtNewRarity, () =>
|
||||
{
|
||||
// Progress animation complete - now transition to "NEW CARD" view
|
||||
TransitionToNewCardView(newRarity);
|
||||
});
|
||||
|
||||
Debug.Log($"[FlippableCard] Card upgraded from {oldRarity} to {newRarity}! Showing progress {ownedAtNewRarity}/5");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transition to "NEW CARD" view after upgrade progress completes
|
||||
/// </summary>
|
||||
private void TransitionToNewCardView(AppleHills.Data.CardSystem.CardRarity newRarity)
|
||||
{
|
||||
Debug.Log($"[FlippableCard] Transitioning to NEW CARD view at {newRarity} rarity");
|
||||
|
||||
// Update the CardDisplay to show new rarity
|
||||
if (cardDisplay != null && _cardData != null)
|
||||
{
|
||||
_cardData.Rarity = newRarity;
|
||||
cardDisplay.SetupCard(_cardData);
|
||||
}
|
||||
|
||||
// Hide progress bar and repeat text
|
||||
if (progressBarContainer != null)
|
||||
progressBarContainer.SetActive(false);
|
||||
if (repeatText != null)
|
||||
repeatText.SetActive(false);
|
||||
|
||||
// Show "NEW CARD" text
|
||||
if (newCardText != null)
|
||||
newCardText.SetActive(true);
|
||||
|
||||
// Now wait for tap
|
||||
_isNew = true;
|
||||
_isWaitingForTap = true;
|
||||
|
||||
Debug.Log($"[FlippableCard] Now showing as NEW CARD at {newRarity}, waiting for tap");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enlarge the card
|
||||
/// </summary>
|
||||
private void EnlargeCard()
|
||||
{
|
||||
Tween.LocalScale(transform, Vector3.one * enlargedScale, 0.3f, 0f, Tween.EaseOutBack);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return card to normal size
|
||||
/// </summary>
|
||||
public void ReturnToNormalSize()
|
||||
{
|
||||
Tween.LocalScale(transform, Vector3.one, 0.3f, 0f, Tween.EaseOutBack, completeCallback: () =>
|
||||
{
|
||||
// After returning to normal, hide new card text, show idle text
|
||||
if (_isNew)
|
||||
{
|
||||
if (newCardText != null)
|
||||
newCardText.SetActive(false);
|
||||
if (newCardIdleText != null)
|
||||
newCardIdleText.SetActive(true);
|
||||
}
|
||||
|
||||
// Keep repeat text visible
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show progress bar with owned count, then blink the new element
|
||||
/// </summary>
|
||||
private void ShowProgressBar(int ownedCount, System.Action onComplete)
|
||||
{
|
||||
if (progressBarContainer == null)
|
||||
{
|
||||
onComplete?.Invoke();
|
||||
return;
|
||||
}
|
||||
|
||||
progressBarContainer.SetActive(true);
|
||||
|
||||
// Get all child Image components
|
||||
UnityEngine.UI.Image[] progressElements = progressBarContainer.GetComponentsInChildren<UnityEngine.UI.Image>(true);
|
||||
|
||||
// Check if we have the required number of elements (should match cardsToUpgrade)
|
||||
if (progressElements.Length < cardsToUpgrade)
|
||||
{
|
||||
Debug.LogWarning($"[FlippableCard] Not enough Image components in progress bar! Expected {cardsToUpgrade}, found {progressElements.Length}");
|
||||
onComplete?.Invoke();
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable all elements first
|
||||
foreach (var img in progressElements)
|
||||
{
|
||||
img.enabled = false;
|
||||
}
|
||||
|
||||
// Show owned count (from the END, going backwards)
|
||||
// E.g., if owned 3 cards, enable elements at index [4], [3], [2] (last 3 elements)
|
||||
int startIndex = Mathf.Max(0, cardsToUpgrade - ownedCount);
|
||||
for (int i = startIndex; i < cardsToUpgrade && i < progressElements.Length; i++)
|
||||
{
|
||||
progressElements[i].enabled = true;
|
||||
}
|
||||
|
||||
// Wait a moment, then blink the new element
|
||||
// New element is at index (cardsToUpgrade - ownedCount - 1)
|
||||
int newElementIndex = Mathf.Max(0, cardsToUpgrade - ownedCount - 1);
|
||||
if (newElementIndex >= 0 && newElementIndex < progressElements.Length)
|
||||
{
|
||||
Tween.Value(0f, 1f, (val) => { }, 0.3f, 0f, completeCallback: () =>
|
||||
{
|
||||
BlinkProgressElement(newElementIndex, progressElements, onComplete);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
onComplete?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Blink a progress element (enable/disable rapidly)
|
||||
/// </summary>
|
||||
private void BlinkProgressElement(int index, UnityEngine.UI.Image[] elements, System.Action onComplete)
|
||||
{
|
||||
if (index < 0 || index >= elements.Length)
|
||||
{
|
||||
onComplete?.Invoke();
|
||||
return;
|
||||
}
|
||||
|
||||
UnityEngine.UI.Image element = elements[index];
|
||||
int blinkCount = 0;
|
||||
const int maxBlinks = 3;
|
||||
|
||||
void Blink()
|
||||
{
|
||||
element.enabled = !element.enabled;
|
||||
blinkCount++;
|
||||
|
||||
if (blinkCount >= maxBlinks * 2)
|
||||
{
|
||||
element.enabled = true; // End on enabled
|
||||
onComplete?.Invoke();
|
||||
}
|
||||
else
|
||||
{
|
||||
Tween.Value(0f, 1f, (val) => { }, 0.15f, 0f, completeCallback: Blink);
|
||||
}
|
||||
}
|
||||
|
||||
Blink();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable or disable clickability of this card
|
||||
/// </summary>
|
||||
public void SetClickable(bool clickable)
|
||||
{
|
||||
_isClickable = clickable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Jiggle the card (shake animation)
|
||||
/// </summary>
|
||||
public void Jiggle()
|
||||
{
|
||||
// Quick shake animation - rotate left, then right, then center
|
||||
Transform cardTransform = transform;
|
||||
Quaternion originalRotation = cardTransform.localRotation;
|
||||
|
||||
// Shake sequence: 0 -> -5 -> +5 -> 0
|
||||
Tween.LocalRotation(cardTransform, Quaternion.Euler(0, 0, -5), 0.05f, 0f, Tween.EaseInOut,
|
||||
completeCallback: () =>
|
||||
{
|
||||
Tween.LocalRotation(cardTransform, Quaternion.Euler(0, 0, 5), 0.1f, 0f, Tween.EaseInOut,
|
||||
completeCallback: () =>
|
||||
{
|
||||
Tween.LocalRotation(cardTransform, originalRotation, 0.05f, 0f, Tween.EaseInOut);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
StopIdleHover();
|
||||
|
||||
Reference in New Issue
Block a user