Fix card cleanup after dismissing minigame

This commit is contained in:
Michal Pikulski
2025-12-16 17:35:05 +01:00
parent b516b093af
commit ba1e506bc6
4 changed files with 154 additions and 6 deletions

View File

@@ -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}

View File

@@ -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<SortableItem> activeItems = new List<SortableItem>();
private HashSet<SortableItem> missedItems = new HashSet<SortableItem>(); // 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<SortableItem>();
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<SortableItem>();
if (item != null)
@@ -497,6 +500,39 @@ namespace Minigames.CardSorting.Controllers
Debug.Log("[ConveyorBeltController] Conveyor stopped - all items disabled");
}
/// <summary>
/// Destroy all active items on the conveyor.
/// Called when quitting to main level to cleanup spawned items.
/// </summary>
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");
}
}
}

View File

@@ -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");
}
/// <summary>
/// Get or create the container for spawned items.
/// Ensures all cards/garbage are organized in the hierarchy.
/// </summary>
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());
}
/// <summary>
/// Cleanup all dynamically spawned items (cards/garbage).
/// Called when quitting to main level to prevent items from lingering on screen.
/// </summary>
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<SortableItem>(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

View File

@@ -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)
{