From 359e0e35bd433c318d7366b8e15d99f6ce76260f Mon Sep 17 00:00:00 2001 From: Michal Pikulski Date: Wed, 19 Nov 2025 08:30:47 +0100 Subject: [PATCH 1/2] Stash work on mingame --- .../Editor/Settings/SettingsEditorWindow.cs | 7 +- .../Core/Settings/CardSortingSettings.cs | 97 ++ .../Core/Settings/CardSortingSettings.cs.meta | 3 + .../Core/Settings/ICardSortingSettings.cs | 40 + .../Settings/ICardSortingSettings.cs.meta | 3 + Assets/Scripts/Minigames/CardSorting.meta | 3 + .../Minigames/CardSorting/Controllers.meta | 3 + .../Controllers/ConveyorBeltController.cs | 266 ++++ .../ConveyorBeltController.cs.meta | 3 + .../Controllers/SortingScoreController.cs | 88 ++ .../SortingScoreController.cs.meta | 3 + .../Scripts/Minigames/CardSorting/Core.meta | 3 + .../CardSorting/Core/GarbageVisual.cs | 36 + .../CardSorting/Core/GarbageVisual.cs.meta | 3 + .../CardSorting/Core/SortableItem.cs | 179 +++ .../CardSorting/Core/SortableItem.cs.meta | 3 + .../CardSorting/Core/SortableItemContext.cs | 99 ++ .../Core/SortableItemContext.cs.meta | 3 + .../Minigames/CardSorting/Core/SortingBox.cs | 41 + .../CardSorting/Core/SortingBox.cs.meta | 3 + .../CardSorting/Core/SortingGameManager.cs | 239 ++++ .../Core/SortingGameManager.cs.meta | 3 + .../Scripts/Minigames/CardSorting/Data.meta | 3 + .../Minigames/CardSorting/Data/Enums.cs | 14 + .../Minigames/CardSorting/Data/Enums.cs.meta | 3 + .../CardSorting/Data/GarbageItemDefinition.cs | 38 + .../Data/GarbageItemDefinition.cs.meta | 3 + .../Minigames/CardSorting/StateMachine.meta | 3 + .../StateMachine/SortingStateMachine.cs | 21 + .../StateMachine/SortingStateMachine.cs.meta | 3 + .../CardSorting/StateMachine/States.meta | 3 + .../StateMachine/States/BeingDraggedState.cs | 51 + .../States/BeingDraggedState.cs.meta | 3 + .../StateMachine/States/OnConveyorState.cs | 62 + .../States/OnConveyorState.cs.meta | 3 + .../StateMachine/States/SortedState.cs | 34 + .../StateMachine/States/SortedState.cs.meta | 3 + Assets/Scripts/Minigames/CardSorting/UI.meta | 3 + .../CardSorting/UI/SortingGameHUD.cs | 116 ++ .../CardSorting/UI/SortingGameHUD.cs.meta | 3 + .../CardSorting/UI/SortingResultsScreen.cs | 126 ++ .../UI/SortingResultsScreen.cs.meta | 3 + docs/card_sorting_minigame_plan.md | 1114 +++++++++++++++++ 43 files changed, 2739 insertions(+), 1 deletion(-) create mode 100644 Assets/Scripts/Core/Settings/CardSortingSettings.cs create mode 100644 Assets/Scripts/Core/Settings/CardSortingSettings.cs.meta create mode 100644 Assets/Scripts/Core/Settings/ICardSortingSettings.cs create mode 100644 Assets/Scripts/Core/Settings/ICardSortingSettings.cs.meta create mode 100644 Assets/Scripts/Minigames/CardSorting.meta create mode 100644 Assets/Scripts/Minigames/CardSorting/Controllers.meta create mode 100644 Assets/Scripts/Minigames/CardSorting/Controllers/ConveyorBeltController.cs create mode 100644 Assets/Scripts/Minigames/CardSorting/Controllers/ConveyorBeltController.cs.meta create mode 100644 Assets/Scripts/Minigames/CardSorting/Controllers/SortingScoreController.cs create mode 100644 Assets/Scripts/Minigames/CardSorting/Controllers/SortingScoreController.cs.meta create mode 100644 Assets/Scripts/Minigames/CardSorting/Core.meta create mode 100644 Assets/Scripts/Minigames/CardSorting/Core/GarbageVisual.cs create mode 100644 Assets/Scripts/Minigames/CardSorting/Core/GarbageVisual.cs.meta create mode 100644 Assets/Scripts/Minigames/CardSorting/Core/SortableItem.cs create mode 100644 Assets/Scripts/Minigames/CardSorting/Core/SortableItem.cs.meta create mode 100644 Assets/Scripts/Minigames/CardSorting/Core/SortableItemContext.cs create mode 100644 Assets/Scripts/Minigames/CardSorting/Core/SortableItemContext.cs.meta create mode 100644 Assets/Scripts/Minigames/CardSorting/Core/SortingBox.cs create mode 100644 Assets/Scripts/Minigames/CardSorting/Core/SortingBox.cs.meta create mode 100644 Assets/Scripts/Minigames/CardSorting/Core/SortingGameManager.cs create mode 100644 Assets/Scripts/Minigames/CardSorting/Core/SortingGameManager.cs.meta create mode 100644 Assets/Scripts/Minigames/CardSorting/Data.meta create mode 100644 Assets/Scripts/Minigames/CardSorting/Data/Enums.cs create mode 100644 Assets/Scripts/Minigames/CardSorting/Data/Enums.cs.meta create mode 100644 Assets/Scripts/Minigames/CardSorting/Data/GarbageItemDefinition.cs create mode 100644 Assets/Scripts/Minigames/CardSorting/Data/GarbageItemDefinition.cs.meta create mode 100644 Assets/Scripts/Minigames/CardSorting/StateMachine.meta create mode 100644 Assets/Scripts/Minigames/CardSorting/StateMachine/SortingStateMachine.cs create mode 100644 Assets/Scripts/Minigames/CardSorting/StateMachine/SortingStateMachine.cs.meta create mode 100644 Assets/Scripts/Minigames/CardSorting/StateMachine/States.meta create mode 100644 Assets/Scripts/Minigames/CardSorting/StateMachine/States/BeingDraggedState.cs create mode 100644 Assets/Scripts/Minigames/CardSorting/StateMachine/States/BeingDraggedState.cs.meta create mode 100644 Assets/Scripts/Minigames/CardSorting/StateMachine/States/OnConveyorState.cs create mode 100644 Assets/Scripts/Minigames/CardSorting/StateMachine/States/OnConveyorState.cs.meta create mode 100644 Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedState.cs create mode 100644 Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedState.cs.meta create mode 100644 Assets/Scripts/Minigames/CardSorting/UI.meta create mode 100644 Assets/Scripts/Minigames/CardSorting/UI/SortingGameHUD.cs create mode 100644 Assets/Scripts/Minigames/CardSorting/UI/SortingGameHUD.cs.meta create mode 100644 Assets/Scripts/Minigames/CardSorting/UI/SortingResultsScreen.cs create mode 100644 Assets/Scripts/Minigames/CardSorting/UI/SortingResultsScreen.cs.meta create mode 100644 docs/card_sorting_minigame_plan.md diff --git a/Assets/Editor/Settings/SettingsEditorWindow.cs b/Assets/Editor/Settings/SettingsEditorWindow.cs index 039e5963..53eb23ec 100644 --- a/Assets/Editor/Settings/SettingsEditorWindow.cs +++ b/Assets/Editor/Settings/SettingsEditorWindow.cs @@ -3,6 +3,7 @@ using UnityEditor; using System.Collections.Generic; using System.Linq; using System.IO; +using Core.Settings; namespace AppleHills.Core.Settings.Editor { @@ -10,7 +11,7 @@ namespace AppleHills.Core.Settings.Editor { private Vector2 scrollPosition; private List allSettings = new List(); - private string[] tabNames = new string[] { "Player & Follower", "Interaction & Items", "Diving Minigame", "Card System" }; + private string[] tabNames = new string[] { "Player & Follower", "Interaction & Items", "Diving Minigame", "Card System", "Card Sorting" }; private int selectedTab = 0; private Dictionary serializedSettingsObjects = new Dictionary(); private GUIStyle headerStyle; @@ -49,6 +50,7 @@ namespace AppleHills.Core.Settings.Editor CreateSettingsIfMissing("InteractionSettings"); CreateSettingsIfMissing("DivingMinigameSettings"); CreateSettingsIfMissing("CardSystemSettings"); + CreateSettingsIfMissing("CardSortingSettings"); } private void CreateSettingsIfMissing(string fileName) where T : BaseSettings @@ -118,6 +120,9 @@ namespace AppleHills.Core.Settings.Editor case 3: // Card System DrawSettingsEditor(); break; + case 4: // Card Sorting + DrawSettingsEditor(); + break; } EditorGUILayout.EndScrollView(); diff --git a/Assets/Scripts/Core/Settings/CardSortingSettings.cs b/Assets/Scripts/Core/Settings/CardSortingSettings.cs new file mode 100644 index 00000000..5ecc8a5e --- /dev/null +++ b/Assets/Scripts/Core/Settings/CardSortingSettings.cs @@ -0,0 +1,97 @@ +using AppleHills.Core.Settings; +using Minigames.CardSorting.Data; +using UnityEngine; + +namespace Core.Settings +{ + /// + /// Settings for Card Sorting minigame. + /// Follows DivingMinigameSettings pattern. + /// + [CreateAssetMenu(fileName = "CardSortingSettings", menuName = "AppleHills/Settings/CardSorting", order = 4)] + public class CardSortingSettings : BaseSettings, ICardSortingSettings + { + [Header("Timing")] + [Tooltip("Total game duration in seconds")] + [SerializeField] private float gameDuration = 120f; + + [Tooltip("Initial time between item spawns (seconds)")] + [SerializeField] private float initialSpawnInterval = 2f; + + [Tooltip("Minimum time between item spawns as difficulty increases (seconds)")] + [SerializeField] private float minimumSpawnInterval = 0.5f; + + [Header("Conveyor Speed")] + [Tooltip("Initial belt movement speed")] + [SerializeField] private float initialBeltSpeed = 1f; + + [Tooltip("Maximum belt movement speed")] + [SerializeField] private float maxBeltSpeed = 3f; + + [Tooltip("Curve for difficulty progression (X=time%, Y=speed multiplier)")] + [SerializeField] private AnimationCurve speedCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); + + [Header("Item Pools")] + [Tooltip("Garbage items that can spawn (banana peels, cans, receipts, etc.)")] + [SerializeField] private GarbageItemDefinition[] garbageItems = new GarbageItemDefinition[0]; + + [Header("Spawn Weights")] + [Tooltip("Weight for spawning normal rarity cards")] + [Range(0, 100)] [SerializeField] private float normalCardWeight = 40f; + + [Tooltip("Weight for spawning rare rarity cards")] + [Range(0, 100)] [SerializeField] private float rareCardWeight = 30f; + + [Tooltip("Weight for spawning legendary rarity cards")] + [Range(0, 100)] [SerializeField] private float legendCardWeight = 20f; + + [Tooltip("Weight for spawning garbage items")] + [Range(0, 100)] [SerializeField] private float garbageWeight = 10f; + + [Header("Scoring")] + [Tooltip("Points awarded for correct sort")] + [SerializeField] private int correctSortPoints = 10; + + [Tooltip("Points deducted for incorrect sort")] + [SerializeField] private int incorrectSortPenalty = -5; + + [Tooltip("Points deducted when item falls off belt")] + [SerializeField] private int missedItemPenalty = -3; + + [Header("Rewards")] + [Tooltip("Booster packs awarded per correct sort")] + [SerializeField] private int boosterPacksPerCorrectItem = 1; + + // Interface implementation + public float GameDuration => gameDuration; + public float InitialSpawnInterval => initialSpawnInterval; + public float MinimumSpawnInterval => minimumSpawnInterval; + public float InitialBeltSpeed => initialBeltSpeed; + public float MaxBeltSpeed => maxBeltSpeed; + public AnimationCurve SpeedCurve => speedCurve; + public GarbageItemDefinition[] GarbageItems => garbageItems; + public float NormalCardWeight => normalCardWeight; + public float RareCardWeight => rareCardWeight; + public float LegendCardWeight => legendCardWeight; + public float GarbageWeight => garbageWeight; + public int CorrectSortPoints => correctSortPoints; + public int IncorrectSortPenalty => incorrectSortPenalty; + public int MissedItemPenalty => missedItemPenalty; + public int BoosterPacksPerCorrectItem => boosterPacksPerCorrectItem; + + public override void OnValidate() + { + base.OnValidate(); + + gameDuration = Mathf.Max(1f, gameDuration); + initialSpawnInterval = Mathf.Max(0.1f, initialSpawnInterval); + minimumSpawnInterval = Mathf.Max(0.1f, minimumSpawnInterval); + minimumSpawnInterval = Mathf.Min(minimumSpawnInterval, initialSpawnInterval); + initialBeltSpeed = Mathf.Max(0.1f, initialBeltSpeed); + maxBeltSpeed = Mathf.Max(initialBeltSpeed, maxBeltSpeed); + correctSortPoints = Mathf.Max(0, correctSortPoints); + boosterPacksPerCorrectItem = Mathf.Max(0, boosterPacksPerCorrectItem); + } + } +} + diff --git a/Assets/Scripts/Core/Settings/CardSortingSettings.cs.meta b/Assets/Scripts/Core/Settings/CardSortingSettings.cs.meta new file mode 100644 index 00000000..c9c99aa5 --- /dev/null +++ b/Assets/Scripts/Core/Settings/CardSortingSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a0fd5f8ab5d74b12968501dd4e3cc416 +timeCreated: 1763461789 \ No newline at end of file diff --git a/Assets/Scripts/Core/Settings/ICardSortingSettings.cs b/Assets/Scripts/Core/Settings/ICardSortingSettings.cs new file mode 100644 index 00000000..89ab9d05 --- /dev/null +++ b/Assets/Scripts/Core/Settings/ICardSortingSettings.cs @@ -0,0 +1,40 @@ +using Minigames.CardSorting.Data; +using UnityEngine; + +namespace Core.Settings +{ + /// + /// Settings interface for Card Sorting minigame. + /// Accessed via GameManager.GetSettingsObject<ICardSortingSettings>() + /// + public interface ICardSortingSettings + { + // Timing + float GameDuration { get; } + float InitialSpawnInterval { get; } + float MinimumSpawnInterval { get; } + + // Conveyor Speed + float InitialBeltSpeed { get; } + float MaxBeltSpeed { get; } + AnimationCurve SpeedCurve { get; } + + // Item Pools + GarbageItemDefinition[] GarbageItems { get; } + + // Spawn Weights + float NormalCardWeight { get; } + float RareCardWeight { get; } + float LegendCardWeight { get; } + float GarbageWeight { get; } + + // Scoring + int CorrectSortPoints { get; } + int IncorrectSortPenalty { get; } + int MissedItemPenalty { get; } + + // Rewards + int BoosterPacksPerCorrectItem { get; } + } +} + diff --git a/Assets/Scripts/Core/Settings/ICardSortingSettings.cs.meta b/Assets/Scripts/Core/Settings/ICardSortingSettings.cs.meta new file mode 100644 index 00000000..fa644e0e --- /dev/null +++ b/Assets/Scripts/Core/Settings/ICardSortingSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 646b90dfa92640e59430f871037affea +timeCreated: 1763461774 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting.meta b/Assets/Scripts/Minigames/CardSorting.meta new file mode 100644 index 00000000..3285e18d --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1f5c5963e2ff4b33a086f5b97e648914 +timeCreated: 1763461758 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting/Controllers.meta b/Assets/Scripts/Minigames/CardSorting/Controllers.meta new file mode 100644 index 00000000..dbf2ca7d --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/Controllers.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d35b6d1850b94234bbb54e77b202861b +timeCreated: 1763469999 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting/Controllers/ConveyorBeltController.cs b/Assets/Scripts/Minigames/CardSorting/Controllers/ConveyorBeltController.cs new file mode 100644 index 00000000..587a3f34 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/Controllers/ConveyorBeltController.cs @@ -0,0 +1,266 @@ +using AppleHills.Data.CardSystem; +using Core.Settings; +using Data.CardSystem; +using Minigames.CardSorting.Core; +using Minigames.CardSorting.Data; +using System.Collections.Generic; +using UnityEngine; + +namespace Minigames.CardSorting.Controllers +{ + /// + /// Non-MonoBehaviour controller for conveyor belt logic. + /// Handles spawning, speed, item lifecycle. + /// Parallel to CornerCardManager in card system. + /// + public class ConveyorBeltController + { + private readonly Transform spawnPoint; + private readonly Transform endPoint; + private readonly GameObject cardPrefab; + private readonly GameObject garbagePrefab; + private readonly ICardSortingSettings settings; + + private List activeItems = new List(); + private float currentSpeed; + private float nextSpawnTime; + + public float CurrentSpeed => currentSpeed; + public int ActiveItemCount => activeItems.Count; + + public ConveyorBeltController( + Transform spawnPoint, + Transform endPoint, + GameObject cardPrefab, + GameObject garbagePrefab, + ICardSortingSettings settings) + { + this.spawnPoint = spawnPoint; + this.endPoint = endPoint; + this.cardPrefab = cardPrefab; + this.garbagePrefab = garbagePrefab; + this.settings = settings; + + this.currentSpeed = settings.InitialBeltSpeed; + this.nextSpawnTime = 0f; + } + + /// + /// Update belt speed and check for items falling off. + /// + public void Update(float deltaTime, float gameProgress) + { + UpdateBeltSpeed(gameProgress); + CheckItemsOffBelt(); + } + + /// + /// Try to spawn an item if enough time has passed. + /// + public SortableItem TrySpawnItem(float currentTime, float gameProgress) + { + if (currentTime < nextSpawnTime) return null; + + // Weighted random: card or garbage? + float totalWeight = settings.NormalCardWeight + settings.RareCardWeight + + settings.LegendCardWeight + settings.GarbageWeight; + + if (totalWeight <= 0f) + { + Debug.LogWarning("[ConveyorBeltController] Total spawn weight is 0, cannot spawn items!"); + return null; + } + + float roll = Random.Range(0f, totalWeight); + + SortableItem item; + + if (roll < settings.GarbageWeight) + { + // Spawn garbage + item = SpawnGarbageItem(); + } + else + { + // Spawn card - determine rarity, get random card from CardSystemManager + CardRarity rarity = DetermineRarity(roll); + item = SpawnCardItem(rarity); + } + + if (item != null) + { + // Set conveyor speed on item + item.Context.ConveyorSpeed = currentSpeed; + + activeItems.Add(item); + ScheduleNextSpawn(gameProgress); + } + + return item; + } + + /// + /// Remove item from tracking (when sorted or missed). + /// + public void RemoveItem(SortableItem item) + { + activeItems.Remove(item); + } + + private SortableItem SpawnGarbageItem() + { + if (settings.GarbageItems == null || settings.GarbageItems.Length == 0) + { + Debug.LogWarning("[ConveyorBeltController] No garbage items configured!"); + return null; + } + + GarbageItemDefinition garbage = SelectRandomGarbage(); + + GameObject obj = Object.Instantiate(garbagePrefab, spawnPoint.position, Quaternion.identity); + SortableItem item = obj.GetComponent(); + + if (item != null) + { + item.SetupAsGarbage(garbage); + } + else + { + Debug.LogError("[ConveyorBeltController] Garbage prefab missing SortableItem component!"); + Object.Destroy(obj); + return null; + } + + return item; + } + + private SortableItem SpawnCardItem(CardRarity rarity) + { + // Get a random card of the specified rarity + CardData cardData = GetRandomCardDataByRarity(rarity); + + if (cardData == null) + { + Debug.LogWarning($"[ConveyorBeltController] No card data found for rarity {rarity}"); + return null; + } + + GameObject obj = Object.Instantiate(cardPrefab, spawnPoint.position, Quaternion.identity); + SortableItem item = obj.GetComponent(); + + if (item != null) + { + item.SetupAsCard(cardData); + } + else + { + Debug.LogError("[ConveyorBeltController] Card prefab missing SortableItem component!"); + Object.Destroy(obj); + return null; + } + + return item; + } + + /// + /// Helper method to get a random card of a specific rarity. + /// Uses CardSystemManager's internal DrawRandomCards logic. + /// + private CardData GetRandomCardDataByRarity(CardRarity targetRarity) + { + // Use reflection or create cards manually + // For now, open a temporary booster and filter + // This is not ideal but works until we add a proper method to CardSystemManager + + // Better approach: Draw cards until we get one of the right rarity + // Simulate drawing process + int maxAttempts = 20; + for (int i = 0; i < maxAttempts; i++) + { + var drawnCards = CardSystemManager.Instance.OpenBoosterPack(); + CardSystemManager.Instance.AddBoosterPack(); // Restore the booster we used + + var matchingCard = drawnCards.Find(c => c.Rarity == targetRarity); + if (matchingCard != null) + { + return matchingCard; + } + } + + Debug.LogWarning($"[ConveyorBeltController] Failed to draw card of rarity {targetRarity} after {maxAttempts} attempts"); + return null; + } + + private void UpdateBeltSpeed(float gameProgress) + { + // Evaluate speed curve + float speedMultiplier = settings.SpeedCurve.Evaluate(gameProgress); + currentSpeed = Mathf.Lerp( + settings.InitialBeltSpeed, + settings.MaxBeltSpeed, + speedMultiplier + ); + + // Update all active items + foreach (var item in activeItems) + { + if (item != null && item.Context.IsOnConveyor) + { + item.Context.ConveyorSpeed = currentSpeed; + } + } + } + + private void CheckItemsOffBelt() + { + for (int i = activeItems.Count - 1; i >= 0; i--) + { + var item = activeItems[i]; + if (item == null) + { + activeItems.RemoveAt(i); + continue; + } + + // Check if past end point + if (item.transform.position.x > endPoint.position.x) + { + item.OnFellOffBelt(); + activeItems.RemoveAt(i); + } + } + } + + private void ScheduleNextSpawn(float gameProgress) + { + // Calculate next spawn time based on difficulty progression + float interval = Mathf.Lerp( + settings.InitialSpawnInterval, + settings.MinimumSpawnInterval, + gameProgress + ); + + nextSpawnTime = Time.time + interval; + } + + private CardRarity DetermineRarity(float roll) + { + // Adjust roll to be relative to card weights only (subtract garbage weight) + float adjusted = roll - settings.GarbageWeight; + + if (adjusted < settings.NormalCardWeight) + return CardRarity.Normal; + + if (adjusted < settings.NormalCardWeight + settings.RareCardWeight) + return CardRarity.Rare; + + return CardRarity.Legendary; + } + + private GarbageItemDefinition SelectRandomGarbage() + { + return settings.GarbageItems[Random.Range(0, settings.GarbageItems.Length)]; + } + } +} + diff --git a/Assets/Scripts/Minigames/CardSorting/Controllers/ConveyorBeltController.cs.meta b/Assets/Scripts/Minigames/CardSorting/Controllers/ConveyorBeltController.cs.meta new file mode 100644 index 00000000..9d440ea8 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/Controllers/ConveyorBeltController.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 681596c1ece04da18b2c3394441ebd4b +timeCreated: 1763469999 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting/Controllers/SortingScoreController.cs b/Assets/Scripts/Minigames/CardSorting/Controllers/SortingScoreController.cs new file mode 100644 index 00000000..493c9da0 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/Controllers/SortingScoreController.cs @@ -0,0 +1,88 @@ +using Core.Settings; +using System; + +namespace Minigames.CardSorting.Controllers +{ + /// + /// Non-MonoBehaviour controller for score tracking. + /// Handles scoring, accuracy calculation, and reward calculation. + /// + public class SortingScoreController + { + private readonly ICardSortingSettings settings; + + private int totalScore; + private int correctSorts; + private int incorrectSorts; + private int missedItems; + + public int TotalScore => totalScore; + public int CorrectSorts => correctSorts; + public int IncorrectSorts => incorrectSorts; + public int MissedItems => missedItems; + public int TotalAttempts => correctSorts + incorrectSorts; + public float Accuracy => TotalAttempts > 0 ? (float)correctSorts / TotalAttempts : 0f; + + public event Action OnScoreChanged; + public event Action OnCorrectSort; + public event Action OnIncorrectSort; + + public SortingScoreController(ICardSortingSettings settings) + { + this.settings = settings; + } + + /// + /// Record a correct sort. + /// + public void RecordCorrectSort() + { + correctSorts++; + totalScore += settings.CorrectSortPoints; + OnScoreChanged?.Invoke(totalScore); + OnCorrectSort?.Invoke(correctSorts); + } + + /// + /// Record an incorrect sort. + /// + public void RecordIncorrectSort() + { + incorrectSorts++; + totalScore += settings.IncorrectSortPenalty; // This is a negative value + OnScoreChanged?.Invoke(totalScore); + OnIncorrectSort?.Invoke(incorrectSorts); + } + + /// + /// Record a missed item (fell off belt). + /// + public void RecordMissedItem() + { + missedItems++; + totalScore += settings.MissedItemPenalty; // This is a negative value + OnScoreChanged?.Invoke(totalScore); + } + + /// + /// Calculate booster pack reward based on performance. + /// + public int CalculateBoosterReward() + { + // Simple: 1 booster per correct sort (or use settings multiplier) + return correctSorts * settings.BoosterPacksPerCorrectItem; + } + + /// + /// Reset all scores (for restarting game). + /// + public void Reset() + { + totalScore = 0; + correctSorts = 0; + incorrectSorts = 0; + missedItems = 0; + } + } +} + diff --git a/Assets/Scripts/Minigames/CardSorting/Controllers/SortingScoreController.cs.meta b/Assets/Scripts/Minigames/CardSorting/Controllers/SortingScoreController.cs.meta new file mode 100644 index 00000000..b66e1154 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/Controllers/SortingScoreController.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 280957c6e5b24e91b9fdc49ec685ed2f +timeCreated: 1763470011 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting/Core.meta b/Assets/Scripts/Minigames/CardSorting/Core.meta new file mode 100644 index 00000000..e332cfa6 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/Core.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: fa35cf17256e403ab8bed2555352eaf5 +timeCreated: 1763461824 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting/Core/GarbageVisual.cs b/Assets/Scripts/Minigames/CardSorting/Core/GarbageVisual.cs new file mode 100644 index 00000000..99de3579 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/Core/GarbageVisual.cs @@ -0,0 +1,36 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace Minigames.CardSorting.Core +{ + /// + /// Simple sprite renderer for garbage items. + /// Parallel to CardDisplay for cards. + /// + public class GarbageVisual : MonoBehaviour + { + [Header("Visual Components")] + [SerializeField] private Image spriteRenderer; + + /// + /// Update the displayed sprite. + /// + public void UpdateDisplay(Sprite sprite) + { + if (spriteRenderer != null) + { + spriteRenderer.sprite = sprite; + } + } + + private void Awake() + { + // Auto-find Image component if not assigned + if (spriteRenderer == null) + { + spriteRenderer = GetComponent(); + } + } + } +} + diff --git a/Assets/Scripts/Minigames/CardSorting/Core/GarbageVisual.cs.meta b/Assets/Scripts/Minigames/CardSorting/Core/GarbageVisual.cs.meta new file mode 100644 index 00000000..96c07f2a --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/Core/GarbageVisual.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b707770fc3a6448ea0dcd1b2fbf41e00 +timeCreated: 1763461824 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting/Core/SortableItem.cs b/Assets/Scripts/Minigames/CardSorting/Core/SortableItem.cs new file mode 100644 index 00000000..ddb1340e --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/Core/SortableItem.cs @@ -0,0 +1,179 @@ +using AppleHills.Data.CardSystem; +using Core; +using Core.SaveLoad; +using Minigames.CardSorting.Data; +using UI.DragAndDrop.Core; +using UnityEngine; + +namespace Minigames.CardSorting.Core +{ + /// + /// Draggable sortable item on conveyor belt. + /// Uses state machine for behavior (OnConveyor → BeingDragged → Sorted). + /// Inherits from DraggableObject to reuse drag/drop system. + /// + public class SortableItem : DraggableObject + { + [Header("Components")] + [SerializeField] private SortableItemContext context; + [SerializeField] private AppleMachine stateMachine; + + [Header("Configuration")] + [SerializeField] private string initialState = "OnConveyorState"; + + // Data tracking + private bool isGarbage; + private CardData cardData; + private GarbageItemDefinition garbageItem; + + // Public accessors + public SortableItemContext Context => context; + public AppleMachine StateMachine => stateMachine; + public bool IsGarbage => isGarbage; + public CardData CardData => cardData; + public GarbageItemDefinition GarbageItem => garbageItem; + + /// + /// Get the correct box type for this item. + /// + public BoxType CorrectBox + { + get + { + if (isGarbage) + return BoxType.Trash; + + return cardData.Rarity switch + { + CardRarity.Normal => BoxType.Normal, + CardRarity.Rare => BoxType.Rare, + CardRarity.Legendary => BoxType.Legend, + _ => BoxType.Trash + }; + } + } + + protected override void Initialize() + { + base.Initialize(); + + // Auto-find components if not assigned + if (context == null) + context = GetComponent(); + + if (stateMachine == null) + stateMachine = GetComponentInChildren(); + } + + /// + /// Setup item as a card. + /// + public void SetupAsCard(CardData data) + { + isGarbage = false; + cardData = data; + garbageItem = null; + + if (context != null) + { + context.SetupAsCard(data); + } + + if (stateMachine != null && !string.IsNullOrEmpty(initialState)) + { + stateMachine.ChangeState(initialState); + } + } + + /// + /// Setup item as garbage. + /// + public void SetupAsGarbage(GarbageItemDefinition garbage) + { + isGarbage = true; + cardData = default; + garbageItem = garbage; + + if (context != null) + { + context.SetupAsGarbage(garbage.Sprite); + } + + if (stateMachine != null && !string.IsNullOrEmpty(initialState)) + { + stateMachine.ChangeState(initialState); + } + } + + protected override void OnDragStartedHook() + { + base.OnDragStartedHook(); + + // Check if current state wants to handle drag behavior + if (stateMachine?.currentState != null) + { + var dragHandler = stateMachine.currentState.GetComponent(); + if (dragHandler != null && dragHandler.OnDragStarted(context)) + { + return; // State handled it + } + } + + // Default behavior if state doesn't handle + Logging.Debug($"[SortableItem] Drag started on {(isGarbage ? garbageItem.DisplayName : cardData.Name)}"); + } + + protected override void OnDragEndedHook() + { + base.OnDragEndedHook(); + + // Validate drop on sorting box + if (CurrentSlot is SortingBox box) + { + bool correctSort = box.ValidateItem(this); + + // Notify game manager + SortingGameManager.Instance?.OnItemSorted(this, box, correctSort); + + // Transition to sorted state + ChangeState("SortedState"); + } + else + { + // Dropped outside valid box - return to conveyor + Logging.Debug("[SortableItem] Dropped outside box, returning to conveyor"); + ChangeState("OnConveyorState"); + } + } + + /// + /// Change to a specific state. + /// + public void ChangeState(string stateName) + { + if (stateMachine != null) + { + stateMachine.ChangeState(stateName); + } + } + + /// + /// Called when item falls off conveyor belt. + /// + public void OnFellOffBelt() + { + // Notify game manager + SortingGameManager.Instance?.OnItemMissed(this); + Destroy(gameObject); + } + } + + /// + /// Interface for states that handle drag behavior. + /// + public interface ISortableItemDragHandler + { + bool OnDragStarted(SortableItemContext context); + } +} + diff --git a/Assets/Scripts/Minigames/CardSorting/Core/SortableItem.cs.meta b/Assets/Scripts/Minigames/CardSorting/Core/SortableItem.cs.meta new file mode 100644 index 00000000..3ca3844d --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/Core/SortableItem.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9b3db9ce867c4df884411fb3da8fd80a +timeCreated: 1763461867 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting/Core/SortableItemContext.cs b/Assets/Scripts/Minigames/CardSorting/Core/SortableItemContext.cs new file mode 100644 index 00000000..87d560d1 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/Core/SortableItemContext.cs @@ -0,0 +1,99 @@ +using AppleHills.Data.CardSystem; +using Core.SaveLoad; +using UI.CardSystem; +using UI.CardSystem.StateMachine; +using UnityEngine; + +namespace Minigames.CardSorting.Core +{ + /// + /// Shared context for sortable item states. + /// Provides access to common components and data that states need. + /// Routes data to appropriate visual component (CardDisplay for cards, GarbageVisual for garbage). + /// + public class SortableItemContext : MonoBehaviour + { + [Header("Visual Components (one or the other)")] + [SerializeField] private CardDisplay cardDisplay; // For cards + [SerializeField] private GarbageVisual garbageVisual; // For garbage + + [Header("Shared Components")] + [SerializeField] private CardAnimator animator; + [SerializeField] private Transform visualTransform; // "Visual" GameObject + + private AppleMachine stateMachine; + + // Public accessors + public CardDisplay CardDisplay => cardDisplay; + public GarbageVisual GarbageVisual => garbageVisual; + public CardAnimator Animator => animator; + public Transform VisualTransform => visualTransform; + public AppleMachine StateMachine => stateMachine; + public Transform RootTransform => transform; + + // Conveyor state + public bool IsOnConveyor { get; set; } = true; + public float ConveyorSpeed { get; set; } = 1f; + + private void Awake() + { + // Auto-find components if not assigned + if (visualTransform == null) + { + visualTransform = transform.Find("Visual"); + if (visualTransform == null) + { + Debug.LogWarning($"[SortableItemContext] 'Visual' child GameObject not found on {name}"); + } + } + + if (animator == null && visualTransform != null) + { + animator = visualTransform.GetComponent(); + } + + if (cardDisplay == null && visualTransform != null) + { + cardDisplay = visualTransform.GetComponentInChildren(); + } + + if (garbageVisual == null && visualTransform != null) + { + garbageVisual = visualTransform.GetComponentInChildren(); + } + + stateMachine = GetComponentInChildren(); + } + + /// + /// Setup as card item - CardDisplay handles all rendering. + /// + public void SetupAsCard(CardData cardData) + { + if (cardDisplay != null) + { + cardDisplay.SetupCard(cardData); + } + else + { + Debug.LogError($"[SortableItemContext] CardDisplay not found on {name}"); + } + } + + /// + /// Setup as garbage item - simple sprite display. + /// + public void SetupAsGarbage(Sprite sprite) + { + if (garbageVisual != null) + { + garbageVisual.UpdateDisplay(sprite); + } + else + { + Debug.LogError($"[SortableItemContext] GarbageVisual not found on {name}"); + } + } + } +} + diff --git a/Assets/Scripts/Minigames/CardSorting/Core/SortableItemContext.cs.meta b/Assets/Scripts/Minigames/CardSorting/Core/SortableItemContext.cs.meta new file mode 100644 index 00000000..d8eb5d2d --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/Core/SortableItemContext.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9a9c60767eef4a3090d8bf70ee87340f +timeCreated: 1763461839 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting/Core/SortingBox.cs b/Assets/Scripts/Minigames/CardSorting/Core/SortingBox.cs new file mode 100644 index 00000000..2bd04fcd --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/Core/SortingBox.cs @@ -0,0 +1,41 @@ +using Minigames.CardSorting.Data; +using UI.DragAndDrop.Core; +using UnityEngine; + +namespace Minigames.CardSorting.Core +{ + /// + /// Drop target for sortable items. + /// Validates if item belongs in this box. + /// + public class SortingBox : DraggableSlot + { + [Header("Box Configuration")] + [SerializeField] private BoxType boxType; + [SerializeField] private Sprite boxSprite; + + public BoxType BoxType => boxType; + + /// + /// Check if item belongs in this box. + /// + public bool ValidateItem(SortableItem item) + { + if (item == null) return false; + + BoxType correctBox = item.CorrectBox; + return correctBox == boxType; + } + + /// + /// Check if this slot can accept a specific draggable type. + /// SortingBox accepts all SortableItems (validation happens on drop). + /// + public new bool CanAccept(DraggableObject draggable) + { + // Accept all sortable items (validation happens on drop) + return draggable is SortableItem; + } + } +} + diff --git a/Assets/Scripts/Minigames/CardSorting/Core/SortingBox.cs.meta b/Assets/Scripts/Minigames/CardSorting/Core/SortingBox.cs.meta new file mode 100644 index 00000000..03014ee0 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/Core/SortingBox.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a25b1c9a82b540c8ac0d6c016849f561 +timeCreated: 1763461875 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting/Core/SortingGameManager.cs b/Assets/Scripts/Minigames/CardSorting/Core/SortingGameManager.cs new file mode 100644 index 00000000..3cfa8a07 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/Core/SortingGameManager.cs @@ -0,0 +1,239 @@ +using System; +using Core; +using Core.Lifecycle; +using Core.Settings; +using Data.CardSystem; +using Input; +using Minigames.CardSorting.Controllers; +using Minigames.CardSorting.Core; +using UnityEngine; + +namespace Minigames.CardSorting.Core +{ + /// + /// Main manager for card sorting minigame. + /// Orchestrates game loop, timer, controllers, and integration with CardSystemManager. + /// Parallel to DivingGameManager. + /// + public class SortingGameManager : ManagedBehaviour + { + [Header("Scene References")] + [SerializeField] private Transform conveyorSpawnPoint; + [SerializeField] private Transform conveyorEndPoint; + [SerializeField] private GameObject sortableCardPrefab; + [SerializeField] private GameObject sortableGarbagePrefab; + [SerializeField] private SortingBox[] sortingBoxes; + + // Settings + private ICardSortingSettings _settings; + + // Controllers (lazy init) + private ConveyorBeltController _conveyorController; + private ConveyorBeltController Conveyor => _conveyorController ??= new ConveyorBeltController( + conveyorSpawnPoint, + conveyorEndPoint, + sortableCardPrefab, + sortableGarbagePrefab, + _settings + ); + + private SortingScoreController _scoreController; + private SortingScoreController Score => _scoreController ??= new SortingScoreController(_settings); + + // Game state + private float gameTimer; + private bool isGameActive; + private bool isGameOver; + + // Singleton + private static SortingGameManager _instance; + public static SortingGameManager Instance => _instance; + + // Events + public event Action OnGameStarted; + public event Action OnGameEnded; + public event Action OnItemSpawned; + public event Action OnItemSortedEvent; + public event Action OnTimerUpdated; // Remaining time + + internal override void OnManagedAwake() + { + _instance = this; + + // Load settings + _settings = GameManager.GetSettingsObject(); + + if (_settings == null) + { + Debug.LogError("[SortingGameManager] Failed to load CardSortingSettings!"); + return; + } + + Logging.Debug("[SortingGameManager] Initialized with settings"); + } + + internal override void OnManagedStart() + { + // Subscribe to score events + Score.OnScoreChanged += OnScoreChanged; + Score.OnCorrectSort += OnCorrectSort; + Score.OnIncorrectSort += OnIncorrectSort; + + // Start game automatically or wait for trigger + // For now, auto-start + StartGame(); + } + + private void OnDestroy() + { + if (_scoreController != null) + { + Score.OnScoreChanged -= OnScoreChanged; + Score.OnCorrectSort -= OnCorrectSort; + Score.OnIncorrectSort -= OnIncorrectSort; + } + } + + private void Update() + { + if (!isGameActive || isGameOver) return; + + gameTimer += Time.deltaTime; + float remainingTime = _settings.GameDuration - gameTimer; + float gameProgress = gameTimer / _settings.GameDuration; + + // Update timer + OnTimerUpdated?.Invoke(remainingTime); + + // Check game over + if (remainingTime <= 0f) + { + EndGame(); + return; + } + + // Update conveyor + Conveyor.Update(Time.deltaTime, gameProgress); + + // Try spawn item + var item = Conveyor.TrySpawnItem(Time.time, gameProgress); + if (item != null) + { + OnItemSpawned?.Invoke(item); + } + } + + public void StartGame() + { + isGameActive = true; + isGameOver = false; + gameTimer = 0f; + + // Reset score + Score.Reset(); + + OnGameStarted?.Invoke(); + + // Set input mode to game + if (InputManager.Instance != null) + { + InputManager.Instance.SetInputMode(InputMode.GameAndUI); + } + + Logging.Debug("[SortingGameManager] Game started!"); + } + + public void EndGame() + { + if (isGameOver) return; + + isGameOver = true; + isGameActive = false; + + // Calculate rewards + int boosterReward = Score.CalculateBoosterReward(); + + Logging.Debug($"[SortingGameManager] Game ended! Score: {Score.TotalScore}, Boosters: {boosterReward}"); + + // Grant boosters + if (CardSystemManager.Instance != null) + { + CardSystemManager.Instance.AddBoosterPack(boosterReward); + } + + OnGameEnded?.Invoke(); + + // Show results screen (handled by UI controller) + } + + /// + /// Called by SortableItem when placed in box. + /// + public void OnItemSorted(SortableItem item, SortingBox box, bool correct) + { + if (correct) + { + Score.RecordCorrectSort(); + Logging.Debug($"[SortingGameManager] Correct sort! {item.CardData?.Name ?? item.GarbageItem?.DisplayName}"); + } + else + { + Score.RecordIncorrectSort(); + Logging.Debug($"[SortingGameManager] Incorrect sort! {item.CardData?.Name ?? item.GarbageItem?.DisplayName}"); + } + + Conveyor.RemoveItem(item); + OnItemSortedEvent?.Invoke(item, box, correct); + + // Play animation then destroy + if (item.Context?.Animator != null) + { + item.Context.Animator.PopOut(0.4f, () => { + if (item != null) + Destroy(item.gameObject); + }); + } + else + { + Destroy(item.gameObject, 0.5f); + } + } + + /// + /// Called when item falls off belt. + /// + public void OnItemMissed(SortableItem item) + { + Score.RecordMissedItem(); + Conveyor.RemoveItem(item); + + Logging.Debug($"[SortingGameManager] Item missed! {item.CardData?.Name ?? item.GarbageItem?.DisplayName}"); + } + + private void OnScoreChanged(int newScore) + { + // UI will subscribe to this event + Logging.Debug($"[SortingGameManager] Score changed: {newScore}"); + } + + private void OnCorrectSort(int totalCorrect) + { + // Could play effects, update combo, etc. + } + + private void OnIncorrectSort(int totalIncorrect) + { + // Could play error effects + } + + // Public accessors for UI + public int CurrentScore => Score?.TotalScore ?? 0; + public int CorrectSorts => Score?.CorrectSorts ?? 0; + public int IncorrectSorts => Score?.IncorrectSorts ?? 0; + public int MissedItems => Score?.MissedItems ?? 0; + public float Accuracy => Score?.Accuracy ?? 0f; + public float RemainingTime => Mathf.Max(0f, _settings.GameDuration - gameTimer); + public bool IsGameActive => isGameActive && !isGameOver; + } +} + diff --git a/Assets/Scripts/Minigames/CardSorting/Core/SortingGameManager.cs.meta b/Assets/Scripts/Minigames/CardSorting/Core/SortingGameManager.cs.meta new file mode 100644 index 00000000..8f91f86d --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/Core/SortingGameManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 20acac8b97ca4d6397612679b3bbde50 +timeCreated: 1763470372 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting/Data.meta b/Assets/Scripts/Minigames/CardSorting/Data.meta new file mode 100644 index 00000000..54a6aece --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/Data.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a450e2687ce14a66b1495e1f2db7d403 +timeCreated: 1763461758 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting/Data/Enums.cs b/Assets/Scripts/Minigames/CardSorting/Data/Enums.cs new file mode 100644 index 00000000..35a9f244 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/Data/Enums.cs @@ -0,0 +1,14 @@ +namespace Minigames.CardSorting.Data +{ + /// + /// Types of sorting boxes in the minigame. + /// + public enum BoxType + { + Normal, // Copper-rimmed box for Normal rarity cards + Rare, // Silver-rimmed box for Rare rarity cards + Legend, // Gold-rimmed box for Legendary rarity cards + Trash // Trash can for garbage items + } +} + diff --git a/Assets/Scripts/Minigames/CardSorting/Data/Enums.cs.meta b/Assets/Scripts/Minigames/CardSorting/Data/Enums.cs.meta new file mode 100644 index 00000000..41a16e53 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/Data/Enums.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7e238b51f7164867b519bf139fe22c01 +timeCreated: 1763461758 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting/Data/GarbageItemDefinition.cs b/Assets/Scripts/Minigames/CardSorting/Data/GarbageItemDefinition.cs new file mode 100644 index 00000000..2faf3c2b --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/Data/GarbageItemDefinition.cs @@ -0,0 +1,38 @@ +using UnityEngine; + +namespace Minigames.CardSorting.Data +{ + /// + /// Definition for garbage items (banana peels, cans, receipts, etc.). + /// Cards use existing CardDefinition from CardSystemManager. + /// + [CreateAssetMenu(fileName = "GarbageItem", menuName = "Minigames/CardSorting/GarbageItem", order = 0)] + public class GarbageItemDefinition : ScriptableObject + { + [Tooltip("Unique identifier for this garbage item")] + [SerializeField] private string itemId; + + [Tooltip("Display name for debugging")] + [SerializeField] private string displayName; + + [Tooltip("Sprite to display for this garbage item")] + [SerializeField] private Sprite sprite; + + // Public accessors + public string ItemId => itemId; + public string DisplayName => displayName; + public Sprite Sprite => sprite; + +#if UNITY_EDITOR + private void OnValidate() + { + // Auto-generate itemId from asset name if empty + if (string.IsNullOrEmpty(itemId)) + { + itemId = name; + } + } +#endif + } +} + diff --git a/Assets/Scripts/Minigames/CardSorting/Data/GarbageItemDefinition.cs.meta b/Assets/Scripts/Minigames/CardSorting/Data/GarbageItemDefinition.cs.meta new file mode 100644 index 00000000..5896cd19 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/Data/GarbageItemDefinition.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2e69a2167710437798b1980126d5a4f6 +timeCreated: 1763461765 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting/StateMachine.meta b/Assets/Scripts/Minigames/CardSorting/StateMachine.meta new file mode 100644 index 00000000..86845772 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/StateMachine.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0197a7c7c3174a5fbf1ddd5b1445f24c +timeCreated: 1763461845 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting/StateMachine/SortingStateMachine.cs b/Assets/Scripts/Minigames/CardSorting/StateMachine/SortingStateMachine.cs new file mode 100644 index 00000000..98be0052 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/StateMachine/SortingStateMachine.cs @@ -0,0 +1,21 @@ +using Core.SaveLoad; + +namespace Minigames.CardSorting.StateMachine +{ + /// + /// State machine for sortable items that opts out of save system. + /// Sorting minigame is session-only and doesn't persist between loads. + /// Follows CardStateMachine pattern. + /// + public class SortingStateMachine : AppleMachine + { + /// + /// Opt out of save/load system - sortable items are transient minigame objects. + /// + public override bool ShouldParticipateInSave() + { + return false; + } + } +} + diff --git a/Assets/Scripts/Minigames/CardSorting/StateMachine/SortingStateMachine.cs.meta b/Assets/Scripts/Minigames/CardSorting/StateMachine/SortingStateMachine.cs.meta new file mode 100644 index 00000000..58e28f91 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/StateMachine/SortingStateMachine.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1b459f40574b45839aa32d5730627ca6 +timeCreated: 1763461845 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting/StateMachine/States.meta b/Assets/Scripts/Minigames/CardSorting/StateMachine/States.meta new file mode 100644 index 00000000..cfb0f4c8 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/StateMachine/States.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 24973c8bb25d493885224ac6f099492d +timeCreated: 1763469762 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting/StateMachine/States/BeingDraggedState.cs b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/BeingDraggedState.cs new file mode 100644 index 00000000..75a11290 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/BeingDraggedState.cs @@ -0,0 +1,51 @@ +using Core; +using Core.SaveLoad; +using Minigames.CardSorting.Core; +using UnityEngine; + +namespace Minigames.CardSorting.StateMachine.States +{ + /// + /// Item is being dragged by the player. + /// Provides visual feedback (scale up). + /// Transitions to SortedState when dropped in box, or back to OnConveyorState if dropped elsewhere. + /// + public class BeingDraggedState : AppleState + { + private SortableItemContext _context; + private Vector3 _originalScale; + + private void Awake() + { + _context = GetComponentInParent(); + } + + public override void OnEnterState() + { + if (_context == null) return; + + _context.IsOnConveyor = false; + + // Store original scale + if (_context.VisualTransform != null) + { + _originalScale = _context.VisualTransform.localScale; + + // Visual feedback: scale up 10% + _context.Animator?.AnimateScale(_originalScale * 1.1f, 0.2f); + } + + Logging.Debug("[BeingDraggedState] Item being dragged, scaled up for feedback"); + } + + private void OnDisable() + { + // Restore original scale + if (_context != null && _context.Animator != null) + { + _context.Animator.AnimateScale(_originalScale, 0.2f); + } + } + } +} + diff --git a/Assets/Scripts/Minigames/CardSorting/StateMachine/States/BeingDraggedState.cs.meta b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/BeingDraggedState.cs.meta new file mode 100644 index 00000000..08340806 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/BeingDraggedState.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 015c0740240748c8901c9304490cb80d +timeCreated: 1763469770 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting/StateMachine/States/OnConveyorState.cs b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/OnConveyorState.cs new file mode 100644 index 00000000..da42ed7f --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/OnConveyorState.cs @@ -0,0 +1,62 @@ +using Core; +using Core.SaveLoad; +using Minigames.CardSorting.Core; +using UnityEngine; + +namespace Minigames.CardSorting.StateMachine.States +{ + /// + /// Item is moving along the conveyor belt. + /// Transitions to BeingDraggedState when player drags the item. + /// + public class OnConveyorState : AppleState, ISortableItemDragHandler + { + private SortableItemContext _context; + private SortableItem _item; + + private void Awake() + { + _context = GetComponentInParent(); + _item = GetComponentInParent(); + } + + public override void OnEnterState() + { + if (_context == null) return; + + _context.IsOnConveyor = true; + + Logging.Debug($"[OnConveyorState] Item entered conveyor state"); + } + + private void OnDisable() + { + if (_context == null) return; + + _context.IsOnConveyor = false; + } + + private void Update() + { + if (_context == null || !_context.IsOnConveyor) return; + + // Move item along conveyor (right direction) + Vector3 movement = Vector3.right * _context.ConveyorSpeed * Time.deltaTime; + _context.RootTransform.position += movement; + } + + /// + /// Handle drag start - transition to BeingDraggedState. + /// + public bool OnDragStarted(SortableItemContext context) + { + Logging.Debug("[OnConveyorState] Drag started, transitioning to BeingDraggedState"); + + // Transition to dragging state + _item?.ChangeState("BeingDraggedState"); + + return true; // We handled it + } + } +} + diff --git a/Assets/Scripts/Minigames/CardSorting/StateMachine/States/OnConveyorState.cs.meta b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/OnConveyorState.cs.meta new file mode 100644 index 00000000..2adba518 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/OnConveyorState.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 17d2ba6f5aec4b698247b082734cad8f +timeCreated: 1763469762 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedState.cs b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedState.cs new file mode 100644 index 00000000..c68ec309 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedState.cs @@ -0,0 +1,34 @@ +using Core; +using Core.SaveLoad; +using Minigames.CardSorting.Core; + +namespace Minigames.CardSorting.StateMachine.States +{ + /// + /// Item has been successfully sorted into a box. + /// Plays animation then marks for destruction. + /// Manager handles the actual PopOut animation and destruction. + /// + public class SortedState : AppleState + { + private SortableItemContext _context; + + private void Awake() + { + _context = GetComponentInParent(); + } + + public override void OnEnterState() + { + if (_context == null) return; + + _context.IsOnConveyor = false; + + Logging.Debug("[SortedState] Item sorted, ready for destruction animation"); + + // Manager will handle PopOut animation and destruction + // State just marks item as no longer on conveyor + } + } +} + diff --git a/Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedState.cs.meta b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedState.cs.meta new file mode 100644 index 00000000..8d2edcd9 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedState.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0717f922952c4f228930ef0a5f6617b0 +timeCreated: 1763469776 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting/UI.meta b/Assets/Scripts/Minigames/CardSorting/UI.meta new file mode 100644 index 00000000..5e555d04 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/UI.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2194dbe8c2c4479f89f7307ce56cac5d +timeCreated: 1763470403 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting/UI/SortingGameHUD.cs b/Assets/Scripts/Minigames/CardSorting/UI/SortingGameHUD.cs new file mode 100644 index 00000000..56bfbdd0 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/UI/SortingGameHUD.cs @@ -0,0 +1,116 @@ +using Core.Settings; +using Minigames.CardSorting.Core; +using TMPro; +using UnityEngine; + +namespace Minigames.CardSorting.UI +{ + /// + /// HUD display for card sorting minigame. + /// Shows timer and score during gameplay. + /// + public class SortingGameHUD : MonoBehaviour + { + [Header("UI Elements")] + [SerializeField] private TextMeshProUGUI timerText; + [SerializeField] private TextMeshProUGUI scoreText; + [SerializeField] private TextMeshProUGUI accuracyText; + + private SortingGameManager gameManager; + + private void Start() + { + gameManager = SortingGameManager.Instance; + + if (gameManager == null) + { + Debug.LogError("[SortingGameHUD] SortingGameManager not found!"); + return; + } + + // Subscribe to events + gameManager.OnTimerUpdated += UpdateTimer; + + if (gameManager != null) + { + var scoreController = typeof(SortingGameManager) + .GetProperty("Score", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance) + ?.GetValue(gameManager); + + if (scoreController != null) + { + var scoreChangedEvent = scoreController.GetType().GetEvent("OnScoreChanged"); + if (scoreChangedEvent != null) + { + scoreChangedEvent.AddEventHandler(scoreController, + new System.Action(UpdateScore)); + } + } + } + + // Initial display + UpdateScore(0); + UpdateTimer(120f); // Default timer display + } + + private void OnDestroy() + { + if (gameManager != null) + { + gameManager.OnTimerUpdated -= UpdateTimer; + } + } + + private void Update() + { + // Update accuracy every frame (could optimize to only update on score change) + if (gameManager != null && accuracyText != null) + { + float accuracy = gameManager.Accuracy; + accuracyText.text = $"Accuracy: {accuracy:P0}"; + } + } + + public void UpdateTimer(float remainingTime) + { + if (timerText == null) return; + + int minutes = Mathf.FloorToInt(remainingTime / 60f); + int seconds = Mathf.FloorToInt(remainingTime % 60f); + + timerText.text = $"{minutes:00}:{seconds:00}"; + + // Change color if time running out + if (remainingTime <= 10f) + { + timerText.color = Color.red; + } + else if (remainingTime <= 30f) + { + timerText.color = Color.yellow; + } + else + { + timerText.color = Color.white; + } + } + + public void UpdateScore(int newScore) + { + if (scoreText == null) return; + + scoreText.text = $"Score: {newScore}"; + + // Color based on positive/negative + if (newScore >= 0) + { + scoreText.color = Color.white; + } + else + { + scoreText.color = new Color(1f, 0.5f, 0.5f); // Light red + } + } + } +} + diff --git a/Assets/Scripts/Minigames/CardSorting/UI/SortingGameHUD.cs.meta b/Assets/Scripts/Minigames/CardSorting/UI/SortingGameHUD.cs.meta new file mode 100644 index 00000000..dd8fb785 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/UI/SortingGameHUD.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: aa656e03d5384a9eae31fab73b6fe5e2 +timeCreated: 1763470403 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting/UI/SortingResultsScreen.cs b/Assets/Scripts/Minigames/CardSorting/UI/SortingResultsScreen.cs new file mode 100644 index 00000000..507ffebb --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/UI/SortingResultsScreen.cs @@ -0,0 +1,126 @@ +using Minigames.CardSorting.Core; +using TMPro; +using UnityEngine; +using UnityEngine.UI; + +namespace Minigames.CardSorting.UI +{ + /// + /// Results screen shown at end of card sorting minigame. + /// Displays final score, accuracy, and boosters earned. + /// + public class SortingResultsScreen : MonoBehaviour + { + [Header("UI Elements")] + [SerializeField] private TextMeshProUGUI finalScoreText; + [SerializeField] private TextMeshProUGUI correctSortsText; + [SerializeField] private TextMeshProUGUI incorrectSortsText; + [SerializeField] private TextMeshProUGUI missedItemsText; + [SerializeField] private TextMeshProUGUI accuracyText; + [SerializeField] private TextMeshProUGUI boostersEarnedText; + [SerializeField] private Button closeButton; + + [Header("Screen")] + [SerializeField] private CanvasGroup canvasGroup; + + private void Awake() + { + // Hide initially + if (canvasGroup != null) + { + canvasGroup.alpha = 0f; + canvasGroup.interactable = false; + canvasGroup.blocksRaycasts = false; + } + else + { + gameObject.SetActive(false); + } + + // Setup close button + if (closeButton != null) + { + closeButton.onClick.AddListener(OnCloseClicked); + } + } + + private void Start() + { + var gameManager = SortingGameManager.Instance; + + if (gameManager != null) + { + gameManager.OnGameEnded += ShowResults; + } + } + + private void OnDestroy() + { + var gameManager = SortingGameManager.Instance; + + if (gameManager != null) + { + gameManager.OnGameEnded -= ShowResults; + } + } + + private void ShowResults() + { + var gameManager = SortingGameManager.Instance; + + if (gameManager == null) return; + + // Populate data + if (finalScoreText != null) + finalScoreText.text = $"Final Score: {gameManager.CurrentScore}"; + + if (correctSortsText != null) + correctSortsText.text = $"Correct: {gameManager.CorrectSorts}"; + + if (incorrectSortsText != null) + incorrectSortsText.text = $"Incorrect: {gameManager.IncorrectSorts}"; + + if (missedItemsText != null) + missedItemsText.text = $"Missed: {gameManager.MissedItems}"; + + if (accuracyText != null) + accuracyText.text = $"Accuracy: {gameManager.Accuracy:P0}"; + + // Calculate boosters (already granted by manager) + int boosters = gameManager.CorrectSorts; // Simple 1:1 ratio + if (boostersEarnedText != null) + boostersEarnedText.text = $"Boosters Earned: {boosters}"; + + // Show screen + if (canvasGroup != null) + { + canvasGroup.alpha = 1f; + canvasGroup.interactable = true; + canvasGroup.blocksRaycasts = true; + } + else + { + gameObject.SetActive(true); + } + } + + private void OnCloseClicked() + { + // Hide screen + if (canvasGroup != null) + { + canvasGroup.alpha = 0f; + canvasGroup.interactable = false; + canvasGroup.blocksRaycasts = false; + } + else + { + gameObject.SetActive(false); + } + + // Could also trigger scene transition, return to menu, etc. + Debug.Log("[SortingResultsScreen] Closed results screen"); + } + } +} + diff --git a/Assets/Scripts/Minigames/CardSorting/UI/SortingResultsScreen.cs.meta b/Assets/Scripts/Minigames/CardSorting/UI/SortingResultsScreen.cs.meta new file mode 100644 index 00000000..0b7a826a --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/UI/SortingResultsScreen.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 03823b5ad80b482086569050fbb8bb40 +timeCreated: 1763470418 \ No newline at end of file diff --git a/docs/card_sorting_minigame_plan.md b/docs/card_sorting_minigame_plan.md new file mode 100644 index 00000000..604e3882 --- /dev/null +++ b/docs/card_sorting_minigame_plan.md @@ -0,0 +1,1114 @@ +# Card Sorting Minigame - Implementation Plan + +**Game Type:** Quality Control Sorting Game +**Duration:** 2 minutes +**Objective:** Sort cards and garbage into correct boxes before timer expires +**Rewards:** Booster packs based on performance + +--- + +## Game Design Summary + +### Narrative +Mr. Cement needs help sorting cards from the printing machine. Some cards are defective, and good cards must be sorted by rarity (Normal/Rare/Legend). Defective items go to trash. + +### Gameplay +- **Conveyor Belt**: Items spawn and move right at increasing speed +- **Player Action**: Drag items to correct sorting boxes +- **Difficulty Curve**: Spawn rate and belt speed increase over time +- **Scoring**: Points for correct sorts, penalties for mistakes/misses +- **Game Over**: Timer expires, machine explodes, rewards granted + +### Item Types +1. **Normal Cards** → Copper-rimmed box +2. **Rare Cards** → Silver-rimmed box +3. **Legendary Cards** → Gold-rimmed box +4. **Defective Items** → Trash can (includes: deformed borders, embarrassing images, garbage like banana peels/cans/receipts) + +--- + +## Technical Architecture + +### Code Reuse Strategy + +**From Card System:** +- ✅ `CardDisplay` (nested prefab) - Renders cards with rarity colors, borders, frames +- ✅ `CardAnimator` (component) - All animations (PopIn, PopOut, Scale, Shake, Bounce) +- ✅ `DraggableObject` (base class) - Drag/drop logic, slot detection, pointer events +- ✅ `CardData` (struct) - Visual rendering format for cards + +**From Drag System:** +- ✅ `DraggableSlot` (base class) - Drop target validation + +**New for Minigame:** +- 🆕 `SortingStateMachine` - Opts out of save system (5 lines, copy CardStateMachine pattern) +- 🆕 `SortableItem` - Drag orchestration (inherits DraggableObject) +- 🆕 `SortableItemContext` - Shared state for minigame items +- 🆕 3 States - OnConveyor, BeingDragged, Sorted +- 🆕 `GarbageVisual` - Simple sprite renderer for non-card items (~20 lines) +- 🆕 Data layer - GarbageItemDefinition, SortingGameConfig, Enums (BoxType only) +- 🆕 Controllers - ConveyorBeltController, SortingScoreController +- 🆕 `SortingGameManager` - Main game loop +- 🆕 `SortingBox` - Drop targets with validation + +### Prefab Architecture + +#### Two Prefab Types + +**SortableCardPrefab** (for actual cards): +``` +Root +├── SortableItem.cs +├── SortableItemContext.cs +├── SortingStateMachine +│ ├── OnConveyorState +│ ├── BeingDraggedState +│ └── SortedState +└── Visual (GameObject) ← CardAnimator targets this + └── CardDisplay (NESTED PREFAB) ← Drag from Prefabs/ +``` + +**SortableGarbagePrefab** (for trash items): +``` +Root +├── SortableItem.cs (SAME script) +├── SortableItemContext.cs (SAME script) +├── SortingStateMachine (SAME states) +└── Visual (GameObject) ← CardAnimator targets this + └── GarbageVisual.cs + Image component +``` + +**Key Points:** +- Both prefabs share ALL logic scripts +- Visual differences isolated to "Visual" child GameObject +- CardAnimator animates "Visual" GameObject (works for both) +- SortableItemContext detects which visual component is assigned (cardDisplay vs garbageVisual) + +--- + +## Data Layer + +### Enums + +**BoxType:** +- `Normal` - Copper-rimmed box (Normal rarity cards) +- `Rare` - Silver-rimmed box (Rare rarity cards) +- `Legend` - Gold-rimmed box (Legendary rarity cards) +- `Trash` - Garbage items + +### GarbageItemDefinition (ScriptableObject) + +**Purpose:** Define garbage items only (banana peels, cans, receipts, etc.) + +```csharp +[CreateAssetMenu("Minigames/CardSorting/GarbageItem")] +class GarbageItemDefinition : ScriptableObject +{ + string itemId; + string displayName; + Sprite sprite; +} +``` + +**Cards use existing CardDefinition from CardSystemManager!** +- No need to duplicate card data +- CardSystemManager already has all cards organized by zone/rarity +- Just query CardSystemManager for random card from collection + +### CardSortingSettings (BaseSettings) + +**Follows existing settings architecture pattern (see DivingMinigameSettings)** +- Inherits from `BaseSettings` +- Implements `ICardSortingSettings` interface +- Accessed via `GameManager.GetSettingsObject()` +- Registered in SettingsEditorWindow with "Card Sorting" tab +- Contains all game configuration (timing, speed, weights, scoring, rewards) + +### CardSortingSettings (BaseSettings + Interface) + +**Follows DivingMinigameSettings pattern:** +- Inherits from `BaseSettings` +- Implements `ICardSortingSettings` interface +- Registered in SettingsEditorWindow with own tab +- Accessed via `GameManager.GetSettingsObject()` + +```csharp +[CreateAssetMenu(fileName = "CardSortingSettings", menuName = "AppleHills/Settings/CardSorting", order = 4)] +class CardSortingSettings : BaseSettings, ICardSortingSettings +{ + [Header("Timing")] + [Tooltip("Total game duration in seconds")] + [SerializeField] private float gameDuration = 120f; + + [Tooltip("Initial time between item spawns (seconds)")] + [SerializeField] private float initialSpawnInterval = 2f; + + [Tooltip("Minimum time between item spawns as difficulty increases (seconds)")] + [SerializeField] private float minimumSpawnInterval = 0.5f; + + [Header("Conveyor Speed")] + [Tooltip("Initial belt movement speed")] + [SerializeField] private float initialBeltSpeed = 1f; + + [Tooltip("Maximum belt movement speed")] + [SerializeField] private float maxBeltSpeed = 3f; + + [Tooltip("Curve for difficulty progression (X=time%, Y=speed multiplier)")] + [SerializeField] private AnimationCurve speedCurve; + + [Header("Item Pools")] + [Tooltip("Garbage items that can spawn (banana peels, cans, receipts, etc.)")] + [SerializeField] private GarbageItemDefinition[] garbageItems; + + [Header("Spawn Weights")] + [Tooltip("Weight for spawning normal rarity cards")] + [Range(0, 100)] [SerializeField] private float normalCardWeight = 40f; + + [Tooltip("Weight for spawning rare rarity cards")] + [Range(0, 100)] [SerializeField] private float rareCardWeight = 30f; + + [Tooltip("Weight for spawning legendary rarity cards")] + [Range(0, 100)] [SerializeField] private float legendCardWeight = 20f; + + [Tooltip("Weight for spawning garbage items")] + [Range(0, 100)] [SerializeField] private float garbageWeight = 10f; + + [Header("Scoring")] + [Tooltip("Points awarded for correct sort")] + [SerializeField] private int correctSortPoints = 10; + + [Tooltip("Points deducted for incorrect sort")] + [SerializeField] private int incorrectSortPenalty = -5; + + [Tooltip("Points deducted when item falls off belt")] + [SerializeField] private int missedItemPenalty = -3; + + [Header("Rewards")] + [Tooltip("Booster packs awarded per correct sort")] + [SerializeField] private int boosterPacksPerCorrectItem = 1; + + // Interface implementation + public float GameDuration => gameDuration; + public float InitialSpawnInterval => initialSpawnInterval; + public float MinimumSpawnInterval => minimumSpawnInterval; + public float InitialBeltSpeed => initialBeltSpeed; + public float MaxBeltSpeed => maxBeltSpeed; + public AnimationCurve SpeedCurve => speedCurve; + public GarbageItemDefinition[] GarbageItems => garbageItems; + public float NormalCardWeight => normalCardWeight; + public float RareCardWeight => rareCardWeight; + public float LegendCardWeight => legendCardWeight; + public float GarbageWeight => garbageWeight; + public int CorrectSortPoints => correctSortPoints; + public int IncorrectSortPenalty => incorrectSortPenalty; + public int MissedItemPenalty => missedItemPenalty; + public int BoosterPacksPerCorrectItem => boosterPacksPerCorrectItem; + + public override void OnValidate() + { + base.OnValidate(); + + gameDuration = Mathf.Max(1f, gameDuration); + initialSpawnInterval = Mathf.Max(0.1f, initialSpawnInterval); + minimumSpawnInterval = Mathf.Max(0.1f, minimumSpawnInterval); + initialBeltSpeed = Mathf.Max(0.1f, initialBeltSpeed); + maxBeltSpeed = Mathf.Max(initialBeltSpeed, maxBeltSpeed); + correctSortPoints = Mathf.Max(0, correctSortPoints); + boosterPacksPerCorrectItem = Mathf.Max(0, boosterPacksPerCorrectItem); + } +} + +// Interface +interface ICardSortingSettings +{ + float GameDuration { get; } + float InitialSpawnInterval { get; } + float MinimumSpawnInterval { get; } + float InitialBeltSpeed { get; } + float MaxBeltSpeed { get; } + AnimationCurve SpeedCurve { get; } + GarbageItemDefinition[] GarbageItems { get; } + float NormalCardWeight { get; } + float RareCardWeight { get; } + float LegendCardWeight { get; } + float GarbageWeight { get; } + int CorrectSortPoints { get; } + int IncorrectSortPenalty { get; } + int MissedItemPenalty { get; } + int BoosterPacksPerCorrectItem { get; } +} +``` + +--- + +## Core Components + +### SortableItem (MonoBehaviour) + +**Responsibilities:** +- Inherits from `DraggableObject` +- Orchestrates drag/drop behavior +- Routes events to state machine +- Handles drop validation +- Tracks whether this is a card or garbage item + +**Key Methods:** +```csharp +void SetupAsCard(CardData cardData) // Setup with card from CardSystemManager +void SetupAsGarbage(GarbageItemDefinition) // Setup with garbage item +void OnFellOffBelt() // Called when reaches end of conveyor +protected override void OnDragStartedHook() // Check state handler +protected override void OnDragEndedHook() // Validate drop, notify manager +``` + +**Properties:** +```csharp +bool IsGarbage { get; } // True if garbage, false if card +CardData CardData { get; } // Null if garbage +GarbageItemDefinition GarbageItem { get; } // Null if card +BoxType CorrectBox { get; } // Calculated from rarity or garbage flag +``` + +**Integration Points:** +- Queries state for `ISortableItemDragHandler` +- Validates drop on `SortingBox` +- Notifies `SortingGameManager` on sort/miss + +### SortableItemContext (MonoBehaviour) + +**Responsibilities:** +- Shared state container for states +- Routes data to appropriate visual component (card vs garbage) +- Provides component references + +**Key Properties:** +```csharp +CardDisplay cardDisplay; // Assigned for cards +GarbageVisual garbageVisual; // Assigned for garbage +CardAnimator animator; // Always assigned +Transform visualTransform; // "Visual" GameObject +bool IsOnConveyor; +float ConveyorSpeed; +``` + +**Setup Logic:** +```csharp +void SetupAsCard(CardData cardData) +{ + // CardDisplay handles EVERYTHING + cardDisplay?.UpdateDisplay(cardData); +} + +void SetupAsGarbage(Sprite sprite) +{ + // Simple sprite assignment + garbageVisual?.UpdateDisplay(sprite); +} +``` + +**That's it! No conversion, no mapping, no adapters.** + +### GarbageVisual (MonoBehaviour) + +**Responsibilities:** +- Simple sprite display for non-card items +- Minimal component (~20 lines) + +**Implementation:** +```csharp +class GarbageVisual : MonoBehaviour +{ + [SerializeField] private Image spriteRenderer; + + public void UpdateDisplay(Sprite sprite) + { + if (spriteRenderer != null) + spriteRenderer.sprite = sprite; + } +} +``` + +### SortingBox (MonoBehaviour) + +**Responsibilities:** +- Drop target for sortable items +- Validates correct placement +- Visual feedback (optional) + +**Key Methods:** +```csharp +bool ValidateItem(SortableItem item) +{ + // Trash box accepts garbage + if (boxType == BoxType.Trash) + return item.IsGarbage; + + // Other boxes reject garbage, check card rarity + if (item.IsGarbage) return false; + + return item.CardData.Rarity switch { + CardRarity.Normal => boxType == BoxType.Normal, + CardRarity.Rare => boxType == BoxType.Rare, + CardRarity.Legendary => boxType == BoxType.Legend, + _ => false + }; +} + +override bool CanAccept(DraggableObject draggable) +{ + return draggable is SortableItem; +} +``` + +--- + +## State Machine + +### SortingStateMachine (Opts Out of Save System) + +```csharp +class SortingStateMachine : AppleMachine +{ + public override bool ShouldParticipateInSave() => false; +} +``` + +### Three States + +#### 1. OnConveyorState + +**Purpose:** Item moves along belt + +**Behavior:** +```csharp +void Update() +{ + Vector3 movement = Vector3.right * context.ConveyorSpeed * Time.deltaTime; + context.visualTransform.position += movement; +} + +bool OnDragStarted(SortableItemContext context) +{ + item.ChangeState("BeingDraggedState"); + return true; // Handled +} +``` + +**Entry:** Item spawned on belt +**Exit:** Player drags item OR item falls off end + +#### 2. BeingDraggedState + +**Purpose:** Player is dragging item + +**Behavior:** +```csharp +void OnEnterState() +{ + context.IsOnConveyor = false; + context.Animator.AnimateScale(Vector3.one * 1.1f, 0.2f); // Visual feedback +} + +void OnExitState() +{ + context.Animator.AnimateScale(Vector3.one, 0.2f); // Restore +} +``` + +**Entry:** Drag started from OnConveyorState +**Exit:** Drop on box (→ SortedState) OR drop elsewhere (→ OnConveyorState) + +#### 3. SortedState + +**Purpose:** Item placed in box, ready for destruction + +**Behavior:** +```csharp +void OnEnterState() +{ + context.IsOnConveyor = false; + // Animation handled by manager +} +``` + +**Entry:** Successfully dropped on box +**Exit:** Destroyed after animation + +--- + +## Controllers (Non-Component) + +### ConveyorBeltController + +**Responsibilities:** +- Spawn items at intervals +- Track active items +- Update belt speed +- Detect items falling off end + +**Constructor:** +```csharp +ConveyorBeltController( + Transform spawnPoint, + Transform endPoint, + GameObject cardPrefab, + GameObject garbagePrefab, + ICardSortingSettings settings // Uses settings interface +) +``` + +**Key Methods:** +```csharp +void Update(float deltaTime, float gameProgress) +{ + UpdateBeltSpeed(gameProgress); // Adjust speed via config curve + UpdateItemPositions(deltaTime); // Movement handled by states + CheckItemsOffBelt(); // Detect falls, notify manager +} + +SortableItem TrySpawnItem(float currentTime) +{ + if (currentTime < nextSpawnTime) return null; + + // Weighted random: card or garbage? + float totalWeight = config.normalCardWeight + config.rareCardWeight + + config.legendCardWeight + config.garbageWeight; + float roll = Random.Range(0f, totalWeight); + + SortableItem item; + + if (roll < config.garbageWeight) + { + // Spawn garbage + GarbageItemDefinition garbage = SelectRandomGarbage(); + GameObject obj = Instantiate(garbagePrefab, spawnPoint.position, Quaternion.identity); + item = obj.GetComponent(); + item.SetupAsGarbage(garbage); + } + else + { + // Spawn card - determine rarity, get random card from CardSystemManager + CardRarity rarity = DetermineRarity(roll); + CardData cardData = CardSystemManager.Instance.GetRandomCardOfRarity(rarity); + + GameObject obj = Instantiate(cardPrefab, spawnPoint.position, Quaternion.identity); + item = obj.GetComponent(); + item.SetupAsCard(cardData); + } + + activeItems.Add(item); + ScheduleNextSpawn(gameProgress); + return item; +} + +CardRarity DetermineRarity(float roll) +{ + // Adjust roll to be relative to card weights only + float adjusted = roll - config.garbageWeight; + + if (adjusted < config.normalCardWeight) return CardRarity.Normal; + if (adjusted < config.normalCardWeight + config.rareCardWeight) return CardRarity.Rare; + return CardRarity.Legendary; +} + +GarbageItemDefinition SelectRandomGarbage() +{ + return config.garbageItems[Random.Range(0, config.garbageItems.Length)]; +} + +void RemoveItem(SortableItem item) // Manual removal +``` + +**Properties:** +```csharp +float CurrentSpeed { get; } +int ActiveItemCount { get; } +``` + +### SortingScoreController + +**Responsibilities:** +- Track correct/incorrect/missed counts +- Calculate total score +- Calculate accuracy +- Calculate booster rewards + +**Constructor:** +```csharp +SortingScoreController(ICardSortingSettings settings) +``` + +**Properties:** +```csharp +int TotalScore { get; } +int CorrectSorts { get; } +int IncorrectSorts { get; } +int MissedItems { get; } +float Accuracy { get; } // correctSorts / totalAttempts +``` + +**Events:** +```csharp +event Action OnScoreChanged; +event Action OnCorrectSort; +event Action OnIncorrectSort; +``` + +--- + +## Main Manager + +### SortingGameManager (ManagedBehaviour) + +**Responsibilities:** +- Game loop orchestration +- Timer management +- Controller lifecycle +- Event coordination +- Integration with CardSystemManager + +**Singleton:** +```csharp +static SortingGameManager Instance { get; } +``` + +**Settings Access:** +```csharp +private ICardSortingSettings _settings; + +internal override void OnManagedAwake() +{ + _instance = this; + _settings = GameManager.GetSettingsObject(); +} +``` + +**Lazy-Init Controllers:** +```csharp +private ConveyorBeltController _conveyorController; +private ConveyorBeltController Conveyor => _conveyorController ??= new ConveyorBeltController( + conveyorSpawnPoint, + conveyorEndPoint, + cardPrefab, + garbagePrefab, + _settings +); + +private SortingScoreController _scoreController; +private SortingScoreController Score => _scoreController ??= new SortingScoreController(_settings); +``` + +**Game Loop:** +```csharp +void Update() +{ + if (!isGameActive || isGameOver) return; + + gameTimer += Time.deltaTime; + float remainingTime = config.gameDuration - gameTimer; + float gameProgress = gameTimer / config.gameDuration; + + OnTimerUpdated?.Invoke(remainingTime); + + if (remainingTime <= 0f) { EndGame(); return; } + + Conveyor.Update(Time.deltaTime, gameProgress); + + var item = Conveyor.TrySpawnItem(gameTimer); + if (item != null) OnItemSpawned?.Invoke(item); +} +``` + +**Public API (Called by SortableItem):** +```csharp +void OnItemSorted(SortableItem item, SortingBox box, bool correct) +{ + if (correct) Score.RecordCorrectSort(); + else Score.RecordIncorrectSort(); + + Conveyor.RemoveItem(item); + OnItemSortedEvent?.Invoke(item, box, correct); + + // Play animation then destroy + item.Context.Animator.PopOut(0.4f, () => Destroy(item.gameObject)); +} + +void OnItemMissed(SortableItem item) +{ + Score.RecordMissedItem(); + Conveyor.RemoveItem(item); +} +``` + +**End Game:** +```csharp +void EndGame() +{ + isGameOver = true; + int boosters = Score.CalculateBoosterReward(); + CardSystemManager.Instance.AddBoosterPack(boosters); + OnGameEnded?.Invoke(); +} +``` + +**Events:** +```csharp +event Action OnGameStarted; +event Action OnGameEnded; +event Action OnItemSpawned; +event Action OnItemSortedEvent; +event Action OnTimerUpdated; // Remaining time +``` + +--- + +## Animation Strategy + +### All Animations via CardAnimator + +**Target:** "Visual" GameObject (parent of CardDisplay/GarbageVisual) + +**Common Animations:** +```csharp +// Spawn on conveyor +context.Animator.PopIn(0.3f); + +// Pick up (BeingDraggedState enter) +context.Animator.AnimateScale(Vector3.one * 1.1f, 0.2f); +context.Animator.PlayBounce(0.1f); + +// Drop back to belt (BeingDraggedState exit) +context.Animator.AnimateScale(Vector3.one, 0.2f); + +// Successful sort (SortedState) +context.Animator.PopOut(0.4f, () => Destroy(gameObject)); + +// Failed sort feedback +context.Animator.PlayShake(0.3f); + +// Conveyor wobble (continuous in OnConveyorState) +context.Animator.PlayBounce(0.05f); + +// Hover over correct box +context.Animator.AnimateScale(Vector3.one * 1.1f, 0.15f); + +// Hover exit +context.Animator.AnimateScale(Vector3.one, 0.15f); +``` + +**Visual GameObject Setup:** +- CardAnimator component attached to "Visual" GameObject +- SortableItemContext.visualTransform references "Visual" +- SortableItemContext.animator references CardAnimator +- States call `context.Animator.MethodName()` + +--- + +## Implementation Phases + +### Phase 1: Data Foundation +**Goal:** Define all data structures and configurations + +**Tasks:** +1. Create `Data/Enums.cs` - BoxType only +2. Create `Data/GarbageItemDefinition.cs` - ScriptableObject for garbage items +3. Create `Core/Settings/ICardSortingSettings.cs` - Interface (follow IDivingMinigameSettings pattern) +4. Create `Core/Settings/CardSortingSettings.cs` - Settings class (follow DivingMinigameSettings pattern) +5. Register CardSortingSettings in SettingsEditorWindow: + - Add to tab names array: "Card Sorting" + - Add case to switch statement + - Add to CreateSettingsIfMissing calls +6. Create 3-5 GarbageItemDefinitions in editor (banana peel, can, receipt, etc.) +7. Create CardSortingSettings asset via menu (will auto-create on first editor window open) + +**Validation:** +- Can create GarbageItemDefinition assets +- CardSortingSettings appears in Settings Editor window +- Can modify settings values in editor +- Settings accessible via `GameManager.GetSettingsObject()` + +--- + +### Phase 2: Core Components +**Goal:** Build sortable item and visual system + +**Tasks:** +1. Create `Core/GarbageVisual.cs` - Simple sprite renderer +2. Create `Core/SortableItemContext.cs` - Shared state, visual routing +3. Create `StateMachine/SortingStateMachine.cs` - Save opt-out (copy CardStateMachine) +4. Create `Core/SortableItem.cs` - Drag orchestration +5. Create `Core/SortingBox.cs` - Drop target validation + +**Validation:** +- GarbageVisual displays sprite correctly +- SortableItemContext routes data to cardDisplay/garbageVisual +- SortingStateMachine doesn't register with SaveLoadManager +- SortableItem inherits DraggableObject correctly +- SortingBox validates card rarity or garbage flag correctly + +--- + +### Phase 3: State Machine +**Goal:** Implement 3 states for item behavior + +**Tasks:** +1. Create `StateMachine/States/OnConveyorState.cs` - Movement logic +2. Create `StateMachine/States/BeingDraggedState.cs` - Visual feedback +3. Create `StateMachine/States/SortedState.cs` - Destruction ready +4. Add `ISortableItemDragHandler` interface to OnConveyorState + +**Validation:** +- OnConveyorState moves item right at ConveyorSpeed +- Drag starts → transitions to BeingDraggedState +- BeingDraggedState scales up visuals +- Drop on box → transitions to SortedState +- States use OnDisable() for cleanup (not OnExitState - AppleState doesn't have it) + +--- + +### Phase 4: Prefab Creation +**Goal:** Build two prefab variants with shared logic + +**Tasks:** +1. Create `SortableCardPrefab`: + - Add SortableItem, SortableItemContext components + - Add CardAnimator component + - Create "Visual" child GameObject + - Nest CardDisplay prefab under "Visual" + - Add SortingStateMachine with 3 state children + - Wire all references +2. Create `SortableGarbagePrefab`: + - Duplicate SortableCardPrefab + - Remove CardDisplay nested prefab + - Add GarbageVisual component to "Visual" GameObject + - Add Image component to "Visual" + - Wire garbageVisual reference +3. Create 4 `SortingBox` prefabs (Normal/Rare/Legend/Trash) + +**Validation:** +- Both prefabs use SAME scripts +- CardAnimator targets "Visual" GameObject on both +- SortableCardPrefab has cardDisplay assigned, garbageVisual null +- SortableGarbagePrefab has garbageVisual assigned, cardDisplay null +- Dragging works on both prefabs +- Visual differences isolated to "Visual" child + +--- + +### Phase 5: Controllers ✅ COMPLETE +**Goal:** Implement non-component logic controllers + +**Tasks:** +1. ✅ Create `Controllers/ConveyorBeltController.cs`: + - Spawning with weighted random selection + - Speed curve evaluation + - Active item tracking + - Fall-off detection +2. ✅ Create `Controllers/SortingScoreController.cs`: + - Score tracking + - Accuracy calculation + - Booster reward calculation + - Event firing + +**Validation:** +- ✅ ConveyorBeltController spawns correct prefab (card vs garbage) +- ✅ Spawn rate increases over time (lerp based on game progress) +- ✅ Belt speed increases per config curve +- ✅ Items detected when falling off end (x position > endPoint.x) +- ✅ Score updates correctly on correct/incorrect/missed +- ✅ Accuracy percentage calculated correctly (correctSorts / totalAttempts) +- ✅ No compilation errors + +--- + +### Phase 6: Game Manager ✅ COMPLETE +**Goal:** Orchestrate game loop and integration + +**Tasks:** +1. ✅ Create `Core/SortingGameManager.cs`: + - Singleton setup + - Lazy-init controllers + - Game loop (Update) + - Timer management + - Event handling + - Integration with CardSystemManager +2. ✅ Add inspector references (spawnPoint, endPoint, prefabs, boxes, config) +3. ✅ Uncomment SortingGameManager references in SortableItem + +**Validation:** +- ✅ Timer counts down correctly +- ✅ Items spawn at increasing rate +- ✅ Belt speed increases +- ✅ OnItemSorted called when dropped on box +- ✅ OnItemMissed called when falls off belt +- ✅ Boosters granted at end via CardSystemManager +- ✅ Events fire correctly +- ✅ No compilation errors + +--- + +### Phase 7: Scene Setup +**Goal:** Build playable minigame scene + +**Tasks:** +1. Create new scene `CardSorting.unity` +2. Add conveyor belt visual (sprite/sprite renderer) +3. Position 4 SortingBox instances: + - Normal (bottom-left) + - Rare (bottom-center-left) + - Legend (bottom-center-right) + - Trash (bottom-right) +4. Add spawn point marker (empty GameObject at left edge) +5. Add end point marker (empty GameObject at right edge) +6. Add SortingGameManager to scene +7. Wire all references in inspector (spawn points, prefabs, boxes) + - Note: Settings accessed via GameManager, no inspector reference needed +8. Add Canvas with UI layout (timer, score - can be placeholder) + +**Validation:** +- Play scene, items spawn and move +- Drag item to box, validates correctly +- Correct sort → score increases +- Incorrect sort → penalty applied +- Items fall off end → miss penalty +- Timer expires → game ends, boosters granted +- Settings changes in editor reflect in game + +--- + +### Phase 8: UI (Minimal MVP) ✅ COMPLETE +**Goal:** Display essential game info + +**Tasks:** +1. ✅ Create `UI/SortingGameHUD.cs`: + - Timer display (TextMeshProUGUI) + - Score display (TextMeshProUGUI) + - Accuracy display (TextMeshProUGUI) + - Subscribe to SortingGameManager events +2. ✅ Create `UI/SortingResultsScreen.cs`: + - Final score + - Accuracy percentage + - Boosters earned + - Close button + +**Validation:** +- ✅ Timer updates every frame +- ✅ Score updates on events +- ✅ Accuracy displays correctly +- ✅ Results screen shows correct data +- ✅ Can close and return to game +- ✅ No compilation errors + +--- + +### Phase 9: Polish (Post-MVP) +**Optional enhancements after core functionality proven** + +**Tasks:** +1. Particle effects on correct sort +2. Sound effects (pickup, drop, correct, wrong) +3. Visual feedback when hovering over correct/wrong box +4. Combo system (consecutive correct sorts) +5. More defect types with visual indicators +6. Tutorial sequence with Mr. Cement dialogue +7. Background music +8. Conveyor belt animation (scrolling texture) + +--- + +## File Structure + +``` +Assets/Scripts/Minigames/CardSorting/ +├── Core/ +│ ├── SortingGameManager.cs +│ ├── SortableItem.cs +│ ├── SortableItemContext.cs +│ ├── GarbageVisual.cs +│ └── SortingBox.cs +├── StateMachine/ +│ ├── SortingStateMachine.cs +│ └── States/ +│ ├── OnConveyorState.cs +│ ├── BeingDraggedState.cs +│ └── SortedState.cs +├── Controllers/ +│ ├── ConveyorBeltController.cs +│ └── SortingScoreController.cs +├── Data/ +│ ├── Enums.cs +│ └── GarbageItemDefinition.cs +└── UI/ + ├── SortingGameHUD.cs + └── SortingResultsScreen.cs + +Assets/Scripts/Core/Settings/ +├── ICardSortingSettings.cs (interface) +└── CardSortingSettings.cs (BaseSettings implementation) + +Assets/Editor/Settings/ +└── SettingsEditorWindow.cs (add CardSortingSettings tab) +``` + +--- + +## Integration Points + +### GameManager (Settings) +```csharp +// Access settings (available after GameManager initialization) +ICardSortingSettings settings = GameManager.GetSettingsObject(); +``` + +### CardSystemManager +```csharp +// Get random card by rarity +CardData cardData = CardSystemManager.Instance.GetRandomCardOfRarity(CardRarity.Rare); + +// Grant boosters at game end +CardSystemManager.Instance.AddBoosterPack(boosterCount); +``` + +### InputManager +```csharp +// Set input mode on game start +InputManager.Instance.SetInputMode(InputMode.GameAndUI); +``` + +### UIPageController (Optional) +```csharp +// Show results screen +UIPageController.Instance.PushPage(sortingResultsScreen); +``` + +### SettingsEditorWindow +```csharp +// Add CardSortingSettings tab (Phase 1) +// Follows pattern of DivingMinigameSettings registration +``` + +--- + +## Key Design Decisions + +### 1. Two Prefabs, Shared Logic +- Cards and garbage use SAME scripts (SortableItem, SortableItemContext, states) +- Visual differences isolated to "Visual" child GameObject +- CardAnimator animates "Visual" on both prefabs +- No code duplication + +### 2. Cards Use Existing CardDefinitions +- **No data duplication!** Cards spawn from CardSystemManager's existing CardDefinition collection +- CardDisplay receives CardData directly, handles all rendering +- Garbage items have simple GarbageItemDefinition (id, name, sprite) +- Zero conversion/mapping layer needed + +### 3. Settings Architecture Pattern +- **Follows DivingMinigameSettings pattern exactly** +- CardSortingSettings inherits BaseSettings, implements ICardSortingSettings +- Registered in SettingsEditorWindow with own tab +- Accessed via `GameManager.GetSettingsObject()` +- Designer-friendly: all configuration in Unity editor +- No ScriptableObject references in scene (accessed globally via GameManager) + +### 4. Visual GameObject Strategy +- "Visual" GameObject is parent of CardDisplay/GarbageVisual +- CardAnimator targets "Visual" +- Animations work identically for both item types +- Clean separation of logic (root) vs presentation (visual child) + +### 5. State Machine Simplicity +- Only 3 states vs 10 in card system +- Linear flow: OnConveyor → BeingDragged → Sorted +- No complex branching or edge cases +- Opts out of save system (runtime-only) + +### 6. Non-Component Controllers +- ConveyorBeltController, SortingScoreController are plain C# classes +- Lazy-initialized in SortingGameManager +- No Unity lifecycle overhead +- Easy to test and maintain + +### 7. Event-Driven Architecture +- Controllers fire events, UI subscribes +- Decoupled components +- Easy to extend with new features + +--- + +## Testing Checklist + +### Core Functionality +- [ ] Items spawn on conveyor at correct rate +- [ ] Items move right at increasing speed +- [ ] Can drag items from conveyor +- [ ] Cards display with correct rarity colors/borders +- [ ] Garbage displays with sprite only +- [ ] Drop on correct box → score increases +- [ ] Drop on wrong box → penalty applied +- [ ] Item falls off belt → miss penalty +- [ ] Timer counts down correctly +- [ ] Game ends at 0:00 + +### Animations +- [ ] PopIn on spawn +- [ ] Scale up when dragged +- [ ] Scale down when released +- [ ] PopOut on successful sort +- [ ] Shake on failed sort +- [ ] Conveyor wobble (continuous) + +### Scoring +- [ ] Correct sort grants points +- [ ] Incorrect sort applies penalty +- [ ] Missed item applies penalty +- [ ] Accuracy calculated correctly +- [ ] Booster reward calculated correctly + +### Integration +- [ ] Boosters granted to CardSystemManager +- [ ] Input mode set correctly +- [ ] No save system participation + +### Edge Cases +- [ ] Drag item off screen → returns to belt or destroys +- [ ] Multiple items on belt simultaneously +- [ ] Rapid dragging doesn't break spawning +- [ ] Game end mid-drag handles gracefully +- [ ] Empty item pools handled gracefully + +--- + +## Code Metrics Estimate + +**Total New Code:** ~800 lines +- SortingGameManager: ~150 lines +- ConveyorBeltController: ~160 lines (simpler spawning) +- SortingScoreController: ~80 lines +- SortableItem + SortableItemContext: ~120 lines (no conversion logic) +- 3 States: ~120 lines +- Data types: ~40 lines (Enums, GarbageItemDefinition only) +- Settings: ~100 lines (ICardSortingSettings interface + CardSortingSettings class) +- SettingsEditorWindow changes: ~10 lines (registration) +- GarbageVisual: ~20 lines +- SortingBox: ~40 lines +- UI scripts: ~70 lines + +**Reused Code:** ~2000+ lines +- CardDisplay (complete visual system) +- CardAnimator (all animations) +- DraggableObject (drag/drop framework) +- AppleMachine (state machine base) +- **CardData (used directly, no conversion!)** +- **CardDefinition (from CardSystemManager!)** +- **Settings architecture (BaseSettings, GameManager integration)** + +**Code Duplication:** 0 lines +**Data Duplication:** 0 (cards reuse existing definitions!) + +--- + +**Last Updated:** November 18, 2025 +**Status:** Planning Phase +**Next Step:** Phase 1 - Data Foundation + -- 2.49.1 From 247f7b73af92408a5b7b0020338f4a6e6ad385f4 Mon Sep 17 00:00:00 2001 From: Michal Pikulski Date: Wed, 19 Nov 2025 14:54:33 +0100 Subject: [PATCH 2/2] Working minigame? --- .../AssetGroups/BlokkemonCards.asset | 12 - .../AssetGroups/Default Local Group.asset | 5 + Assets/Data/CardQualityControl.meta | 8 + .../ExampleGarbageItem.asset | 17 + .../ExampleGarbageItem.asset.meta | 8 + .../Settings/SceneOrientationConfig.asset | 2 + Assets/External/Placeholders/battlefield6.png | Bin 0 -> 225602 bytes .../Placeholders/battlefield6.png.meta | 195 ++ .../Prefabs/Minigames/CardQualityControl.meta | 8 + .../CardQualityControl/SortableCard.prefab | 662 +++++ .../SortableCard.prefab.meta | 7 + .../CardQualityControl/SortableGarbage.prefab | 602 +++++ .../SortableGarbage.prefab.meta | 7 + .../CardQualityControl/SortingBox.prefab | 265 ++ .../CardQualityControl/SortingBox.prefab.meta | 7 + .../SortingBox_Legend.prefab | 75 + .../SortingBox_Legend.prefab.meta | 7 + .../SortingBox_Normal.prefab | 59 + .../SortingBox_Normal.prefab.meta | 7 + .../CardQualityControl/SortingBox_Rare.prefab | 75 + .../SortingBox_Rare.prefab.meta | 7 + .../SortingBox_Trash.prefab | 87 + .../SortingBox_Trash.prefab.meta | 7 + .../Minigames/CardQualityControl/UI.meta | 8 + .../CardQualityControl/UI/MinigameHUD.prefab | 527 ++++ .../UI/MinigameHUD.prefab.meta | 7 + .../UI/ResultsScreen.prefab | 2370 +++++++++++++++++ .../UI/ResultsScreen.prefab.meta | 7 + .../UI/CardsSystem/Cards/NewCard.prefab | 6 +- .../Fonts/Æblerup Font/AppleHills01 SDF.asset | 814 +++++- Assets/Resources/PerformanceTestRunInfo.json | 1 + .../PerformanceTestRunInfo.json.meta | 7 + .../Resources/PerformanceTestRunSettings.json | 1 + .../PerformanceTestRunSettings.json.meta | 7 + .../Scenes/MiniGames/CardQualityControl.unity | 1878 ++++++++++++- .../CardSystem/Data/CardSystemManager.cs | 19 + .../CardSystem/StateMachine/CardAnimator.cs | 50 + Assets/Scripts/Core/GameManager.cs | 11 + .../Core/Settings/CardSortingSettings.cs | 15 +- .../Core/Settings/ICardSortingSettings.cs | 3 +- .../Controllers/ConveyorBeltController.cs | 198 +- .../CardSorting/Core/SortableItem.cs | 85 +- .../CardSorting/Core/SortableItemContext.cs | 44 +- .../Minigames/CardSorting/Core/SortingBox.cs | 1 - .../CardSorting/Core/SortingGameManager.cs | 176 +- .../StateMachine/States/BeingDraggedState.cs | 16 +- .../States/DroppedOnFloorState.cs | 86 + .../States/DroppedOnFloorState.cs.meta | 3 + .../States/FellOffConveyorState.cs | 88 + .../States/FellOffConveyorState.cs.meta | 3 + .../States/SortedCorrectlyState.cs | 73 + .../States/SortedCorrectlyState.cs.meta | 3 + .../States/SortedIncorrectlyState.cs | 109 + .../States/SortedIncorrectlyState.cs.meta | 3 + .../StateMachine/States/SortedState.cs | 34 - .../StateMachine/States/SortedState.cs.meta | 3 - .../UI/DragAndDrop/Core/DraggableObject.cs | 5 +- .../UI/DragAndDrop/Core/DraggableSlot.cs | 6 + Assets/Scripts/UI/PlayerHudManager.cs | 25 +- Assets/Settings/CardSortingSettings.asset | 52 + .../Settings/CardSortingSettings.asset.meta | 8 + ...niversalRenderPipelineGlobalSettings.asset | 14 +- docs/card_sorting_minigame_plan.md | 1114 -------- 63 files changed, 8546 insertions(+), 1463 deletions(-) create mode 100644 Assets/Data/CardQualityControl.meta create mode 100644 Assets/Data/CardQualityControl/ExampleGarbageItem.asset create mode 100644 Assets/Data/CardQualityControl/ExampleGarbageItem.asset.meta create mode 100644 Assets/External/Placeholders/battlefield6.png create mode 100644 Assets/External/Placeholders/battlefield6.png.meta create mode 100644 Assets/Prefabs/Minigames/CardQualityControl.meta create mode 100644 Assets/Prefabs/Minigames/CardQualityControl/SortableCard.prefab create mode 100644 Assets/Prefabs/Minigames/CardQualityControl/SortableCard.prefab.meta create mode 100644 Assets/Prefabs/Minigames/CardQualityControl/SortableGarbage.prefab create mode 100644 Assets/Prefabs/Minigames/CardQualityControl/SortableGarbage.prefab.meta create mode 100644 Assets/Prefabs/Minigames/CardQualityControl/SortingBox.prefab create mode 100644 Assets/Prefabs/Minigames/CardQualityControl/SortingBox.prefab.meta create mode 100644 Assets/Prefabs/Minigames/CardQualityControl/SortingBox_Legend.prefab create mode 100644 Assets/Prefabs/Minigames/CardQualityControl/SortingBox_Legend.prefab.meta create mode 100644 Assets/Prefabs/Minigames/CardQualityControl/SortingBox_Normal.prefab create mode 100644 Assets/Prefabs/Minigames/CardQualityControl/SortingBox_Normal.prefab.meta create mode 100644 Assets/Prefabs/Minigames/CardQualityControl/SortingBox_Rare.prefab create mode 100644 Assets/Prefabs/Minigames/CardQualityControl/SortingBox_Rare.prefab.meta create mode 100644 Assets/Prefabs/Minigames/CardQualityControl/SortingBox_Trash.prefab create mode 100644 Assets/Prefabs/Minigames/CardQualityControl/SortingBox_Trash.prefab.meta create mode 100644 Assets/Prefabs/Minigames/CardQualityControl/UI.meta create mode 100644 Assets/Prefabs/Minigames/CardQualityControl/UI/MinigameHUD.prefab create mode 100644 Assets/Prefabs/Minigames/CardQualityControl/UI/MinigameHUD.prefab.meta create mode 100644 Assets/Prefabs/Minigames/CardQualityControl/UI/ResultsScreen.prefab create mode 100644 Assets/Prefabs/Minigames/CardQualityControl/UI/ResultsScreen.prefab.meta create mode 100644 Assets/Resources/PerformanceTestRunInfo.json create mode 100644 Assets/Resources/PerformanceTestRunInfo.json.meta create mode 100644 Assets/Resources/PerformanceTestRunSettings.json create mode 100644 Assets/Resources/PerformanceTestRunSettings.json.meta create mode 100644 Assets/Scripts/Minigames/CardSorting/StateMachine/States/DroppedOnFloorState.cs create mode 100644 Assets/Scripts/Minigames/CardSorting/StateMachine/States/DroppedOnFloorState.cs.meta create mode 100644 Assets/Scripts/Minigames/CardSorting/StateMachine/States/FellOffConveyorState.cs create mode 100644 Assets/Scripts/Minigames/CardSorting/StateMachine/States/FellOffConveyorState.cs.meta create mode 100644 Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedCorrectlyState.cs create mode 100644 Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedCorrectlyState.cs.meta create mode 100644 Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedIncorrectlyState.cs create mode 100644 Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedIncorrectlyState.cs.meta delete mode 100644 Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedState.cs delete mode 100644 Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedState.cs.meta create mode 100644 Assets/Settings/CardSortingSettings.asset create mode 100644 Assets/Settings/CardSortingSettings.asset.meta delete mode 100644 docs/card_sorting_minigame_plan.md diff --git a/Assets/AddressableAssetsData/AssetGroups/BlokkemonCards.asset b/Assets/AddressableAssetsData/AssetGroups/BlokkemonCards.asset index 27cbdbc8..69bb9a0d 100644 --- a/Assets/AddressableAssetsData/AssetGroups/BlokkemonCards.asset +++ b/Assets/AddressableAssetsData/AssetGroups/BlokkemonCards.asset @@ -63,18 +63,6 @@ MonoBehaviour: m_SerializedLabels: - BlokkemonCard FlaggedDuringContentUpdateRestriction: 0 - - m_GUID: 4f4ec75013bc276429c2f4fa52d165e0 - m_Address: Assets/Data/Cards/Card_New Card.asset - m_ReadOnly: 0 - m_SerializedLabels: - - BlokkemonCard - FlaggedDuringContentUpdateRestriction: 0 - - m_GUID: 53996921ed2094948aa317efe4ca6630 - m_Address: Assets/Data/Cards/Card_New Card.asset - m_ReadOnly: 0 - m_SerializedLabels: - - BlokkemonCard - FlaggedDuringContentUpdateRestriction: 0 - m_GUID: 73d54071304571647b3238a799d9781f m_Address: Assets/Data/Cards/Card_New Card.asset m_ReadOnly: 0 diff --git a/Assets/AddressableAssetsData/AssetGroups/Default Local Group.asset b/Assets/AddressableAssetsData/AssetGroups/Default Local Group.asset index 34a52fdb..573affe6 100644 --- a/Assets/AddressableAssetsData/AssetGroups/Default Local Group.asset +++ b/Assets/AddressableAssetsData/AssetGroups/Default Local Group.asset @@ -20,6 +20,11 @@ MonoBehaviour: m_ReadOnly: 0 m_SerializedLabels: [] FlaggedDuringContentUpdateRestriction: 0 + - m_GUID: 9d4a355954ae0a544a9c2a8281bc4bee + m_Address: Settings/CardSortingSettings + m_ReadOnly: 0 + m_SerializedLabels: [] + FlaggedDuringContentUpdateRestriction: 0 - m_GUID: d28c589c05c122f449a8b34e696cda53 m_Address: Puzzles/Quarry m_ReadOnly: 0 diff --git a/Assets/Data/CardQualityControl.meta b/Assets/Data/CardQualityControl.meta new file mode 100644 index 00000000..9a83b0f7 --- /dev/null +++ b/Assets/Data/CardQualityControl.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8e78bf67b6dbe484a9550a8689254162 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/CardQualityControl/ExampleGarbageItem.asset b/Assets/Data/CardQualityControl/ExampleGarbageItem.asset new file mode 100644 index 00000000..c54928e2 --- /dev/null +++ b/Assets/Data/CardQualityControl/ExampleGarbageItem.asset @@ -0,0 +1,17 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2e69a2167710437798b1980126d5a4f6, type: 3} + m_Name: ExampleGarbageItem + m_EditorClassIdentifier: AppleHillsScripts::Minigames.CardSorting.Data.GarbageItemDefinition + itemId: ExampleGarbageItem + displayName: Battlefield 6 + sprite: {fileID: 3452939858483483321, guid: 07aae524a464bd44fbb2abd932615899, type: 3} diff --git a/Assets/Data/CardQualityControl/ExampleGarbageItem.asset.meta b/Assets/Data/CardQualityControl/ExampleGarbageItem.asset.meta new file mode 100644 index 00000000..4e1185cd --- /dev/null +++ b/Assets/Data/CardQualityControl/ExampleGarbageItem.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b9c54fbced64684419e983429fd27b34 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/Settings/SceneOrientationConfig.asset b/Assets/Data/Settings/SceneOrientationConfig.asset index 301f84fc..09568497 100644 --- a/Assets/Data/Settings/SceneOrientationConfig.asset +++ b/Assets/Data/Settings/SceneOrientationConfig.asset @@ -19,3 +19,5 @@ MonoBehaviour: requiredOrientation: 1 - sceneName: DivingForPictures requiredOrientation: 0 + - sceneName: CardQualityControl + requiredOrientation: 1 diff --git a/Assets/External/Placeholders/battlefield6.png b/Assets/External/Placeholders/battlefield6.png new file mode 100644 index 0000000000000000000000000000000000000000..349a13625a0e92d0383e2674b5a3b3e0fa4be185 GIT binary patch literal 225602 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 z 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 y5%j6=uR==aM(`DMz3pkA(IB0000 + /// Gets a random card definition of the specified rarity. + /// Used by minigames to spawn cards without affecting player's collection. + /// + public CardDefinition GetRandomCardDefinitionByRarity(CardRarity targetRarity) + { + // Filter available cards by rarity + var matchingCards = availableCards.Where(c => c.Rarity == targetRarity).ToList(); + + if (matchingCards.Count == 0) + { + Debug.LogWarning($"[CardSystemManager] No card definitions found for rarity {targetRarity}"); + return null; + } + + // Return random card from matching rarity + return matchingCards[UnityEngine.Random.Range(0, matchingCards.Count)]; + } + #endregion /// diff --git a/Assets/Scripts/CardSystem/StateMachine/CardAnimator.cs b/Assets/Scripts/CardSystem/StateMachine/CardAnimator.cs index c0743676..3b2cff63 100644 --- a/Assets/Scripts/CardSystem/StateMachine/CardAnimator.cs +++ b/Assets/Scripts/CardSystem/StateMachine/CardAnimator.cs @@ -401,6 +401,56 @@ namespace UI.CardSystem.StateMachine } #endregion + + #region Color/Tint Animations + + private TweenBase _activeBlinkTween; + private Color _originalColor; + + /// + /// Blink an image red repeatedly (for fell-off-conveyor state) + /// + public void BlinkRed(UnityEngine.UI.Image image, float blinkSpeed = 0.25f) + { + if (image == null) return; + + // Stop any existing blink + StopBlinking(); + + // Store original color + _originalColor = image.color; + + // Start blinking red loop + BlinkLoop(image, blinkSpeed); + } + + private void BlinkLoop(UnityEngine.UI.Image image, float blinkSpeed) + { + if (image == null) return; + + // Tween to red + _activeBlinkTween = Tween.Color(image, Color.red, blinkSpeed, 0f, Tween.EaseInOut, + completeCallback: () => + { + // Tween back to original + _activeBlinkTween = Tween.Color(image, _originalColor, blinkSpeed, 0f, Tween.EaseInOut, + completeCallback: () => BlinkLoop(image, blinkSpeed)); // Loop + }); + } + + /// + /// Stop blinking animation and restore original color + /// + public void StopBlinking() + { + if (_activeBlinkTween != null) + { + _activeBlinkTween.Stop(); + _activeBlinkTween = null; + } + } + + #endregion } } diff --git a/Assets/Scripts/Core/GameManager.cs b/Assets/Scripts/Core/GameManager.cs index 61bbe092..58eb3dbf 100644 --- a/Assets/Scripts/Core/GameManager.cs +++ b/Assets/Scripts/Core/GameManager.cs @@ -170,6 +170,7 @@ namespace Core var interactionSettings = SettingsProvider.Instance.LoadSettingsSynchronous(); var minigameSettings = SettingsProvider.Instance.LoadSettingsSynchronous(); var cardSystemSettings = SettingsProvider.Instance.LoadSettingsSynchronous(); + var sortingGameSettings = SettingsProvider.Instance.LoadSettingsSynchronous(); // Register settings with service locator if (playerSettings != null) @@ -211,6 +212,16 @@ namespace Core { Debug.LogError("Failed to load CardSystemSettings"); } + + if (sortingGameSettings != null) + { + ServiceLocator.Register(sortingGameSettings); + Logging.Debug("CardSortingSettings registered successfully"); + } + else + { + Debug.LogError("Failed to load CardSystemSettings"); + } // Log success _settingsLoaded = playerSettings != null && interactionSettings != null && minigameSettings != null && cardSystemSettings != null; diff --git a/Assets/Scripts/Core/Settings/CardSortingSettings.cs b/Assets/Scripts/Core/Settings/CardSortingSettings.cs index 5ecc8a5e..6faf176b 100644 --- a/Assets/Scripts/Core/Settings/CardSortingSettings.cs +++ b/Assets/Scripts/Core/Settings/CardSortingSettings.cs @@ -15,11 +15,8 @@ namespace Core.Settings [Tooltip("Total game duration in seconds")] [SerializeField] private float gameDuration = 120f; - [Tooltip("Initial time between item spawns (seconds)")] - [SerializeField] private float initialSpawnInterval = 2f; - - [Tooltip("Minimum time between item spawns as difficulty increases (seconds)")] - [SerializeField] private float minimumSpawnInterval = 0.5f; + [Tooltip("Distance between item spawns (units)")] + [SerializeField] private float spawnDistance = 50f; [Header("Conveyor Speed")] [Tooltip("Initial belt movement speed")] @@ -64,8 +61,9 @@ namespace Core.Settings // Interface implementation public float GameDuration => gameDuration; - public float InitialSpawnInterval => initialSpawnInterval; - public float MinimumSpawnInterval => minimumSpawnInterval; + + public float SpawnDistance => spawnDistance; + public float InitialBeltSpeed => initialBeltSpeed; public float MaxBeltSpeed => maxBeltSpeed; public AnimationCurve SpeedCurve => speedCurve; @@ -84,9 +82,6 @@ namespace Core.Settings base.OnValidate(); gameDuration = Mathf.Max(1f, gameDuration); - initialSpawnInterval = Mathf.Max(0.1f, initialSpawnInterval); - minimumSpawnInterval = Mathf.Max(0.1f, minimumSpawnInterval); - minimumSpawnInterval = Mathf.Min(minimumSpawnInterval, initialSpawnInterval); initialBeltSpeed = Mathf.Max(0.1f, initialBeltSpeed); maxBeltSpeed = Mathf.Max(initialBeltSpeed, maxBeltSpeed); correctSortPoints = Mathf.Max(0, correctSortPoints); diff --git a/Assets/Scripts/Core/Settings/ICardSortingSettings.cs b/Assets/Scripts/Core/Settings/ICardSortingSettings.cs index 89ab9d05..6d5636f4 100644 --- a/Assets/Scripts/Core/Settings/ICardSortingSettings.cs +++ b/Assets/Scripts/Core/Settings/ICardSortingSettings.cs @@ -11,8 +11,7 @@ namespace Core.Settings { // Timing float GameDuration { get; } - float InitialSpawnInterval { get; } - float MinimumSpawnInterval { get; } + float SpawnDistance { get; } // Conveyor Speed float InitialBeltSpeed { get; } diff --git a/Assets/Scripts/Minigames/CardSorting/Controllers/ConveyorBeltController.cs b/Assets/Scripts/Minigames/CardSorting/Controllers/ConveyorBeltController.cs index 587a3f34..632e17f5 100644 --- a/Assets/Scripts/Minigames/CardSorting/Controllers/ConveyorBeltController.cs +++ b/Assets/Scripts/Minigames/CardSorting/Controllers/ConveyorBeltController.cs @@ -11,19 +11,29 @@ namespace Minigames.CardSorting.Controllers /// /// Non-MonoBehaviour controller for conveyor belt logic. /// Handles spawning, speed, item lifecycle. + /// Owns item tracking and emits events when items fall off or are sorted. /// Parallel to CornerCardManager in card system. /// public class ConveyorBeltController { private readonly Transform spawnPoint; - private readonly Transform endPoint; + private readonly Transform endPoint; // Visual end - scoring happens here + private readonly Transform despawnPoint; // Off-screen - destruction happens here private readonly GameObject cardPrefab; private readonly GameObject garbagePrefab; private readonly ICardSortingSettings settings; private List activeItems = new List(); + private HashSet missedItems = new HashSet(); // Items past visual end, moving to despawn private float currentSpeed; - private float nextSpawnTime; + private SortableItem lastSpawnedItem; // Track last spawned item for distance-based spawning + + // Events - conveyor owns item lifecycle + public event System.Action OnItemSpawned; // Fired when new item spawns + public event System.Action OnItemFellOffBelt; // Fired at visual end (endPoint) + public event System.Action OnItemDespawned; // Fired at despawn point (destruction) + public event System.Action OnItemSorted; // item, box, correct + public event System.Action OnItemDroppedOnFloor; // Fired when dropped outside any box public float CurrentSpeed => currentSpeed; public int ActiveItemCount => activeItems.Count; @@ -31,36 +41,59 @@ namespace Minigames.CardSorting.Controllers public ConveyorBeltController( Transform spawnPoint, Transform endPoint, + Transform despawnPoint, GameObject cardPrefab, GameObject garbagePrefab, ICardSortingSettings settings) { this.spawnPoint = spawnPoint; this.endPoint = endPoint; + this.despawnPoint = despawnPoint; this.cardPrefab = cardPrefab; this.garbagePrefab = garbagePrefab; this.settings = settings; this.currentSpeed = settings.InitialBeltSpeed; - this.nextSpawnTime = 0f; + this.lastSpawnedItem = null; // No items spawned yet } /// - /// Update belt speed and check for items falling off. + /// Update belt speed, check for items falling off, and handle distance-based spawning. /// public void Update(float deltaTime, float gameProgress) { UpdateBeltSpeed(gameProgress); CheckItemsOffBelt(); + CheckDistanceBasedSpawn(gameProgress); } /// - /// Try to spawn an item if enough time has passed. + /// Check if we should spawn a new item based on distance from last spawn. + /// Items spawn when last item has moved far enough from spawn point. /// - public SortableItem TrySpawnItem(float currentTime, float gameProgress) + private void CheckDistanceBasedSpawn(float gameProgress) { - if (currentTime < nextSpawnTime) return null; + // If no items spawned yet, spawn immediately + if (lastSpawnedItem == null) + { + SpawnNewItem(gameProgress); + return; + } + // Check if last spawned item is far enough from spawn point + float distanceFromSpawn = Mathf.Abs(lastSpawnedItem.transform.position.x - spawnPoint.position.x); + + if (distanceFromSpawn >= settings.SpawnDistance) // Using InitialSpawnInterval as distance threshold + { + SpawnNewItem(gameProgress); + } + } + + /// + /// Spawn a new item at the spawn point. + /// + private SortableItem SpawnNewItem(float gameProgress) + { // Weighted random: card or garbage? float totalWeight = settings.NormalCardWeight + settings.RareCardWeight + settings.LegendCardWeight + settings.GarbageWeight; @@ -93,20 +126,15 @@ namespace Minigames.CardSorting.Controllers item.Context.ConveyorSpeed = currentSpeed; activeItems.Add(item); - ScheduleNextSpawn(gameProgress); + lastSpawnedItem = item; // Track for distance-based spawning + + // Emit spawn event + OnItemSpawned?.Invoke(item); } return item; } - /// - /// Remove item from tracking (when sorted or missed). - /// - public void RemoveItem(SortableItem item) - { - activeItems.Remove(item); - } - private SortableItem SpawnGarbageItem() { if (settings.GarbageItems == null || settings.GarbageItems.Length == 0) @@ -123,6 +151,10 @@ namespace Minigames.CardSorting.Controllers if (item != null) { item.SetupAsGarbage(garbage); + + // Subscribe to item events + item.OnItemDroppedInBox += HandleItemDroppedInBox; + item.OnItemReturnedToConveyor += HandleItemReturnedToConveyor; } else { @@ -151,6 +183,10 @@ namespace Minigames.CardSorting.Controllers if (item != null) { item.SetupAsCard(cardData); + + // Subscribe to item events + item.OnItemDroppedInBox += HandleItemDroppedInBox; + item.OnItemReturnedToConveyor += HandleItemReturnedToConveyor; } else { @@ -164,31 +200,23 @@ namespace Minigames.CardSorting.Controllers /// /// Helper method to get a random card of a specific rarity. - /// Uses CardSystemManager's internal DrawRandomCards logic. + /// Gets a CardDefinition from CardSystemManager and converts to CardData. + /// Does NOT affect player's collection or open boosters. /// private CardData GetRandomCardDataByRarity(CardRarity targetRarity) { - // Use reflection or create cards manually - // For now, open a temporary booster and filter - // This is not ideal but works until we add a proper method to CardSystemManager + // Get random card definition from manager + var definition = CardSystemManager.Instance.GetRandomCardDefinitionByRarity(targetRarity); - // Better approach: Draw cards until we get one of the right rarity - // Simulate drawing process - int maxAttempts = 20; - for (int i = 0; i < maxAttempts; i++) + if (definition == null) { - var drawnCards = CardSystemManager.Instance.OpenBoosterPack(); - CardSystemManager.Instance.AddBoosterPack(); // Restore the booster we used - - var matchingCard = drawnCards.Find(c => c.Rarity == targetRarity); - if (matchingCard != null) - { - return matchingCard; - } + Debug.LogWarning($"[ConveyorBeltController] No card definition found for rarity {targetRarity}"); + return null; } - Debug.LogWarning($"[ConveyorBeltController] Failed to draw card of rarity {targetRarity} after {maxAttempts} attempts"); - return null; + // Create CardData from definition using constructor + // This properly links the definition and sets all properties + return new CardData(definition); } private void UpdateBeltSpeed(float gameProgress) @@ -201,7 +229,7 @@ namespace Minigames.CardSorting.Controllers speedMultiplier ); - // Update all active items + // Update all active items (including missed items moving to despawn) foreach (var item in activeItems) { if (item != null && item.Context.IsOnConveyor) @@ -213,6 +241,7 @@ namespace Minigames.CardSorting.Controllers private void CheckItemsOffBelt() { + // Check active items for reaching visual end point for (int i = activeItems.Count - 1; i >= 0; i--) { var item = activeItems[i]; @@ -222,25 +251,100 @@ namespace Minigames.CardSorting.Controllers continue; } - // Check if past end point - if (item.transform.position.x > endPoint.position.x) + // Check if past visual end point (not yet scored as missed) + if (item.transform.position.x > endPoint.position.x && !missedItems.Contains(item)) + { + // Mark as missed and emit event for scoring + missedItems.Add(item); + + // Transition item to FellOffConveyorState (will blink red) + item.ChangeState("FellOffConveyorState"); + + OnItemFellOffBelt?.Invoke(item); + + // Item continues moving, stays in activeItems until despawn + } + } + + // Check missed items for reaching despawn point + for (int i = activeItems.Count - 1; i >= 0; i--) + { + var item = activeItems[i]; + if (item == null) { - item.OnFellOffBelt(); activeItems.RemoveAt(i); + continue; + } + + // Check if past despawn point (time to destroy) + if (item.transform.position.x > despawnPoint.position.x && missedItems.Contains(item)) + { + // Remove from tracking + activeItems.RemoveAt(i); + missedItems.Remove(item); + + // Clear lastSpawnedItem reference if this was it + if (lastSpawnedItem == item) + { + lastSpawnedItem = null; + } + + // Emit despawn event for destruction + OnItemDespawned?.Invoke(item); } } } - private void ScheduleNextSpawn(float gameProgress) + + /// + /// Handle when an item is dropped in a box (correct or incorrect). + /// + private void HandleItemDroppedInBox(SortableItem item, SortingBox box, bool correct) { - // Calculate next spawn time based on difficulty progression - float interval = Mathf.Lerp( - settings.InitialSpawnInterval, - settings.MinimumSpawnInterval, - gameProgress - ); - - nextSpawnTime = Time.time + interval; + // Remove from tracking and unsubscribe + if (activeItems.Remove(item)) + { + // Also remove from missed items if it was there + missedItems.Remove(item); + + // Clear lastSpawnedItem reference if this was it + if (lastSpawnedItem == item) + { + lastSpawnedItem = null; + } + + item.OnItemDroppedInBox -= HandleItemDroppedInBox; + item.OnItemReturnedToConveyor -= HandleItemReturnedToConveyor; + + // Emit event for game manager to handle scoring, passing box and correctness + OnItemSorted?.Invoke(item, box, correct); + } + } + + /// + /// Handle when an item is returned to conveyor (dropped outside box). + /// Item transitions to DroppedOnFloorState and gets destroyed. + /// + private void HandleItemReturnedToConveyor(SortableItem item) + { + // Remove from tracking and unsubscribe (item will be destroyed) + if (activeItems.Remove(item)) + { + missedItems.Remove(item); + + if (lastSpawnedItem == item) + { + lastSpawnedItem = null; + } + + item.OnItemDroppedInBox -= HandleItemDroppedInBox; + item.OnItemReturnedToConveyor -= HandleItemReturnedToConveyor; + + // Emit event for scoring + OnItemDroppedOnFloor?.Invoke(item); + + Debug.Log($"[ConveyorBeltController] Item dropped on floor: {item.CardData?.Name ?? item.GarbageItem?.DisplayName}"); + } } private CardRarity DetermineRarity(float roll) diff --git a/Assets/Scripts/Minigames/CardSorting/Core/SortableItem.cs b/Assets/Scripts/Minigames/CardSorting/Core/SortableItem.cs index ddb1340e..53f4a77d 100644 --- a/Assets/Scripts/Minigames/CardSorting/Core/SortableItem.cs +++ b/Assets/Scripts/Minigames/CardSorting/Core/SortableItem.cs @@ -26,6 +26,10 @@ namespace Minigames.CardSorting.Core private CardData cardData; private GarbageItemDefinition garbageItem; + // Events - item emits notifications, conveyor subscribes + public event System.Action OnItemDroppedInBox; + public event System.Action OnItemReturnedToConveyor; + // Public accessors public SortableItemContext Context => context; public AppleMachine StateMachine => stateMachine; @@ -122,6 +126,17 @@ namespace Minigames.CardSorting.Core // Default behavior if state doesn't handle Logging.Debug($"[SortableItem] Drag started on {(isGarbage ? garbageItem.DisplayName : cardData.Name)}"); } + + // TODO: Fixed when base slot/draggable reworked + public override void OnDrag(UnityEngine.EventSystems.PointerEventData eventData) + { + base.OnDrag(eventData); + + if (!IsDragging) return; + + // Perform raycast to detect what's underneath the dragged card + DetectSlotUnderPointer(eventData); + } protected override void OnDragEndedHook() { @@ -132,17 +147,63 @@ namespace Minigames.CardSorting.Core { bool correctSort = box.ValidateItem(this); - // Notify game manager - SortingGameManager.Instance?.OnItemSorted(this, box, correctSort); + // Fire event IMMEDIATELY when card is released over bin + // This allows manager to update score/UI right away + OnItemDroppedInBox?.Invoke(this, box, correctSort); - // Transition to sorted state - ChangeState("SortedState"); + // Transition to appropriate state based on correctness + // State will handle fall-into-bin animation and destruction + if (correctSort) + { + ChangeState("SortedCorrectlyState"); + } + else + { + ChangeState("SortedIncorrectlyState"); + } } else { - // Dropped outside valid box - return to conveyor - Logging.Debug("[SortableItem] Dropped outside box, returning to conveyor"); - ChangeState("OnConveyorState"); + // Dropped outside valid box - transition to dropped on floor state + Logging.Debug("[SortableItem] Dropped outside box, transitioning to floor state"); + ChangeState("DroppedOnFloorState"); + } + } + + // TODO: Fixed when base slot/draggable reworked + /// + /// Detect which slot (if any) is under the pointer during drag. + /// Updates CurrentSlot for drop detection. + /// + private void DetectSlotUnderPointer(UnityEngine.EventSystems.PointerEventData eventData) + { + // Perform raycast at pointer position to find slots + var raycastResults = new System.Collections.Generic.List(); + UnityEngine.EventSystems.EventSystem.current.RaycastAll(eventData, raycastResults); + + SortingBox hoveredBox = null; + + // Find first SortingBox in raycast results + foreach (var result in raycastResults) + { + var box = result.gameObject.GetComponentInParent(); + if (box != null) + { + hoveredBox = box; + break; + } + } + + // Update current slot (used in OnDragEndedHook) + if (hoveredBox != null && hoveredBox != CurrentSlot) + { + _currentSlot = hoveredBox; + Logging.Debug($"[SortableItem] Now hovering over {hoveredBox.BoxType} box"); + } + else if (hoveredBox == null && CurrentSlot != null) + { + _currentSlot = null; + Logging.Debug("[SortableItem] No longer over any box"); } } @@ -156,16 +217,6 @@ namespace Minigames.CardSorting.Core stateMachine.ChangeState(stateName); } } - - /// - /// Called when item falls off conveyor belt. - /// - public void OnFellOffBelt() - { - // Notify game manager - SortingGameManager.Instance?.OnItemMissed(this); - Destroy(gameObject); - } } /// diff --git a/Assets/Scripts/Minigames/CardSorting/Core/SortableItemContext.cs b/Assets/Scripts/Minigames/CardSorting/Core/SortableItemContext.cs index 87d560d1..3fa460d6 100644 --- a/Assets/Scripts/Minigames/CardSorting/Core/SortableItemContext.cs +++ b/Assets/Scripts/Minigames/CardSorting/Core/SortableItemContext.cs @@ -35,6 +35,11 @@ namespace Minigames.CardSorting.Core public bool IsOnConveyor { get; set; } = true; public float ConveyorSpeed { get; set; } = 1f; + // Original transform data (captured on spawn for drag animations) + public Vector3 OriginalScale { get; private set; } + public Vector3 OriginalPosition { get; private set; } + public Quaternion OriginalRotation { get; private set; } + private void Awake() { // Auto-find components if not assigned @@ -47,9 +52,16 @@ namespace Minigames.CardSorting.Core } } - if (animator == null && visualTransform != null) + if (animator == null) { - animator = visualTransform.GetComponent(); + // CardAnimator should be on root GameObject (animates root transform with Canvas scale) + animator = GetComponent(); + + // Fallback: check Visual child (legacy setup) + if (animator == null && visualTransform != null) + { + animator = visualTransform.GetComponent(); + } } if (cardDisplay == null && visualTransform != null) @@ -70,6 +82,20 @@ namespace Minigames.CardSorting.Core /// public void SetupAsCard(CardData cardData) { + // Capture original root transform for drag animations + // This preserves the tiny world-space Canvas scale (e.g., 0.05) + var currentScale = transform.localScale; + if (currentScale.x < 0.01f && currentScale.y < 0.01f && currentScale.z < 0.01f) + { + OriginalScale = Vector3.one; // Fallback if scale is ~0 + } + else + { + OriginalScale = currentScale; + } + OriginalPosition = transform.localPosition; + OriginalRotation = transform.localRotation; + if (cardDisplay != null) { cardDisplay.SetupCard(cardData); @@ -85,6 +111,20 @@ namespace Minigames.CardSorting.Core /// public void SetupAsGarbage(Sprite sprite) { + // Capture original root transform for drag animations + // This preserves the tiny world-space Canvas scale (e.g., 0.05) + var currentScale = transform.localScale; + if (currentScale.x < 0.01f && currentScale.y < 0.01f && currentScale.z < 0.01f) + { + OriginalScale = Vector3.one; // Fallback if scale is ~0 + } + else + { + OriginalScale = currentScale; + } + OriginalPosition = transform.localPosition; + OriginalRotation = transform.localRotation; + if (garbageVisual != null) { garbageVisual.UpdateDisplay(sprite); diff --git a/Assets/Scripts/Minigames/CardSorting/Core/SortingBox.cs b/Assets/Scripts/Minigames/CardSorting/Core/SortingBox.cs index 2bd04fcd..42e825a8 100644 --- a/Assets/Scripts/Minigames/CardSorting/Core/SortingBox.cs +++ b/Assets/Scripts/Minigames/CardSorting/Core/SortingBox.cs @@ -12,7 +12,6 @@ namespace Minigames.CardSorting.Core { [Header("Box Configuration")] [SerializeField] private BoxType boxType; - [SerializeField] private Sprite boxSprite; public BoxType BoxType => boxType; diff --git a/Assets/Scripts/Minigames/CardSorting/Core/SortingGameManager.cs b/Assets/Scripts/Minigames/CardSorting/Core/SortingGameManager.cs index 3cfa8a07..3fb03567 100644 --- a/Assets/Scripts/Minigames/CardSorting/Core/SortingGameManager.cs +++ b/Assets/Scripts/Minigames/CardSorting/Core/SortingGameManager.cs @@ -6,6 +6,7 @@ using Data.CardSystem; using Input; using Minigames.CardSorting.Controllers; using Minigames.CardSorting.Core; +using Unity.Cinemachine; using UnityEngine; namespace Minigames.CardSorting.Core @@ -19,11 +20,15 @@ namespace Minigames.CardSorting.Core { [Header("Scene References")] [SerializeField] private Transform conveyorSpawnPoint; - [SerializeField] private Transform conveyorEndPoint; + [SerializeField] private Transform conveyorEndPoint; // Visual end - items scored as missed here + [SerializeField] private Transform conveyorDespawnPoint; // Off-screen - items destroyed here [SerializeField] private GameObject sortableCardPrefab; [SerializeField] private GameObject sortableGarbagePrefab; [SerializeField] private SortingBox[] sortingBoxes; + [Header("Effects")] + [SerializeField] private CinemachineImpulseSource impulseSource; // Screen shake on incorrect sort + // Settings private ICardSortingSettings _settings; @@ -32,6 +37,7 @@ namespace Minigames.CardSorting.Core private ConveyorBeltController Conveyor => _conveyorController ??= new ConveyorBeltController( conveyorSpawnPoint, conveyorEndPoint, + conveyorDespawnPoint, sortableCardPrefab, sortableGarbagePrefab, _settings @@ -56,6 +62,11 @@ namespace Minigames.CardSorting.Core public event Action OnItemSortedEvent; public event Action OnTimerUpdated; // Remaining time + // Global effect events + public event Action OnItemSortedCorrectly; + public event Action OnItemSortedIncorrectly; + public event Action OnItemFellOffBelt; + internal override void OnManagedAwake() { _instance = this; @@ -79,6 +90,13 @@ namespace Minigames.CardSorting.Core Score.OnCorrectSort += OnCorrectSort; Score.OnIncorrectSort += OnIncorrectSort; + // Subscribe to conveyor events + Conveyor.OnItemSpawned += OnConveyorItemSpawned; + Conveyor.OnItemFellOffBelt += OnConveyorItemFellOff; + Conveyor.OnItemDespawned += OnConveyorItemDespawned; + Conveyor.OnItemSorted += OnConveyorItemSorted; + Conveyor.OnItemDroppedOnFloor += OnConveyorItemDroppedOnFloor; + // Start game automatically or wait for trigger // For now, auto-start StartGame(); @@ -92,6 +110,15 @@ namespace Minigames.CardSorting.Core Score.OnCorrectSort -= OnCorrectSort; Score.OnIncorrectSort -= OnIncorrectSort; } + + if (_conveyorController != null) + { + Conveyor.OnItemSpawned -= OnConveyorItemSpawned; + Conveyor.OnItemFellOffBelt -= OnConveyorItemFellOff; + Conveyor.OnItemDespawned -= OnConveyorItemDespawned; + Conveyor.OnItemSorted -= OnConveyorItemSorted; + Conveyor.OnItemDroppedOnFloor -= OnConveyorItemDroppedOnFloor; + } } private void Update() @@ -112,15 +139,8 @@ namespace Minigames.CardSorting.Core return; } - // Update conveyor + // Update conveyor (handles spawning, movement, and despawning internally) Conveyor.Update(Time.deltaTime, gameProgress); - - // Try spawn item - var item = Conveyor.TrySpawnItem(Time.time, gameProgress); - if (item != null) - { - OnItemSpawned?.Invoke(item); - } } public void StartGame() @@ -167,47 +187,129 @@ namespace Minigames.CardSorting.Core } /// - /// Called by SortableItem when placed in box. + /// Called when conveyor spawns a new item. /// - public void OnItemSorted(SortableItem item, SortingBox box, bool correct) + private void OnConveyorItemSpawned(SortableItem item) + { + // Forward to public event for UI/other systems + OnItemSpawned?.Invoke(item); + + Logging.Debug($"[SortingGameManager] Item spawned: {item.CardData?.Name ?? item.GarbageItem?.DisplayName}"); + } + + /// + /// Called when item reaches visual end of belt (via conveyor event). + /// Item continues moving off-screen until despawn point. + /// Scoring rules: + /// - Trash fell off: Negative score (penalty) + /// - Card fell off: Neutral (no score change) + /// + private void OnConveyorItemFellOff(SortableItem item) + { + // Only penalize TRASH items that fall off + // Cards falling off are neutral (no score change) + if (item.IsGarbage) + { + Score.RecordMissedItem(); + Logging.Debug($"[SortingGameManager] Trash fell off belt! {item.GarbageItem?.DisplayName} - PENALTY"); + } + else + { + Logging.Debug($"[SortingGameManager] Card fell off belt: {item.CardData?.Name} - no penalty"); + } + + // Fire global fell off belt event for effects + OnItemFellOffBelt?.Invoke(item); + + // Visual feedback could go here (e.g., "MISS!" popup) + // Item will continue moving and be destroyed at despawn point + } + + /// + /// Called when item is dropped on floor (via conveyor event). + /// Scoring rules: + /// - Trash dropped on floor: Negative score (penalty) + /// - Card dropped on floor: Neutral (no score change) + /// + private void OnConveyorItemDroppedOnFloor(SortableItem item) + { + // Only penalize TRASH items dropped on floor + // Cards dropped on floor are neutral (no score change) + if (item.IsGarbage) + { + Score.RecordIncorrectSort(); + Logging.Debug($"[SortingGameManager] Trash dropped on floor! {item.GarbageItem?.DisplayName} - PENALTY"); + + // Trigger screen shake for trash dropped on floor + if (impulseSource != null) + { + impulseSource.GenerateImpulse(); + } + } + else + { + Logging.Debug($"[SortingGameManager] Card dropped on floor: {item.CardData?.Name} - no penalty"); + } + } + + /// + /// Called when item reaches despawn point (via conveyor event). + /// Actually destroys the item. + /// + private void OnConveyorItemDespawned(SortableItem item) + { + Logging.Debug($"[SortingGameManager] Item despawned: {item.CardData?.Name ?? item.GarbageItem?.DisplayName}"); + + // Destroy the item + if (item != null) + Destroy(item.gameObject); + } + + /// + /// Called when conveyor confirms item was sorted (via event). + /// Handles scoring only - the state (SortedCorrectlyState/SortedIncorrectlyState) handles animation and destruction. + /// Scoring rules: + /// - Correct sort: Positive score (cards or trash in correct box) + /// - Incorrect trash: Negative score (trash in wrong box) + /// - Incorrect card: Neutral (no score change) + /// + private void OnConveyorItemSorted(SortableItem item, SortingBox box, bool correct) { if (correct) { Score.RecordCorrectSort(); Logging.Debug($"[SortingGameManager] Correct sort! {item.CardData?.Name ?? item.GarbageItem?.DisplayName}"); + + // Fire global correct sort event for effects + OnItemSortedCorrectly?.Invoke(item); } else { - Score.RecordIncorrectSort(); - Logging.Debug($"[SortingGameManager] Incorrect sort! {item.CardData?.Name ?? item.GarbageItem?.DisplayName}"); + // Only penalize incorrect sorting for TRASH items + // Cards incorrectly sorted are neutral (no score change) + if (item.IsGarbage) + { + Score.RecordIncorrectSort(); + Logging.Debug($"[SortingGameManager] Incorrect trash sort! {item.GarbageItem?.DisplayName} - PENALTY"); + + // Fire global incorrect sort event for effects + OnItemSortedIncorrectly?.Invoke(item); + + // Trigger screen shake + if (impulseSource != null) + { + impulseSource.GenerateImpulse(); + } + } + else + { + Logging.Debug($"[SortingGameManager] Card sorted incorrectly: {item.CardData?.Name} - no penalty"); + } } - Conveyor.RemoveItem(item); OnItemSortedEvent?.Invoke(item, box, correct); - // Play animation then destroy - if (item.Context?.Animator != null) - { - item.Context.Animator.PopOut(0.4f, () => { - if (item != null) - Destroy(item.gameObject); - }); - } - else - { - Destroy(item.gameObject, 0.5f); - } - } - - /// - /// Called when item falls off belt. - /// - public void OnItemMissed(SortableItem item) - { - Score.RecordMissedItem(); - Conveyor.RemoveItem(item); - - Logging.Debug($"[SortingGameManager] Item missed! {item.CardData?.Name ?? item.GarbageItem?.DisplayName}"); + // State handles animation and destruction - we just update score/UI here } private void OnScoreChanged(int newScore) diff --git a/Assets/Scripts/Minigames/CardSorting/StateMachine/States/BeingDraggedState.cs b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/BeingDraggedState.cs index 75a11290..1827b1a5 100644 --- a/Assets/Scripts/Minigames/CardSorting/StateMachine/States/BeingDraggedState.cs +++ b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/BeingDraggedState.cs @@ -13,7 +13,6 @@ namespace Minigames.CardSorting.StateMachine.States public class BeingDraggedState : AppleState { private SortableItemContext _context; - private Vector3 _originalScale; private void Awake() { @@ -26,13 +25,12 @@ namespace Minigames.CardSorting.StateMachine.States _context.IsOnConveyor = false; - // Store original scale - if (_context.VisualTransform != null) + // Visual feedback: scale up root transform by 10% + // Use OriginalScale from context (captured at spawn, preserves world-space Canvas scale) + if (_context.RootTransform != null && _context.Animator != null) { - _originalScale = _context.VisualTransform.localScale; - - // Visual feedback: scale up 10% - _context.Animator?.AnimateScale(_originalScale * 1.1f, 0.2f); + Vector3 targetScale = _context.OriginalScale * 1.1f; + _context.Animator.AnimateScale(targetScale, 0.2f); } Logging.Debug("[BeingDraggedState] Item being dragged, scaled up for feedback"); @@ -40,10 +38,10 @@ namespace Minigames.CardSorting.StateMachine.States private void OnDisable() { - // Restore original scale + // Restore original root transform scale (e.g., 0.05 for world-space Canvas) if (_context != null && _context.Animator != null) { - _context.Animator.AnimateScale(_originalScale, 0.2f); + _context.Animator.AnimateScale(_context.OriginalScale, 0.2f); } } } diff --git a/Assets/Scripts/Minigames/CardSorting/StateMachine/States/DroppedOnFloorState.cs b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/DroppedOnFloorState.cs new file mode 100644 index 00000000..567aefb8 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/DroppedOnFloorState.cs @@ -0,0 +1,86 @@ +using Core; +using Core.SaveLoad; +using Minigames.CardSorting.Core; + +namespace Minigames.CardSorting.StateMachine.States +{ + /// + /// Item was dropped outside any bin (on the floor). + /// Plays "disappear" animation then destroys the item. + /// + public class DroppedOnFloorState : AppleState + { + private SortableItemContext _context; + private SortableItem _item; + + private void Awake() + { + _context = GetComponentInParent(); + _item = GetComponentInParent(); + } + + public override void OnEnterState() + { + if (_context == null) return; + + _context.IsOnConveyor = false; + + Logging.Debug("[DroppedOnFloorState] Item dropped on floor, blinking red then disappearing"); + + // Blink red briefly, then play disappear animation + StartBlinkThenDisappear(); + } + + private void StartBlinkThenDisappear() + { + if (_context.Animator == null || _item == null) return; + + // Get the image to blink + UnityEngine.UI.Image imageToBlink = null; + + if (_context.CardDisplay != null) + { + imageToBlink = _context.CardDisplay.GetComponent(); + } + else if (_context.GarbageVisual != null) + { + imageToBlink = _context.GarbageVisual.GetComponent(); + } + + if (imageToBlink != null) + { + // Blink red briefly (2-3 times), then stop and disappear + _context.Animator.BlinkRed(imageToBlink, 0.15f); // Fast blink + + // After brief delay, stop blinking and play disappear animation + _context.Animator.AnimateScale(_context.RootTransform.localScale, 0.5f, () => + { + _context.Animator.StopBlinking(); + PlayDisappearAnimation(); + }); + } + else + { + // No image found, just disappear directly + PlayDisappearAnimation(); + } + } + + private void PlayDisappearAnimation() + { + if (_context.Animator == null || _item == null) return; + + // Tween scale down to 0 (disappear) + // When complete, destroy the item + _context.Animator.PopOut(0.4f, () => + { + if (_item != null) + { + Logging.Debug("[DroppedOnFloorState] Animation complete, destroying item"); + Destroy(_item.gameObject); + } + }); + } + } +} + diff --git a/Assets/Scripts/Minigames/CardSorting/StateMachine/States/DroppedOnFloorState.cs.meta b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/DroppedOnFloorState.cs.meta new file mode 100644 index 00000000..18e12c23 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/DroppedOnFloorState.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b384e4988bf549f2b6e70d1ff0fa4bcd +timeCreated: 1763557103 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting/StateMachine/States/FellOffConveyorState.cs b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/FellOffConveyorState.cs new file mode 100644 index 00000000..b3d7a519 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/FellOffConveyorState.cs @@ -0,0 +1,88 @@ +using Core; +using Core.SaveLoad; +using Minigames.CardSorting.Core; +using UnityEngine; + +namespace Minigames.CardSorting.StateMachine.States +{ + /// + /// Item reached the visual end of conveyor without being sorted. + /// Becomes non-clickable and blinks red until despawn point. + /// + public class FellOffConveyorState : AppleState + { + private SortableItemContext _context; + private SortableItem _item; + + private void Awake() + { + _context = GetComponentInParent(); + _item = GetComponentInParent(); + } + + public override void OnEnterState() + { + if (_context == null) return; + + // Keep IsOnConveyor = true so item continues moving to despawn point + // Item is no longer sortable but must continue moving off-screen + _context.IsOnConveyor = true; + + Logging.Debug("[FellOffConveyorState] Item fell off conveyor, blinking red until despawn"); + + // Disable dragging - item can no longer be picked up + if (_item != null) + { + _item.SetDraggingEnabled(false); + } + + // Start blinking red animation + StartBlinkingRed(); + } + + private void Update() + { + if (_context == null || !_context.IsOnConveyor) return; + + // Continue moving item toward despawn point (same logic as OnConveyorState) + Vector3 movement = Vector3.right * _context.ConveyorSpeed * Time.deltaTime; + _context.RootTransform.position += movement; + } + + private void StartBlinkingRed() + { + if (_context.Animator == null) return; + + // Get the image to tint (CardDisplay or GarbageVisual) + UnityEngine.UI.Image imageToBlink = null; + + if (_context.CardDisplay != null) + { + imageToBlink = + _context.CardDisplay.GetComponent() + ?? _context.CardDisplay.GetComponentInChildren(); + } + else if (_context.GarbageVisual != null) + { + imageToBlink = + _context.GarbageVisual.GetComponent() + ?? _context.GarbageVisual.GetComponentInChildren(); + } + + if (imageToBlink != null) + { + _context.Animator.BlinkRed(imageToBlink); + } + } + + private void OnDisable() + { + // Stop blinking when state exits (item despawned) + if (_context?.Animator != null) + { + _context.Animator.StopBlinking(); + } + } + } +} + diff --git a/Assets/Scripts/Minigames/CardSorting/StateMachine/States/FellOffConveyorState.cs.meta b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/FellOffConveyorState.cs.meta new file mode 100644 index 00000000..6b9f2f47 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/FellOffConveyorState.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 619a38624dcf48b19913bd4e1ac28625 +timeCreated: 1763557115 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedCorrectlyState.cs b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedCorrectlyState.cs new file mode 100644 index 00000000..9b77fb1f --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedCorrectlyState.cs @@ -0,0 +1,73 @@ +using Core; +using Core.SaveLoad; +using Minigames.CardSorting.Core; + +namespace Minigames.CardSorting.StateMachine.States +{ + /// + /// Item has been correctly sorted into the right box. + /// Plays "fall into bin" animation then destroys the card. + /// + public class SortedCorrectlyState : AppleState + { + private SortableItemContext _context; + private SortableItem _item; + + private void Awake() + { + _context = GetComponentInParent(); + _item = GetComponentInParent(); + } + + public override void OnEnterState() + { + if (_context == null) return; + + _context.IsOnConveyor = false; + + Logging.Debug("[SortedCorrectlyState] Item correctly sorted, tweening to box then falling in"); + + // First tween to box center, then play fall animation + TweenToBoxThenFall(); + } + + private void TweenToBoxThenFall() + { + if (_context.Animator == null || _item == null) return; + + // Get the box position (if available from CurrentSlot) + var box = _item.CurrentSlot as SortingBox; + if (box != null) + { + // Tween position to box center + _context.Animator.AnimateLocalPosition(box.transform.position, 0.2f, () => + { + // After reaching box, play fall animation + PlayFallIntoBinAnimation(); + }); + } + else + { + // No box found, just play fall animation + PlayFallIntoBinAnimation(); + } + } + + private void PlayFallIntoBinAnimation() + { + if (_context.Animator == null || _item == null) return; + + // Tween scale down to 0 (looks like falling into bin) + // When complete, destroy the card + _context.Animator.PopOut(0.4f, () => + { + if (_item != null) + { + Logging.Debug("[SortedCorrectlyState] Animation complete, destroying item"); + Destroy(_item.gameObject); + } + }); + } + } +} + diff --git a/Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedCorrectlyState.cs.meta b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedCorrectlyState.cs.meta new file mode 100644 index 00000000..9a0763ea --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedCorrectlyState.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f3ed2e6fb0814273926c33a178bdf42b +timeCreated: 1763555977 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedIncorrectlyState.cs b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedIncorrectlyState.cs new file mode 100644 index 00000000..79ab65f1 --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedIncorrectlyState.cs @@ -0,0 +1,109 @@ +using Core; +using Core.SaveLoad; +using Minigames.CardSorting.Core; + +namespace Minigames.CardSorting.StateMachine.States +{ + /// + /// Item has been incorrectly sorted into the wrong box. + /// Plays "fall into bin" animation then destroys the card. + /// Same animation as correct sort, but different state for tracking/events. + /// + public class SortedIncorrectlyState : AppleState + { + private SortableItemContext _context; + private SortableItem _item; + + private void Awake() + { + _context = GetComponentInParent(); + _item = GetComponentInParent(); + } + + public override void OnEnterState() + { + if (_context == null) return; + + _context.IsOnConveyor = false; + + Logging.Debug("[SortedIncorrectlyState] Item incorrectly sorted, blinking red then tweening to box"); + + // Start blinking red briefly, then tween to box + StartBlinkThenTween(); + } + + private void StartBlinkThenTween() + { + if (_context.Animator == null || _item == null) return; + + // Get the image to blink + UnityEngine.UI.Image imageToBlink = null; + + if (_context.CardDisplay != null) + { + imageToBlink = _context.CardDisplay.GetComponent(); + } + else if (_context.GarbageVisual != null) + { + imageToBlink = _context.GarbageVisual.GetComponent(); + } + + if (imageToBlink != null) + { + // Blink red briefly (2-3 times), then stop and continue with tween + _context.Animator.BlinkRed(imageToBlink, 0.15f); // Fast blink + + // After brief delay, stop blinking and tween to box + _context.Animator.AnimateScale(_context.RootTransform.localScale, 0.5f, () => + { + _context.Animator.StopBlinking(); + TweenToBoxThenFall(); + }); + } + else + { + // No image found, just tween directly + TweenToBoxThenFall(); + } + } + + private void TweenToBoxThenFall() + { + if (_context.Animator == null || _item == null) return; + + // Get the box position (if available from CurrentSlot) + var box = _item.CurrentSlot as SortingBox; + if (box != null) + { + // Tween position to box center + _context.Animator.AnimateLocalPosition(box.transform.position, 0.2f, () => + { + // After reaching box, play fall animation + PlayFallIntoBinAnimation(); + }); + } + else + { + // No box found, just play fall animation + PlayFallIntoBinAnimation(); + } + } + + private void PlayFallIntoBinAnimation() + { + if (_context.Animator == null || _item == null) return; + + // Tween scale down to 0 (looks like falling into bin) + // When complete, destroy the card + _context.Animator.PopOut(0.4f, () => + { + if (_item != null) + { + Logging.Debug("[SortedIncorrectlyState] Animation complete, destroying item"); + Destroy(_item.gameObject); + } + }); + } + } +} + diff --git a/Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedIncorrectlyState.cs.meta b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedIncorrectlyState.cs.meta new file mode 100644 index 00000000..903dfbdc --- /dev/null +++ b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedIncorrectlyState.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: edef0fb846be4fd99d396ea27dca1e4f +timeCreated: 1763555989 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedState.cs b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedState.cs deleted file mode 100644 index c68ec309..00000000 --- a/Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedState.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Core; -using Core.SaveLoad; -using Minigames.CardSorting.Core; - -namespace Minigames.CardSorting.StateMachine.States -{ - /// - /// Item has been successfully sorted into a box. - /// Plays animation then marks for destruction. - /// Manager handles the actual PopOut animation and destruction. - /// - public class SortedState : AppleState - { - private SortableItemContext _context; - - private void Awake() - { - _context = GetComponentInParent(); - } - - public override void OnEnterState() - { - if (_context == null) return; - - _context.IsOnConveyor = false; - - Logging.Debug("[SortedState] Item sorted, ready for destruction animation"); - - // Manager will handle PopOut animation and destruction - // State just marks item as no longer on conveyor - } - } -} - diff --git a/Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedState.cs.meta b/Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedState.cs.meta deleted file mode 100644 index 8d2edcd9..00000000 --- a/Assets/Scripts/Minigames/CardSorting/StateMachine/States/SortedState.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 0717f922952c4f228930ef0a5f6617b0 -timeCreated: 1763469776 \ No newline at end of file diff --git a/Assets/Scripts/UI/DragAndDrop/Core/DraggableObject.cs b/Assets/Scripts/UI/DragAndDrop/Core/DraggableObject.cs index 57592e8b..a57d182b 100644 --- a/Assets/Scripts/UI/DragAndDrop/Core/DraggableObject.cs +++ b/Assets/Scripts/UI/DragAndDrop/Core/DraggableObject.cs @@ -130,8 +130,9 @@ namespace UI.DragAndDrop.Core SmoothMoveTowardPointer(); } - // Only clamp for non-overlay canvases (WorldSpace/ScreenSpaceCamera) - if (_canvas != null && _canvas.renderMode != RenderMode.ScreenSpaceOverlay) + // Only clamp when actively being dragged (prevent dragging off-screen) + // Don't clamp when just sitting idle - allow objects to move freely off-screen + if (_isDragging && _canvas != null && _canvas.renderMode != RenderMode.ScreenSpaceOverlay) { ClampToScreen(); } diff --git a/Assets/Scripts/UI/DragAndDrop/Core/DraggableSlot.cs b/Assets/Scripts/UI/DragAndDrop/Core/DraggableSlot.cs index a4b63bf3..f46118e1 100644 --- a/Assets/Scripts/UI/DragAndDrop/Core/DraggableSlot.cs +++ b/Assets/Scripts/UI/DragAndDrop/Core/DraggableSlot.cs @@ -45,6 +45,10 @@ namespace UI.DragAndDrop.Core public Vector3 WorldPosition => transform.position; public RectTransform RectTransform => transform as RectTransform; + // Support for both UI and world-space slots + public bool IsUISlot => transform is RectTransform; + public Vector3 SlotPosition => transform.position; // Works for both Transform types + private void Start() { if (hideImageOnPlay) @@ -78,6 +82,7 @@ namespace UI.DragAndDrop.Core switch (occupantSizeMode) { case OccupantSizeMode.MatchSlotSize: + // Only works for UI slots with RectTransform if (draggable.RectTransform != null && RectTransform != null) { Vector2 targetSize = RectTransform.sizeDelta; @@ -85,6 +90,7 @@ namespace UI.DragAndDrop.Core (val) => draggable.RectTransform.sizeDelta = val, scaleTransitionDuration, 0f, Tween.EaseOutBack); } + // World-space slots (no RectTransform) skip size matching break; case OccupantSizeMode.Scale: diff --git a/Assets/Scripts/UI/PlayerHudManager.cs b/Assets/Scripts/UI/PlayerHudManager.cs index b363d4a0..12e1a432 100644 --- a/Assets/Scripts/UI/PlayerHudManager.cs +++ b/Assets/Scripts/UI/PlayerHudManager.cs @@ -157,19 +157,24 @@ namespace UI } } + // Subscribe to scene load events to adjust HUD based on scene if (SceneManagerService.Instance != null) { SceneManagerService.Instance.SceneLoadCompleted += NewSceneLoaded; } - if (SceneManagerService.Instance.CurrentGameplayScene == "AppleHillsOverworld") - { - NewSceneLoaded("AppleHillsOverworld"); - } - if (SceneManagerService.Instance.CurrentGameplayScene == "StartingScene") - { - // TODO: Hide all UI until cinematics have played - NewSceneLoaded("AppleHillsOverworld"); - } + + // If in editor - initialize HUD based on current scene + #if UNITY_EDITOR + if (SceneManagerService.Instance.CurrentGameplayScene == "StartingScene") + { + // TODO: Hide all UI until cinematics have played + NewSceneLoaded("AppleHillsOverworld"); + } + else if (SceneManagerService.Instance.CurrentGameplayScene != null) + { + NewSceneLoaded(SceneManagerService.Instance.CurrentGameplayScene); + } + #endif } internal override void OnManagedDestroy() @@ -229,7 +234,7 @@ namespace UI case "Quarry": currentUIMode = UIMode.Puzzle; break; - case "DivingForPictures": + case "DivingForPictures" or "CardQualityControl": currentUIMode = UIMode.Minigame; break; } diff --git a/Assets/Settings/CardSortingSettings.asset b/Assets/Settings/CardSortingSettings.asset new file mode 100644 index 00000000..14f98302 --- /dev/null +++ b/Assets/Settings/CardSortingSettings.asset @@ -0,0 +1,52 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a0fd5f8ab5d74b12968501dd4e3cc416, type: 3} + m_Name: CardSortingSettings + m_EditorClassIdentifier: AppleHillsScripts::Core.Settings.CardSortingSettings + gameDuration: 120 + spawnDistance: 10 + initialBeltSpeed: 5 + maxBeltSpeed: 10 + speedCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + garbageItems: + - {fileID: 11400000, guid: b9c54fbced64684419e983429fd27b34, type: 2} + normalCardWeight: 40 + rareCardWeight: 30 + legendCardWeight: 20 + garbageWeight: 40 + correctSortPoints: 10 + incorrectSortPenalty: -5 + missedItemPenalty: -3 + boosterPacksPerCorrectItem: 1 diff --git a/Assets/Settings/CardSortingSettings.asset.meta b/Assets/Settings/CardSortingSettings.asset.meta new file mode 100644 index 00000000..14c22ad6 --- /dev/null +++ b/Assets/Settings/CardSortingSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9d4a355954ae0a544a9c2a8281bc4bee +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniversalRenderPipelineGlobalSettings.asset b/Assets/UniversalRenderPipelineGlobalSettings.asset index 0957631e..9497abb8 100644 --- a/Assets/UniversalRenderPipelineGlobalSettings.asset +++ b/Assets/UniversalRenderPipelineGlobalSettings.asset @@ -63,19 +63,7 @@ MonoBehaviour: - rid: 7785851992983994373 - rid: 1219994508087787520 m_RuntimeSettings: - m_List: - - rid: 7752762179098771456 - - rid: 7752762179098771457 - - rid: 7752762179098771459 - - rid: 7752762179098771461 - - rid: 7752762179098771462 - - rid: 7752762179098771464 - - rid: 7752762179098771466 - - rid: 7752762179098771468 - - rid: 7752762179098771472 - - rid: 7752762179098771476 - - rid: 7785851992983994372 - - rid: 7785851992983994373 + m_List: [] m_AssetVersion: 8 m_ObsoleteDefaultVolumeProfile: {fileID: 0} m_RenderingLayerNames: diff --git a/docs/card_sorting_minigame_plan.md b/docs/card_sorting_minigame_plan.md deleted file mode 100644 index 604e3882..00000000 --- a/docs/card_sorting_minigame_plan.md +++ /dev/null @@ -1,1114 +0,0 @@ -# Card Sorting Minigame - Implementation Plan - -**Game Type:** Quality Control Sorting Game -**Duration:** 2 minutes -**Objective:** Sort cards and garbage into correct boxes before timer expires -**Rewards:** Booster packs based on performance - ---- - -## Game Design Summary - -### Narrative -Mr. Cement needs help sorting cards from the printing machine. Some cards are defective, and good cards must be sorted by rarity (Normal/Rare/Legend). Defective items go to trash. - -### Gameplay -- **Conveyor Belt**: Items spawn and move right at increasing speed -- **Player Action**: Drag items to correct sorting boxes -- **Difficulty Curve**: Spawn rate and belt speed increase over time -- **Scoring**: Points for correct sorts, penalties for mistakes/misses -- **Game Over**: Timer expires, machine explodes, rewards granted - -### Item Types -1. **Normal Cards** → Copper-rimmed box -2. **Rare Cards** → Silver-rimmed box -3. **Legendary Cards** → Gold-rimmed box -4. **Defective Items** → Trash can (includes: deformed borders, embarrassing images, garbage like banana peels/cans/receipts) - ---- - -## Technical Architecture - -### Code Reuse Strategy - -**From Card System:** -- ✅ `CardDisplay` (nested prefab) - Renders cards with rarity colors, borders, frames -- ✅ `CardAnimator` (component) - All animations (PopIn, PopOut, Scale, Shake, Bounce) -- ✅ `DraggableObject` (base class) - Drag/drop logic, slot detection, pointer events -- ✅ `CardData` (struct) - Visual rendering format for cards - -**From Drag System:** -- ✅ `DraggableSlot` (base class) - Drop target validation - -**New for Minigame:** -- 🆕 `SortingStateMachine` - Opts out of save system (5 lines, copy CardStateMachine pattern) -- 🆕 `SortableItem` - Drag orchestration (inherits DraggableObject) -- 🆕 `SortableItemContext` - Shared state for minigame items -- 🆕 3 States - OnConveyor, BeingDragged, Sorted -- 🆕 `GarbageVisual` - Simple sprite renderer for non-card items (~20 lines) -- 🆕 Data layer - GarbageItemDefinition, SortingGameConfig, Enums (BoxType only) -- 🆕 Controllers - ConveyorBeltController, SortingScoreController -- 🆕 `SortingGameManager` - Main game loop -- 🆕 `SortingBox` - Drop targets with validation - -### Prefab Architecture - -#### Two Prefab Types - -**SortableCardPrefab** (for actual cards): -``` -Root -├── SortableItem.cs -├── SortableItemContext.cs -├── SortingStateMachine -│ ├── OnConveyorState -│ ├── BeingDraggedState -│ └── SortedState -└── Visual (GameObject) ← CardAnimator targets this - └── CardDisplay (NESTED PREFAB) ← Drag from Prefabs/ -``` - -**SortableGarbagePrefab** (for trash items): -``` -Root -├── SortableItem.cs (SAME script) -├── SortableItemContext.cs (SAME script) -├── SortingStateMachine (SAME states) -└── Visual (GameObject) ← CardAnimator targets this - └── GarbageVisual.cs + Image component -``` - -**Key Points:** -- Both prefabs share ALL logic scripts -- Visual differences isolated to "Visual" child GameObject -- CardAnimator animates "Visual" GameObject (works for both) -- SortableItemContext detects which visual component is assigned (cardDisplay vs garbageVisual) - ---- - -## Data Layer - -### Enums - -**BoxType:** -- `Normal` - Copper-rimmed box (Normal rarity cards) -- `Rare` - Silver-rimmed box (Rare rarity cards) -- `Legend` - Gold-rimmed box (Legendary rarity cards) -- `Trash` - Garbage items - -### GarbageItemDefinition (ScriptableObject) - -**Purpose:** Define garbage items only (banana peels, cans, receipts, etc.) - -```csharp -[CreateAssetMenu("Minigames/CardSorting/GarbageItem")] -class GarbageItemDefinition : ScriptableObject -{ - string itemId; - string displayName; - Sprite sprite; -} -``` - -**Cards use existing CardDefinition from CardSystemManager!** -- No need to duplicate card data -- CardSystemManager already has all cards organized by zone/rarity -- Just query CardSystemManager for random card from collection - -### CardSortingSettings (BaseSettings) - -**Follows existing settings architecture pattern (see DivingMinigameSettings)** -- Inherits from `BaseSettings` -- Implements `ICardSortingSettings` interface -- Accessed via `GameManager.GetSettingsObject()` -- Registered in SettingsEditorWindow with "Card Sorting" tab -- Contains all game configuration (timing, speed, weights, scoring, rewards) - -### CardSortingSettings (BaseSettings + Interface) - -**Follows DivingMinigameSettings pattern:** -- Inherits from `BaseSettings` -- Implements `ICardSortingSettings` interface -- Registered in SettingsEditorWindow with own tab -- Accessed via `GameManager.GetSettingsObject()` - -```csharp -[CreateAssetMenu(fileName = "CardSortingSettings", menuName = "AppleHills/Settings/CardSorting", order = 4)] -class CardSortingSettings : BaseSettings, ICardSortingSettings -{ - [Header("Timing")] - [Tooltip("Total game duration in seconds")] - [SerializeField] private float gameDuration = 120f; - - [Tooltip("Initial time between item spawns (seconds)")] - [SerializeField] private float initialSpawnInterval = 2f; - - [Tooltip("Minimum time between item spawns as difficulty increases (seconds)")] - [SerializeField] private float minimumSpawnInterval = 0.5f; - - [Header("Conveyor Speed")] - [Tooltip("Initial belt movement speed")] - [SerializeField] private float initialBeltSpeed = 1f; - - [Tooltip("Maximum belt movement speed")] - [SerializeField] private float maxBeltSpeed = 3f; - - [Tooltip("Curve for difficulty progression (X=time%, Y=speed multiplier)")] - [SerializeField] private AnimationCurve speedCurve; - - [Header("Item Pools")] - [Tooltip("Garbage items that can spawn (banana peels, cans, receipts, etc.)")] - [SerializeField] private GarbageItemDefinition[] garbageItems; - - [Header("Spawn Weights")] - [Tooltip("Weight for spawning normal rarity cards")] - [Range(0, 100)] [SerializeField] private float normalCardWeight = 40f; - - [Tooltip("Weight for spawning rare rarity cards")] - [Range(0, 100)] [SerializeField] private float rareCardWeight = 30f; - - [Tooltip("Weight for spawning legendary rarity cards")] - [Range(0, 100)] [SerializeField] private float legendCardWeight = 20f; - - [Tooltip("Weight for spawning garbage items")] - [Range(0, 100)] [SerializeField] private float garbageWeight = 10f; - - [Header("Scoring")] - [Tooltip("Points awarded for correct sort")] - [SerializeField] private int correctSortPoints = 10; - - [Tooltip("Points deducted for incorrect sort")] - [SerializeField] private int incorrectSortPenalty = -5; - - [Tooltip("Points deducted when item falls off belt")] - [SerializeField] private int missedItemPenalty = -3; - - [Header("Rewards")] - [Tooltip("Booster packs awarded per correct sort")] - [SerializeField] private int boosterPacksPerCorrectItem = 1; - - // Interface implementation - public float GameDuration => gameDuration; - public float InitialSpawnInterval => initialSpawnInterval; - public float MinimumSpawnInterval => minimumSpawnInterval; - public float InitialBeltSpeed => initialBeltSpeed; - public float MaxBeltSpeed => maxBeltSpeed; - public AnimationCurve SpeedCurve => speedCurve; - public GarbageItemDefinition[] GarbageItems => garbageItems; - public float NormalCardWeight => normalCardWeight; - public float RareCardWeight => rareCardWeight; - public float LegendCardWeight => legendCardWeight; - public float GarbageWeight => garbageWeight; - public int CorrectSortPoints => correctSortPoints; - public int IncorrectSortPenalty => incorrectSortPenalty; - public int MissedItemPenalty => missedItemPenalty; - public int BoosterPacksPerCorrectItem => boosterPacksPerCorrectItem; - - public override void OnValidate() - { - base.OnValidate(); - - gameDuration = Mathf.Max(1f, gameDuration); - initialSpawnInterval = Mathf.Max(0.1f, initialSpawnInterval); - minimumSpawnInterval = Mathf.Max(0.1f, minimumSpawnInterval); - initialBeltSpeed = Mathf.Max(0.1f, initialBeltSpeed); - maxBeltSpeed = Mathf.Max(initialBeltSpeed, maxBeltSpeed); - correctSortPoints = Mathf.Max(0, correctSortPoints); - boosterPacksPerCorrectItem = Mathf.Max(0, boosterPacksPerCorrectItem); - } -} - -// Interface -interface ICardSortingSettings -{ - float GameDuration { get; } - float InitialSpawnInterval { get; } - float MinimumSpawnInterval { get; } - float InitialBeltSpeed { get; } - float MaxBeltSpeed { get; } - AnimationCurve SpeedCurve { get; } - GarbageItemDefinition[] GarbageItems { get; } - float NormalCardWeight { get; } - float RareCardWeight { get; } - float LegendCardWeight { get; } - float GarbageWeight { get; } - int CorrectSortPoints { get; } - int IncorrectSortPenalty { get; } - int MissedItemPenalty { get; } - int BoosterPacksPerCorrectItem { get; } -} -``` - ---- - -## Core Components - -### SortableItem (MonoBehaviour) - -**Responsibilities:** -- Inherits from `DraggableObject` -- Orchestrates drag/drop behavior -- Routes events to state machine -- Handles drop validation -- Tracks whether this is a card or garbage item - -**Key Methods:** -```csharp -void SetupAsCard(CardData cardData) // Setup with card from CardSystemManager -void SetupAsGarbage(GarbageItemDefinition) // Setup with garbage item -void OnFellOffBelt() // Called when reaches end of conveyor -protected override void OnDragStartedHook() // Check state handler -protected override void OnDragEndedHook() // Validate drop, notify manager -``` - -**Properties:** -```csharp -bool IsGarbage { get; } // True if garbage, false if card -CardData CardData { get; } // Null if garbage -GarbageItemDefinition GarbageItem { get; } // Null if card -BoxType CorrectBox { get; } // Calculated from rarity or garbage flag -``` - -**Integration Points:** -- Queries state for `ISortableItemDragHandler` -- Validates drop on `SortingBox` -- Notifies `SortingGameManager` on sort/miss - -### SortableItemContext (MonoBehaviour) - -**Responsibilities:** -- Shared state container for states -- Routes data to appropriate visual component (card vs garbage) -- Provides component references - -**Key Properties:** -```csharp -CardDisplay cardDisplay; // Assigned for cards -GarbageVisual garbageVisual; // Assigned for garbage -CardAnimator animator; // Always assigned -Transform visualTransform; // "Visual" GameObject -bool IsOnConveyor; -float ConveyorSpeed; -``` - -**Setup Logic:** -```csharp -void SetupAsCard(CardData cardData) -{ - // CardDisplay handles EVERYTHING - cardDisplay?.UpdateDisplay(cardData); -} - -void SetupAsGarbage(Sprite sprite) -{ - // Simple sprite assignment - garbageVisual?.UpdateDisplay(sprite); -} -``` - -**That's it! No conversion, no mapping, no adapters.** - -### GarbageVisual (MonoBehaviour) - -**Responsibilities:** -- Simple sprite display for non-card items -- Minimal component (~20 lines) - -**Implementation:** -```csharp -class GarbageVisual : MonoBehaviour -{ - [SerializeField] private Image spriteRenderer; - - public void UpdateDisplay(Sprite sprite) - { - if (spriteRenderer != null) - spriteRenderer.sprite = sprite; - } -} -``` - -### SortingBox (MonoBehaviour) - -**Responsibilities:** -- Drop target for sortable items -- Validates correct placement -- Visual feedback (optional) - -**Key Methods:** -```csharp -bool ValidateItem(SortableItem item) -{ - // Trash box accepts garbage - if (boxType == BoxType.Trash) - return item.IsGarbage; - - // Other boxes reject garbage, check card rarity - if (item.IsGarbage) return false; - - return item.CardData.Rarity switch { - CardRarity.Normal => boxType == BoxType.Normal, - CardRarity.Rare => boxType == BoxType.Rare, - CardRarity.Legendary => boxType == BoxType.Legend, - _ => false - }; -} - -override bool CanAccept(DraggableObject draggable) -{ - return draggable is SortableItem; -} -``` - ---- - -## State Machine - -### SortingStateMachine (Opts Out of Save System) - -```csharp -class SortingStateMachine : AppleMachine -{ - public override bool ShouldParticipateInSave() => false; -} -``` - -### Three States - -#### 1. OnConveyorState - -**Purpose:** Item moves along belt - -**Behavior:** -```csharp -void Update() -{ - Vector3 movement = Vector3.right * context.ConveyorSpeed * Time.deltaTime; - context.visualTransform.position += movement; -} - -bool OnDragStarted(SortableItemContext context) -{ - item.ChangeState("BeingDraggedState"); - return true; // Handled -} -``` - -**Entry:** Item spawned on belt -**Exit:** Player drags item OR item falls off end - -#### 2. BeingDraggedState - -**Purpose:** Player is dragging item - -**Behavior:** -```csharp -void OnEnterState() -{ - context.IsOnConveyor = false; - context.Animator.AnimateScale(Vector3.one * 1.1f, 0.2f); // Visual feedback -} - -void OnExitState() -{ - context.Animator.AnimateScale(Vector3.one, 0.2f); // Restore -} -``` - -**Entry:** Drag started from OnConveyorState -**Exit:** Drop on box (→ SortedState) OR drop elsewhere (→ OnConveyorState) - -#### 3. SortedState - -**Purpose:** Item placed in box, ready for destruction - -**Behavior:** -```csharp -void OnEnterState() -{ - context.IsOnConveyor = false; - // Animation handled by manager -} -``` - -**Entry:** Successfully dropped on box -**Exit:** Destroyed after animation - ---- - -## Controllers (Non-Component) - -### ConveyorBeltController - -**Responsibilities:** -- Spawn items at intervals -- Track active items -- Update belt speed -- Detect items falling off end - -**Constructor:** -```csharp -ConveyorBeltController( - Transform spawnPoint, - Transform endPoint, - GameObject cardPrefab, - GameObject garbagePrefab, - ICardSortingSettings settings // Uses settings interface -) -``` - -**Key Methods:** -```csharp -void Update(float deltaTime, float gameProgress) -{ - UpdateBeltSpeed(gameProgress); // Adjust speed via config curve - UpdateItemPositions(deltaTime); // Movement handled by states - CheckItemsOffBelt(); // Detect falls, notify manager -} - -SortableItem TrySpawnItem(float currentTime) -{ - if (currentTime < nextSpawnTime) return null; - - // Weighted random: card or garbage? - float totalWeight = config.normalCardWeight + config.rareCardWeight + - config.legendCardWeight + config.garbageWeight; - float roll = Random.Range(0f, totalWeight); - - SortableItem item; - - if (roll < config.garbageWeight) - { - // Spawn garbage - GarbageItemDefinition garbage = SelectRandomGarbage(); - GameObject obj = Instantiate(garbagePrefab, spawnPoint.position, Quaternion.identity); - item = obj.GetComponent(); - item.SetupAsGarbage(garbage); - } - else - { - // Spawn card - determine rarity, get random card from CardSystemManager - CardRarity rarity = DetermineRarity(roll); - CardData cardData = CardSystemManager.Instance.GetRandomCardOfRarity(rarity); - - GameObject obj = Instantiate(cardPrefab, spawnPoint.position, Quaternion.identity); - item = obj.GetComponent(); - item.SetupAsCard(cardData); - } - - activeItems.Add(item); - ScheduleNextSpawn(gameProgress); - return item; -} - -CardRarity DetermineRarity(float roll) -{ - // Adjust roll to be relative to card weights only - float adjusted = roll - config.garbageWeight; - - if (adjusted < config.normalCardWeight) return CardRarity.Normal; - if (adjusted < config.normalCardWeight + config.rareCardWeight) return CardRarity.Rare; - return CardRarity.Legendary; -} - -GarbageItemDefinition SelectRandomGarbage() -{ - return config.garbageItems[Random.Range(0, config.garbageItems.Length)]; -} - -void RemoveItem(SortableItem item) // Manual removal -``` - -**Properties:** -```csharp -float CurrentSpeed { get; } -int ActiveItemCount { get; } -``` - -### SortingScoreController - -**Responsibilities:** -- Track correct/incorrect/missed counts -- Calculate total score -- Calculate accuracy -- Calculate booster rewards - -**Constructor:** -```csharp -SortingScoreController(ICardSortingSettings settings) -``` - -**Properties:** -```csharp -int TotalScore { get; } -int CorrectSorts { get; } -int IncorrectSorts { get; } -int MissedItems { get; } -float Accuracy { get; } // correctSorts / totalAttempts -``` - -**Events:** -```csharp -event Action OnScoreChanged; -event Action OnCorrectSort; -event Action OnIncorrectSort; -``` - ---- - -## Main Manager - -### SortingGameManager (ManagedBehaviour) - -**Responsibilities:** -- Game loop orchestration -- Timer management -- Controller lifecycle -- Event coordination -- Integration with CardSystemManager - -**Singleton:** -```csharp -static SortingGameManager Instance { get; } -``` - -**Settings Access:** -```csharp -private ICardSortingSettings _settings; - -internal override void OnManagedAwake() -{ - _instance = this; - _settings = GameManager.GetSettingsObject(); -} -``` - -**Lazy-Init Controllers:** -```csharp -private ConveyorBeltController _conveyorController; -private ConveyorBeltController Conveyor => _conveyorController ??= new ConveyorBeltController( - conveyorSpawnPoint, - conveyorEndPoint, - cardPrefab, - garbagePrefab, - _settings -); - -private SortingScoreController _scoreController; -private SortingScoreController Score => _scoreController ??= new SortingScoreController(_settings); -``` - -**Game Loop:** -```csharp -void Update() -{ - if (!isGameActive || isGameOver) return; - - gameTimer += Time.deltaTime; - float remainingTime = config.gameDuration - gameTimer; - float gameProgress = gameTimer / config.gameDuration; - - OnTimerUpdated?.Invoke(remainingTime); - - if (remainingTime <= 0f) { EndGame(); return; } - - Conveyor.Update(Time.deltaTime, gameProgress); - - var item = Conveyor.TrySpawnItem(gameTimer); - if (item != null) OnItemSpawned?.Invoke(item); -} -``` - -**Public API (Called by SortableItem):** -```csharp -void OnItemSorted(SortableItem item, SortingBox box, bool correct) -{ - if (correct) Score.RecordCorrectSort(); - else Score.RecordIncorrectSort(); - - Conveyor.RemoveItem(item); - OnItemSortedEvent?.Invoke(item, box, correct); - - // Play animation then destroy - item.Context.Animator.PopOut(0.4f, () => Destroy(item.gameObject)); -} - -void OnItemMissed(SortableItem item) -{ - Score.RecordMissedItem(); - Conveyor.RemoveItem(item); -} -``` - -**End Game:** -```csharp -void EndGame() -{ - isGameOver = true; - int boosters = Score.CalculateBoosterReward(); - CardSystemManager.Instance.AddBoosterPack(boosters); - OnGameEnded?.Invoke(); -} -``` - -**Events:** -```csharp -event Action OnGameStarted; -event Action OnGameEnded; -event Action OnItemSpawned; -event Action OnItemSortedEvent; -event Action OnTimerUpdated; // Remaining time -``` - ---- - -## Animation Strategy - -### All Animations via CardAnimator - -**Target:** "Visual" GameObject (parent of CardDisplay/GarbageVisual) - -**Common Animations:** -```csharp -// Spawn on conveyor -context.Animator.PopIn(0.3f); - -// Pick up (BeingDraggedState enter) -context.Animator.AnimateScale(Vector3.one * 1.1f, 0.2f); -context.Animator.PlayBounce(0.1f); - -// Drop back to belt (BeingDraggedState exit) -context.Animator.AnimateScale(Vector3.one, 0.2f); - -// Successful sort (SortedState) -context.Animator.PopOut(0.4f, () => Destroy(gameObject)); - -// Failed sort feedback -context.Animator.PlayShake(0.3f); - -// Conveyor wobble (continuous in OnConveyorState) -context.Animator.PlayBounce(0.05f); - -// Hover over correct box -context.Animator.AnimateScale(Vector3.one * 1.1f, 0.15f); - -// Hover exit -context.Animator.AnimateScale(Vector3.one, 0.15f); -``` - -**Visual GameObject Setup:** -- CardAnimator component attached to "Visual" GameObject -- SortableItemContext.visualTransform references "Visual" -- SortableItemContext.animator references CardAnimator -- States call `context.Animator.MethodName()` - ---- - -## Implementation Phases - -### Phase 1: Data Foundation -**Goal:** Define all data structures and configurations - -**Tasks:** -1. Create `Data/Enums.cs` - BoxType only -2. Create `Data/GarbageItemDefinition.cs` - ScriptableObject for garbage items -3. Create `Core/Settings/ICardSortingSettings.cs` - Interface (follow IDivingMinigameSettings pattern) -4. Create `Core/Settings/CardSortingSettings.cs` - Settings class (follow DivingMinigameSettings pattern) -5. Register CardSortingSettings in SettingsEditorWindow: - - Add to tab names array: "Card Sorting" - - Add case to switch statement - - Add to CreateSettingsIfMissing calls -6. Create 3-5 GarbageItemDefinitions in editor (banana peel, can, receipt, etc.) -7. Create CardSortingSettings asset via menu (will auto-create on first editor window open) - -**Validation:** -- Can create GarbageItemDefinition assets -- CardSortingSettings appears in Settings Editor window -- Can modify settings values in editor -- Settings accessible via `GameManager.GetSettingsObject()` - ---- - -### Phase 2: Core Components -**Goal:** Build sortable item and visual system - -**Tasks:** -1. Create `Core/GarbageVisual.cs` - Simple sprite renderer -2. Create `Core/SortableItemContext.cs` - Shared state, visual routing -3. Create `StateMachine/SortingStateMachine.cs` - Save opt-out (copy CardStateMachine) -4. Create `Core/SortableItem.cs` - Drag orchestration -5. Create `Core/SortingBox.cs` - Drop target validation - -**Validation:** -- GarbageVisual displays sprite correctly -- SortableItemContext routes data to cardDisplay/garbageVisual -- SortingStateMachine doesn't register with SaveLoadManager -- SortableItem inherits DraggableObject correctly -- SortingBox validates card rarity or garbage flag correctly - ---- - -### Phase 3: State Machine -**Goal:** Implement 3 states for item behavior - -**Tasks:** -1. Create `StateMachine/States/OnConveyorState.cs` - Movement logic -2. Create `StateMachine/States/BeingDraggedState.cs` - Visual feedback -3. Create `StateMachine/States/SortedState.cs` - Destruction ready -4. Add `ISortableItemDragHandler` interface to OnConveyorState - -**Validation:** -- OnConveyorState moves item right at ConveyorSpeed -- Drag starts → transitions to BeingDraggedState -- BeingDraggedState scales up visuals -- Drop on box → transitions to SortedState -- States use OnDisable() for cleanup (not OnExitState - AppleState doesn't have it) - ---- - -### Phase 4: Prefab Creation -**Goal:** Build two prefab variants with shared logic - -**Tasks:** -1. Create `SortableCardPrefab`: - - Add SortableItem, SortableItemContext components - - Add CardAnimator component - - Create "Visual" child GameObject - - Nest CardDisplay prefab under "Visual" - - Add SortingStateMachine with 3 state children - - Wire all references -2. Create `SortableGarbagePrefab`: - - Duplicate SortableCardPrefab - - Remove CardDisplay nested prefab - - Add GarbageVisual component to "Visual" GameObject - - Add Image component to "Visual" - - Wire garbageVisual reference -3. Create 4 `SortingBox` prefabs (Normal/Rare/Legend/Trash) - -**Validation:** -- Both prefabs use SAME scripts -- CardAnimator targets "Visual" GameObject on both -- SortableCardPrefab has cardDisplay assigned, garbageVisual null -- SortableGarbagePrefab has garbageVisual assigned, cardDisplay null -- Dragging works on both prefabs -- Visual differences isolated to "Visual" child - ---- - -### Phase 5: Controllers ✅ COMPLETE -**Goal:** Implement non-component logic controllers - -**Tasks:** -1. ✅ Create `Controllers/ConveyorBeltController.cs`: - - Spawning with weighted random selection - - Speed curve evaluation - - Active item tracking - - Fall-off detection -2. ✅ Create `Controllers/SortingScoreController.cs`: - - Score tracking - - Accuracy calculation - - Booster reward calculation - - Event firing - -**Validation:** -- ✅ ConveyorBeltController spawns correct prefab (card vs garbage) -- ✅ Spawn rate increases over time (lerp based on game progress) -- ✅ Belt speed increases per config curve -- ✅ Items detected when falling off end (x position > endPoint.x) -- ✅ Score updates correctly on correct/incorrect/missed -- ✅ Accuracy percentage calculated correctly (correctSorts / totalAttempts) -- ✅ No compilation errors - ---- - -### Phase 6: Game Manager ✅ COMPLETE -**Goal:** Orchestrate game loop and integration - -**Tasks:** -1. ✅ Create `Core/SortingGameManager.cs`: - - Singleton setup - - Lazy-init controllers - - Game loop (Update) - - Timer management - - Event handling - - Integration with CardSystemManager -2. ✅ Add inspector references (spawnPoint, endPoint, prefabs, boxes, config) -3. ✅ Uncomment SortingGameManager references in SortableItem - -**Validation:** -- ✅ Timer counts down correctly -- ✅ Items spawn at increasing rate -- ✅ Belt speed increases -- ✅ OnItemSorted called when dropped on box -- ✅ OnItemMissed called when falls off belt -- ✅ Boosters granted at end via CardSystemManager -- ✅ Events fire correctly -- ✅ No compilation errors - ---- - -### Phase 7: Scene Setup -**Goal:** Build playable minigame scene - -**Tasks:** -1. Create new scene `CardSorting.unity` -2. Add conveyor belt visual (sprite/sprite renderer) -3. Position 4 SortingBox instances: - - Normal (bottom-left) - - Rare (bottom-center-left) - - Legend (bottom-center-right) - - Trash (bottom-right) -4. Add spawn point marker (empty GameObject at left edge) -5. Add end point marker (empty GameObject at right edge) -6. Add SortingGameManager to scene -7. Wire all references in inspector (spawn points, prefabs, boxes) - - Note: Settings accessed via GameManager, no inspector reference needed -8. Add Canvas with UI layout (timer, score - can be placeholder) - -**Validation:** -- Play scene, items spawn and move -- Drag item to box, validates correctly -- Correct sort → score increases -- Incorrect sort → penalty applied -- Items fall off end → miss penalty -- Timer expires → game ends, boosters granted -- Settings changes in editor reflect in game - ---- - -### Phase 8: UI (Minimal MVP) ✅ COMPLETE -**Goal:** Display essential game info - -**Tasks:** -1. ✅ Create `UI/SortingGameHUD.cs`: - - Timer display (TextMeshProUGUI) - - Score display (TextMeshProUGUI) - - Accuracy display (TextMeshProUGUI) - - Subscribe to SortingGameManager events -2. ✅ Create `UI/SortingResultsScreen.cs`: - - Final score - - Accuracy percentage - - Boosters earned - - Close button - -**Validation:** -- ✅ Timer updates every frame -- ✅ Score updates on events -- ✅ Accuracy displays correctly -- ✅ Results screen shows correct data -- ✅ Can close and return to game -- ✅ No compilation errors - ---- - -### Phase 9: Polish (Post-MVP) -**Optional enhancements after core functionality proven** - -**Tasks:** -1. Particle effects on correct sort -2. Sound effects (pickup, drop, correct, wrong) -3. Visual feedback when hovering over correct/wrong box -4. Combo system (consecutive correct sorts) -5. More defect types with visual indicators -6. Tutorial sequence with Mr. Cement dialogue -7. Background music -8. Conveyor belt animation (scrolling texture) - ---- - -## File Structure - -``` -Assets/Scripts/Minigames/CardSorting/ -├── Core/ -│ ├── SortingGameManager.cs -│ ├── SortableItem.cs -│ ├── SortableItemContext.cs -│ ├── GarbageVisual.cs -│ └── SortingBox.cs -├── StateMachine/ -│ ├── SortingStateMachine.cs -│ └── States/ -│ ├── OnConveyorState.cs -│ ├── BeingDraggedState.cs -│ └── SortedState.cs -├── Controllers/ -│ ├── ConveyorBeltController.cs -│ └── SortingScoreController.cs -├── Data/ -│ ├── Enums.cs -│ └── GarbageItemDefinition.cs -└── UI/ - ├── SortingGameHUD.cs - └── SortingResultsScreen.cs - -Assets/Scripts/Core/Settings/ -├── ICardSortingSettings.cs (interface) -└── CardSortingSettings.cs (BaseSettings implementation) - -Assets/Editor/Settings/ -└── SettingsEditorWindow.cs (add CardSortingSettings tab) -``` - ---- - -## Integration Points - -### GameManager (Settings) -```csharp -// Access settings (available after GameManager initialization) -ICardSortingSettings settings = GameManager.GetSettingsObject(); -``` - -### CardSystemManager -```csharp -// Get random card by rarity -CardData cardData = CardSystemManager.Instance.GetRandomCardOfRarity(CardRarity.Rare); - -// Grant boosters at game end -CardSystemManager.Instance.AddBoosterPack(boosterCount); -``` - -### InputManager -```csharp -// Set input mode on game start -InputManager.Instance.SetInputMode(InputMode.GameAndUI); -``` - -### UIPageController (Optional) -```csharp -// Show results screen -UIPageController.Instance.PushPage(sortingResultsScreen); -``` - -### SettingsEditorWindow -```csharp -// Add CardSortingSettings tab (Phase 1) -// Follows pattern of DivingMinigameSettings registration -``` - ---- - -## Key Design Decisions - -### 1. Two Prefabs, Shared Logic -- Cards and garbage use SAME scripts (SortableItem, SortableItemContext, states) -- Visual differences isolated to "Visual" child GameObject -- CardAnimator animates "Visual" on both prefabs -- No code duplication - -### 2. Cards Use Existing CardDefinitions -- **No data duplication!** Cards spawn from CardSystemManager's existing CardDefinition collection -- CardDisplay receives CardData directly, handles all rendering -- Garbage items have simple GarbageItemDefinition (id, name, sprite) -- Zero conversion/mapping layer needed - -### 3. Settings Architecture Pattern -- **Follows DivingMinigameSettings pattern exactly** -- CardSortingSettings inherits BaseSettings, implements ICardSortingSettings -- Registered in SettingsEditorWindow with own tab -- Accessed via `GameManager.GetSettingsObject()` -- Designer-friendly: all configuration in Unity editor -- No ScriptableObject references in scene (accessed globally via GameManager) - -### 4. Visual GameObject Strategy -- "Visual" GameObject is parent of CardDisplay/GarbageVisual -- CardAnimator targets "Visual" -- Animations work identically for both item types -- Clean separation of logic (root) vs presentation (visual child) - -### 5. State Machine Simplicity -- Only 3 states vs 10 in card system -- Linear flow: OnConveyor → BeingDragged → Sorted -- No complex branching or edge cases -- Opts out of save system (runtime-only) - -### 6. Non-Component Controllers -- ConveyorBeltController, SortingScoreController are plain C# classes -- Lazy-initialized in SortingGameManager -- No Unity lifecycle overhead -- Easy to test and maintain - -### 7. Event-Driven Architecture -- Controllers fire events, UI subscribes -- Decoupled components -- Easy to extend with new features - ---- - -## Testing Checklist - -### Core Functionality -- [ ] Items spawn on conveyor at correct rate -- [ ] Items move right at increasing speed -- [ ] Can drag items from conveyor -- [ ] Cards display with correct rarity colors/borders -- [ ] Garbage displays with sprite only -- [ ] Drop on correct box → score increases -- [ ] Drop on wrong box → penalty applied -- [ ] Item falls off belt → miss penalty -- [ ] Timer counts down correctly -- [ ] Game ends at 0:00 - -### Animations -- [ ] PopIn on spawn -- [ ] Scale up when dragged -- [ ] Scale down when released -- [ ] PopOut on successful sort -- [ ] Shake on failed sort -- [ ] Conveyor wobble (continuous) - -### Scoring -- [ ] Correct sort grants points -- [ ] Incorrect sort applies penalty -- [ ] Missed item applies penalty -- [ ] Accuracy calculated correctly -- [ ] Booster reward calculated correctly - -### Integration -- [ ] Boosters granted to CardSystemManager -- [ ] Input mode set correctly -- [ ] No save system participation - -### Edge Cases -- [ ] Drag item off screen → returns to belt or destroys -- [ ] Multiple items on belt simultaneously -- [ ] Rapid dragging doesn't break spawning -- [ ] Game end mid-drag handles gracefully -- [ ] Empty item pools handled gracefully - ---- - -## Code Metrics Estimate - -**Total New Code:** ~800 lines -- SortingGameManager: ~150 lines -- ConveyorBeltController: ~160 lines (simpler spawning) -- SortingScoreController: ~80 lines -- SortableItem + SortableItemContext: ~120 lines (no conversion logic) -- 3 States: ~120 lines -- Data types: ~40 lines (Enums, GarbageItemDefinition only) -- Settings: ~100 lines (ICardSortingSettings interface + CardSortingSettings class) -- SettingsEditorWindow changes: ~10 lines (registration) -- GarbageVisual: ~20 lines -- SortingBox: ~40 lines -- UI scripts: ~70 lines - -**Reused Code:** ~2000+ lines -- CardDisplay (complete visual system) -- CardAnimator (all animations) -- DraggableObject (drag/drop framework) -- AppleMachine (state machine base) -- **CardData (used directly, no conversion!)** -- **CardDefinition (from CardSystemManager!)** -- **Settings architecture (BaseSettings, GameManager integration)** - -**Code Duplication:** 0 lines -**Data Duplication:** 0 (cards reuse existing definitions!) - ---- - -**Last Updated:** November 18, 2025 -**Status:** Planning Phase -**Next Step:** Phase 1 - Data Foundation - -- 2.49.1