diff --git a/Assets/Scenes/MiniGames/CardQualityControl.unity b/Assets/Scenes/MiniGames/CardQualityControl.unity index 434599a5..a90a324d 100644 --- a/Assets/Scenes/MiniGames/CardQualityControl.unity +++ b/Assets/Scenes/MiniGames/CardQualityControl.unity @@ -159,6 +159,7 @@ MonoBehaviour: - {fileID: 731655009} - {fileID: 254614580} - {fileID: 222800744} + spawnedItemsContainer: {fileID: 330631194} impulseSource: {fileID: 90351797} livesDisplay: {fileID: 934831599} --- !u!4 &90351796 @@ -375,6 +376,37 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: a25b1c9a82b540c8ac0d6c016849f561, type: 3} m_Name: m_EditorClassIdentifier: AppleHillsScripts::Minigames.CardSorting.Core.SortingBox +--- !u!1 &330631193 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 330631194} + m_Layer: 0 + m_Name: SpawnedItemsTransform + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &330631194 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 330631193} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!224 &425139808 stripped RectTransform: m_CorrespondingSourceObject: {fileID: 707190640386266950, guid: acc5a752dcc18834b984fe78b6926dad, type: 3} @@ -499,6 +531,7 @@ GameObject: m_IsActive: 1 --- !u!212 &558760374 SpriteRenderer: + serializedVersion: 2 m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} @@ -544,6 +577,7 @@ SpriteRenderer: m_SortingLayerID: 622133659 m_SortingLayer: -1 m_SortingOrder: 0 + m_MaskInteraction: 0 m_Sprite: {fileID: -673586258, guid: 91cb3ae9a614f914997704a638d8b514, type: 3} m_Color: {r: 1, g: 1, b: 1, a: 1} m_FlipX: 0 @@ -553,7 +587,6 @@ SpriteRenderer: m_AdaptiveModeThreshold: 0.5 m_SpriteTileMode: 0 m_WasSpriteAssigned: 1 - m_MaskInteraction: 0 m_SpriteSortPoint: 0 --- !u!4 &558760375 Transform: @@ -1174,6 +1207,7 @@ GameObject: m_IsActive: 1 --- !u!212 &1020017634 SpriteRenderer: + serializedVersion: 2 m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} @@ -1219,6 +1253,7 @@ SpriteRenderer: m_SortingLayerID: 622133659 m_SortingLayer: -1 m_SortingOrder: 0 + m_MaskInteraction: 0 m_Sprite: {fileID: -7171755534009967257, guid: b382c7219ff059c499bdeba018f5a93f, type: 3} m_Color: {r: 1, g: 1, b: 1, a: 1} m_FlipX: 0 @@ -1228,7 +1263,6 @@ SpriteRenderer: m_AdaptiveModeThreshold: 0.5 m_SpriteTileMode: 0 m_WasSpriteAssigned: 1 - m_MaskInteraction: 0 m_SpriteSortPoint: 0 --- !u!4 &1020017635 Transform: @@ -2212,5 +2246,6 @@ SceneRoots: - {fileID: 558760375} - {fileID: 1020017635} - {fileID: 1541890084} + - {fileID: 330631194} - {fileID: 621563394} - {fileID: 818930091} diff --git a/Assets/Scripts/Minigames/CardSorting/Controllers/ConveyorBeltController.cs b/Assets/Scripts/Minigames/CardSorting/Controllers/ConveyorBeltController.cs index 00540d6b..8b04e131 100644 --- a/Assets/Scripts/Minigames/CardSorting/Controllers/ConveyorBeltController.cs +++ b/Assets/Scripts/Minigames/CardSorting/Controllers/ConveyorBeltController.cs @@ -23,6 +23,7 @@ namespace Minigames.CardSorting.Controllers private readonly GameObject cardPrefab; private readonly GameObject garbagePrefab; private readonly ICardSortingSettings settings; + private readonly Transform spawnContainer; // Container for all spawned items private List activeItems = new List(); private HashSet missedItems = new HashSet(); // Items past visual end, moving to despawn @@ -48,7 +49,8 @@ namespace Minigames.CardSorting.Controllers Transform despawnPoint, GameObject cardPrefab, GameObject garbagePrefab, - ICardSortingSettings settings) + ICardSortingSettings settings, + Transform spawnContainer) { this.spawnPoint = spawnPoint; this.endPoint = endPoint; @@ -56,6 +58,7 @@ namespace Minigames.CardSorting.Controllers this.cardPrefab = cardPrefab; this.garbagePrefab = garbagePrefab; this.settings = settings; + this.spawnContainer = spawnContainer; this.currentSpeed = settings.InitialBeltSpeed; this.lastSpawnedItem = null; // No items spawned yet @@ -169,7 +172,7 @@ namespace Minigames.CardSorting.Controllers float randomOffsetY = Random.Range(settings.SpawnOffsetY.x, settings.SpawnOffsetY.y); Vector3 spawnPos = spawnPoint.position + new Vector3(0f, randomOffsetY, 0f); - GameObject obj = Object.Instantiate(garbagePrefab, spawnPos, Quaternion.identity); + GameObject obj = Object.Instantiate(garbagePrefab, spawnPos, Quaternion.identity, spawnContainer); SortableItem item = obj.GetComponent(); if (item != null) @@ -212,7 +215,7 @@ namespace Minigames.CardSorting.Controllers float randomOffsetY = Random.Range(settings.SpawnOffsetY.x, settings.SpawnOffsetY.y); Vector3 spawnPos = spawnPoint.position + new Vector3(0f, randomOffsetY, 0f); - GameObject obj = Object.Instantiate(cardPrefab, spawnPos, Quaternion.identity); + GameObject obj = Object.Instantiate(cardPrefab, spawnPos, Quaternion.identity, spawnContainer); SortableItem item = obj.GetComponent(); if (item != null) @@ -497,6 +500,39 @@ namespace Minigames.CardSorting.Controllers Debug.Log("[ConveyorBeltController] Conveyor stopped - all items disabled"); } + + /// + /// Destroy all active items on the conveyor. + /// Called when quitting to main level to cleanup spawned items. + /// + public void DestroyAllItems() + { + Debug.Log($"[ConveyorBeltController] Destroying {activeItems.Count} active items"); + + // Unsubscribe from all item events and destroy them + for (int i = activeItems.Count - 1; i >= 0; i--) + { + var item = activeItems[i]; + if (item != null) + { + // Unsubscribe from events + item.OnItemDroppedInBox -= HandleItemDroppedInBox; + item.OnItemDroppedOnFloor -= HandleItemDroppedOnFloor; + item.OnItemReturnedToConveyor -= HandleItemReturnedToConveyor; + item.OnDragStarted -= HandleItemDragStarted; + + // Destroy the game object + Object.Destroy(item.gameObject); + } + } + + // Clear all tracking + activeItems.Clear(); + missedItems.Clear(); + lastSpawnedItem = null; + + Debug.Log("[ConveyorBeltController] All items destroyed and tracking cleared"); + } } } diff --git a/Assets/Scripts/Minigames/CardSorting/Core/SortingGameManager.cs b/Assets/Scripts/Minigames/CardSorting/Core/SortingGameManager.cs index ecca109f..e00a226f 100644 --- a/Assets/Scripts/Minigames/CardSorting/Core/SortingGameManager.cs +++ b/Assets/Scripts/Minigames/CardSorting/Core/SortingGameManager.cs @@ -24,6 +24,7 @@ namespace Minigames.CardSorting.Core [SerializeField] private GameObject sortableCardPrefab; [SerializeField] private GameObject sortableGarbagePrefab; [SerializeField] private SortingBox[] sortingBoxes; + [SerializeField] private Transform spawnedItemsContainer; // Container for all spawned items (optional, will auto-create if null) [Header("Effects")] [SerializeField] private CinemachineImpulseSource impulseSource; // Screen shake on incorrect sort @@ -45,7 +46,8 @@ namespace Minigames.CardSorting.Core conveyorDespawnPoint, sortableCardPrefab, sortableGarbagePrefab, - _settings + _settings, + GetOrCreateSpawnContainer() ); // Public accessor for states to check game over status @@ -91,6 +93,26 @@ namespace Minigames.CardSorting.Core Logging.Debug("[SortingGameManager] Initialized with settings"); } + /// + /// Get or create the container for spawned items. + /// Ensures all cards/garbage are organized in the hierarchy. + /// + private Transform GetOrCreateSpawnContainer() + { + if (spawnedItemsContainer != null) + return spawnedItemsContainer; + + // Auto-create container if not assigned + var containerObj = new GameObject("[Spawned Items]"); + spawnedItemsContainer = containerObj.transform; + spawnedItemsContainer.SetParent(transform); // Parent to manager for organization + spawnedItemsContainer.localPosition = Vector3.zero; + + Logging.Debug("[SortingGameManager] Auto-created spawned items container"); + + return spawnedItemsContainer; + } + internal override void OnManagedStart() { // Subscribe to score events @@ -247,6 +269,54 @@ namespace Minigames.CardSorting.Core StartCoroutine(EndGameSequence()); } + /// + /// Cleanup all dynamically spawned items (cards/garbage). + /// Called when quitting to main level to prevent items from lingering on screen. + /// + public void CleanupAllItems() + { + Logging.Debug("[SortingGameManager] Cleaning up all spawned items"); + + // Tell conveyor to destroy all active items + // Use the property which handles lazy initialization + Conveyor?.DestroyAllItems(); + + // Also destroy any remaining children in the spawn container + if (spawnedItemsContainer != null) + { + int childCount = spawnedItemsContainer.childCount; + if (childCount > 0) + { + Logging.Debug($"[SortingGameManager] Cleaning up {childCount} items from spawn container"); + + for (int i = childCount - 1; i >= 0; i--) + { + var child = spawnedItemsContainer.GetChild(i); + if (child != null) + { + Destroy(child.gameObject); + } + } + } + } + + // Final safety check: search for any orphaned items in case of edge cases + var allItems = FindObjectsByType(FindObjectsSortMode.None); + if (allItems.Length > 0) + { + Logging.Warning($"[SortingGameManager] Found {allItems.Length} orphaned items, cleaning up..."); + + foreach (var item in allItems) + { + if (item != null && item.gameObject != null) + { + Logging.Debug($"[SortingGameManager] Destroying orphaned item: {item.CardData?.Name ?? item.GarbageItem?.DisplayName}"); + Destroy(item.gameObject); + } + } + } + } + private IEnumerator EndGameSequence() { // Calculate rewards diff --git a/Assets/Scripts/Minigames/CardSorting/UI/SortingResultsScreen.cs b/Assets/Scripts/Minigames/CardSorting/UI/SortingResultsScreen.cs index 033aa661..7db9dfb3 100644 --- a/Assets/Scripts/Minigames/CardSorting/UI/SortingResultsScreen.cs +++ b/Assets/Scripts/Minigames/CardSorting/UI/SortingResultsScreen.cs @@ -108,6 +108,13 @@ namespace Minigames.CardSorting.UI private async void OnCloseClicked() { + // Cleanup all spawned items before transitioning + var gameManager = SortingGameManager.Instance; + if (gameManager != null) + { + gameManager.CleanupAllItems(); + } + // Hide screen if (canvasGroup != null) {