Merge a card refresh (#59)
- **Refactored Card Placement Flow** - Separated card presentation from orchestration logic - Extracted `CornerCardManager` for pending card lifecycle (spawn, shuffle, rebuild) - Extracted `AlbumNavigationService` for book page navigation and zone mapping - Extracted `CardEnlargeController` for backdrop management and card reparenting - Implemented controller pattern (non-MonoBehaviour) for complex logic - Cards now unparent from slots before rebuild to prevent premature destruction - **Improved Corner Card Display** - Fixed cards spawning on top of each other during rebuild - Implemented shuffle-to-front logic (remaining cards occupy slots 0→1→2) - Added smart card selection (prioritizes cards matching current album page) - Pending cards now removed from queue immediately on drag start - Corner cards rebuild after each placement with proper slot reassignment - **Enhanced Album Card Viewing** - Added dramatic scale increase when viewing cards from album slots - Implemented shrink animation when dismissing enlarged cards - Cards transition: `PlacedInSlotState` → `AlbumEnlargedState` → `PlacedInSlotState` - Backdrop shows/hides with card enlarge/shrink cycle - Cards reparent to enlarged container while viewing, return to slot after - **State Machine Improvements** - Added `CardStateNames` constants for type-safe state transitions - Implemented `ICardClickHandler` and `ICardStateDragHandler` interfaces - State transitions now use cached property indices - `BoosterCardContext` separated from `CardContext` for single responsibility - **Code Cleanup** - Identified unused `SlotContainerHelper.cs` (superseded by `CornerCardManager`) - Identified unused `BoosterPackDraggable.canOpenOnDrop` field - Identified unused `AlbumViewPage._previousInputMode` (hardcoded value) - Identified unused `Card.OnPlacedInAlbumSlot` event (no subscribers) Co-authored-by: Michal Pikulski <michal.a.pikulski@gmail.com> Co-authored-by: Michal Pikulski <michal@foolhardyhorizons.com> Reviewed-on: #59
This commit is contained in:
206
Assets/Scripts/CardSystem/Data/CardVisualConfig.cs
Normal file
206
Assets/Scripts/CardSystem/Data/CardVisualConfig.cs
Normal file
@@ -0,0 +1,206 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Core;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AppleHills.Data.CardSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// ScriptableObject containing visual configuration for card display
|
||||
/// Maps card rarities to frames/overlays and zones to backgrounds/shapes
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "CardVisualConfig", menuName = "AppleHills/Card System/Visual Config")]
|
||||
public class CardVisualConfig : ScriptableObject
|
||||
{
|
||||
[Serializable]
|
||||
public class RarityVisualMapping
|
||||
{
|
||||
public CardRarity rarity;
|
||||
[Tooltip("Frame image for this rarity")]
|
||||
public Sprite frame;
|
||||
[Tooltip("Overlay image for this rarity (can be null)")]
|
||||
public Sprite overlay;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ZoneVisualMapping
|
||||
{
|
||||
public CardZone zone;
|
||||
[Tooltip("Background image for this zone")]
|
||||
public Sprite background;
|
||||
[Tooltip("Shape sprite for Normal rarity cards in this zone")]
|
||||
public Sprite shapeNormal;
|
||||
[Tooltip("Shape sprite for Rare rarity cards in this zone")]
|
||||
public Sprite shapeRare;
|
||||
}
|
||||
|
||||
[Header("Rarity Configuration")]
|
||||
[Tooltip("Visual mappings for different card rarities (frames and overlays)")]
|
||||
[SerializeField] private List<RarityVisualMapping> rarityVisuals = new List<RarityVisualMapping>();
|
||||
|
||||
[Header("Zone Configuration")]
|
||||
[Tooltip("Visual mappings for different card zones (backgrounds and shapes)")]
|
||||
[SerializeField] private List<ZoneVisualMapping> zoneVisuals = new List<ZoneVisualMapping>();
|
||||
|
||||
[Header("Legendary Override")]
|
||||
[Tooltip("Background used for all Legendary cards, regardless of zone")]
|
||||
[SerializeField] private Sprite legendaryBackground;
|
||||
|
||||
private Dictionary<CardRarity, RarityVisualMapping> _rarityLookup;
|
||||
private Dictionary<CardZone, ZoneVisualMapping> _zoneLookup;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the lookup dictionaries when the asset is loaded
|
||||
/// </summary>
|
||||
private void OnEnable()
|
||||
{
|
||||
InitializeLookups();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds the lookup dictionaries from the serialized lists
|
||||
/// </summary>
|
||||
private void InitializeLookups()
|
||||
{
|
||||
// Build rarity visual lookup
|
||||
_rarityLookup = new Dictionary<CardRarity, RarityVisualMapping>();
|
||||
foreach (var mapping in rarityVisuals)
|
||||
{
|
||||
_rarityLookup[mapping.rarity] = mapping;
|
||||
}
|
||||
|
||||
// Build zone visual lookup
|
||||
_zoneLookup = new Dictionary<CardZone, ZoneVisualMapping>();
|
||||
foreach (var mapping in zoneVisuals)
|
||||
{
|
||||
_zoneLookup[mapping.zone] = mapping;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the frame sprite for a specific card rarity
|
||||
/// </summary>
|
||||
public Sprite GetRarityFrame(CardRarity rarity)
|
||||
{
|
||||
if (_rarityLookup == null) InitializeLookups();
|
||||
|
||||
if (_rarityLookup.TryGetValue(rarity, out RarityVisualMapping mapping))
|
||||
{
|
||||
return mapping.frame;
|
||||
}
|
||||
|
||||
Logging.Warning($"[CardVisualConfig] No frame mapping found for rarity {rarity}");
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the overlay sprite for a specific card rarity (can be null)
|
||||
/// </summary>
|
||||
public Sprite GetRarityOverlay(CardRarity rarity)
|
||||
{
|
||||
if (_rarityLookup == null) InitializeLookups();
|
||||
|
||||
if (_rarityLookup.TryGetValue(rarity, out RarityVisualMapping mapping))
|
||||
{
|
||||
return mapping.overlay;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the background sprite for a card based on zone and rarity
|
||||
/// Legendary cards always use the legendary background override
|
||||
/// </summary>
|
||||
public Sprite GetBackground(CardZone zone, CardRarity rarity)
|
||||
{
|
||||
if (_zoneLookup == null) InitializeLookups();
|
||||
|
||||
// Legendary cards use special background
|
||||
if (rarity == CardRarity.Legendary)
|
||||
{
|
||||
return legendaryBackground;
|
||||
}
|
||||
|
||||
// Normal and Rare cards use zone background
|
||||
if (_zoneLookup.TryGetValue(zone, out ZoneVisualMapping mapping))
|
||||
{
|
||||
return mapping.background;
|
||||
}
|
||||
|
||||
Logging.Warning($"[CardVisualConfig] No background mapping found for zone {zone}");
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the shape sprite for a card based on zone and rarity
|
||||
/// Legendary cards don't display shapes (returns null)
|
||||
/// </summary>
|
||||
public Sprite GetZoneShape(CardZone zone, CardRarity rarity)
|
||||
{
|
||||
if (_zoneLookup == null) InitializeLookups();
|
||||
|
||||
// Legendary cards don't have shapes
|
||||
if (rarity == CardRarity.Legendary)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (_zoneLookup.TryGetValue(zone, out ZoneVisualMapping mapping))
|
||||
{
|
||||
// Return shape based on rarity
|
||||
return rarity == CardRarity.Rare ? mapping.shapeRare : mapping.shapeNormal;
|
||||
}
|
||||
|
||||
Logging.Warning($"[CardVisualConfig] No shape mapping found for zone {zone}");
|
||||
return null;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// Editor-only utility to initialize the config with default structure
|
||||
/// </summary>
|
||||
public void InitializeDefaults()
|
||||
{
|
||||
// Clear existing mappings
|
||||
rarityVisuals.Clear();
|
||||
zoneVisuals.Clear();
|
||||
|
||||
// Add entries for all rarities
|
||||
foreach (CardRarity rarity in Enum.GetValues(typeof(CardRarity)))
|
||||
{
|
||||
rarityVisuals.Add(new RarityVisualMapping { rarity = rarity });
|
||||
}
|
||||
|
||||
// Add entries for all zones
|
||||
foreach (CardZone zone in Enum.GetValues(typeof(CardZone)))
|
||||
{
|
||||
zoneVisuals.Add(new ZoneVisualMapping { zone = zone });
|
||||
}
|
||||
|
||||
// Initialize the lookups
|
||||
InitializeLookups();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[UnityEditor.CustomEditor(typeof(CardVisualConfig))]
|
||||
public class CardVisualConfigEditor : UnityEditor.Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
DrawDefaultInspector();
|
||||
|
||||
CardVisualConfig config = (CardVisualConfig)target;
|
||||
|
||||
UnityEditor.EditorGUILayout.Space();
|
||||
if (GUILayout.Button("Initialize Default Structure"))
|
||||
{
|
||||
config.InitializeDefaults();
|
||||
UnityEditor.EditorUtility.SetDirty(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
Reference in New Issue
Block a user