Kind of working booster packs

This commit is contained in:
Michal Adam Pikulski
2025-10-20 13:45:56 +02:00
parent 32f726d229
commit 83b5c8994d
12 changed files with 1244 additions and 299 deletions

View File

@@ -44,6 +44,13 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 8d80347e4bd04c87be23a9399860783d, type: 3}
m_Name:
m_EditorClassIdentifier: AppleHillsScripts::Data.CardSystem.CardSystemManager
availableCards: []
availableCards:
- {fileID: 11400000, guid: 91031de62f795884e8e2ccbaebeebf9b, type: 2}
- {fileID: 11400000, guid: 5d8121cdf52bfe9488b40ed22d649209, type: 2}
- {fileID: 11400000, guid: 8f02c3699de87014bac8c03b96772a4b, type: 2}
- {fileID: 11400000, guid: 8fdeae7881d130f408e0f31c101ab41f, type: 2}
- {fileID: 11400000, guid: 28dbfbd7a6b2cd84b8274bd1126b220b, type: 2}
- {fileID: 11400000, guid: dec49537f6ae6d241acf8275eaa6c653, type: 2}
- {fileID: 11400000, guid: 6afed7a67f64404418f905e7808bf5cb, type: 2}
playerInventory:
boosterPackCount: 0

View File

@@ -59,7 +59,6 @@ MonoBehaviour:
boosterPackObject: {fileID: 4219171218593530538}
cardRevealContainer: {fileID: 8941221421597332096}
cardPrefab: {fileID: 3326706725254864107, guid: 594aad71e4281174da8fb4f47a8d19b0, type: 3}
cardBackPrefab: {fileID: 1385409402919571665, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
openBoosterButton: {fileID: 7440552304132850408}
continueButton: {fileID: 5542651507418784372}
canvasGroup: {fileID: 4766500435349212810}
@@ -89,6 +88,7 @@ GameObject:
m_Component:
- component: {fileID: 8941221421597332096}
- component: {fileID: 418545990734724097}
- component: {fileID: 8234492749045289478}
m_Layer: 5
m_Name: CardRevealContainer
m_TagString: Untagged
@@ -107,13 +107,16 @@ RectTransform:
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Children:
- {fileID: 8423460607813885254}
- {fileID: 4629474234990118368}
- {fileID: 4937963996820091238}
m_Father: {fileID: 2026295995152435872}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 100, y: 100}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &418545990734724097
MonoBehaviour:
@@ -132,8 +135,8 @@ MonoBehaviour:
m_Right: 0
m_Top: 0
m_Bottom: 0
m_ChildAlignment: 0
m_Spacing: 0
m_ChildAlignment: 4
m_Spacing: 50
m_ChildForceExpandWidth: 1
m_ChildForceExpandHeight: 1
m_ChildControlWidth: 0
@@ -141,6 +144,20 @@ MonoBehaviour:
m_ChildScaleWidth: 0
m_ChildScaleHeight: 0
m_ReverseArrangement: 0
--- !u!114 &8234492749045289478
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3540414444069180921}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.ContentSizeFitter
m_HorizontalFit: 2
m_VerticalFit: 2
--- !u!1 &4219171218593530538
GameObject:
m_ObjectHideFlags: 0
@@ -1027,3 +1044,309 @@ MonoBehaviour:
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!1001 &5261682198164265578
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 8941221421597332096}
m_Modifications:
- target: {fileID: 1385409402919571665, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_Name
value: CardBack
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_Pivot.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_Pivot.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_AnchorMax.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_AnchorMin.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_SizeDelta.x
value: 150
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_SizeDelta.y
value: 200
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalRotation.x
value: -0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalRotation.y
value: -0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalRotation.z
value: -0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
--- !u!224 &8423460607813885254 stripped
RectTransform:
m_CorrespondingSourceObject: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
m_PrefabInstance: {fileID: 5261682198164265578}
m_PrefabAsset: {fileID: 0}
--- !u!1001 &8747196401207539274
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 8941221421597332096}
m_Modifications:
- target: {fileID: 1385409402919571665, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_Name
value: CardBack3
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_Pivot.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_Pivot.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_AnchorMax.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_AnchorMin.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_SizeDelta.x
value: 150
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_SizeDelta.y
value: 200
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
--- !u!224 &4937963996820091238 stripped
RectTransform:
m_CorrespondingSourceObject: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
m_PrefabInstance: {fileID: 8747196401207539274}
m_PrefabAsset: {fileID: 0}
--- !u!1001 &9069218952194097868
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 8941221421597332096}
m_Modifications:
- target: {fileID: 1385409402919571665, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_Name
value: CardBack2
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_Pivot.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_Pivot.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_AnchorMax.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_AnchorMin.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_SizeDelta.x
value: 150
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_SizeDelta.y
value: 200
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
--- !u!224 &4629474234990118368 stripped
RectTransform:
m_CorrespondingSourceObject: {fileID: 4459518969173100332, guid: 1d048f366a1113d4ab16b5d332bfc11d, type: 3}
m_PrefabInstance: {fileID: 9069218952194097868}
m_PrefabAsset: {fileID: 0}

View File

@@ -91,7 +91,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 0
m_IsActive: 1
--- !u!224 &4459518969173100332
RectTransform:
m_ObjectHideFlags: 0

View File

@@ -536,10 +536,6 @@ PrefabInstance:
propertyPath: m_Name
value: BoosterOpeningPage
objectReference: {fileID: 0}
- target: {fileID: 1485089218833421720, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_IsActive
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2026295995152435872, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_Pivot.x
value: 0.5
@@ -622,37 +618,106 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 3492318441088451548, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_AnchorMax.y
value: 1
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3492318441088451548, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_AnchorMin.y
value: 1
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3492318441088451548, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_AnchoredPosition.x
value: 125
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3492318441088451548, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_AnchoredPosition.y
value: -25
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4525022388006312158, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_AnchorMax.y
value: 1
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4525022388006312158, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_AnchorMin.y
value: 1
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4525022388006312158, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_AnchoredPosition.x
value: 375
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4525022388006312158, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_AnchoredPosition.y
value: -25
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
- target: {fileID: 4629474234990118368, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4629474234990118368, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_AnchorMin.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4629474234990118368, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_AnchoredPosition.x
value: 350
objectReference: {fileID: 0}
- target: {fileID: 4629474234990118368, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_AnchoredPosition.y
value: -150
objectReference: {fileID: 0}
- target: {fileID: 4937963996820091238, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4937963996820091238, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_AnchorMin.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4937963996820091238, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_AnchoredPosition.x
value: 600
objectReference: {fileID: 0}
- target: {fileID: 4937963996820091238, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_AnchoredPosition.y
value: -150
objectReference: {fileID: 0}
- target: {fileID: 6502272725549189819, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_IsActive
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7664491371311212187, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_IsActive
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7990969126200070685, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_IsActive
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8423460607813885254, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 8423460607813885254, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_AnchorMin.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 8423460607813885254, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_AnchoredPosition.x
value: 100
objectReference: {fileID: 0}
- target: {fileID: 8423460607813885254, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_AnchoredPosition.y
value: -150
objectReference: {fileID: 0}
- target: {fileID: 8941221421597332096, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_SizeDelta.x
value: 700
objectReference: {fileID: 0}
- target: {fileID: 8941221421597332096, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
propertyPath: m_SizeDelta.y
value: 300
objectReference: {fileID: 0}
m_RemovedComponents:
- {fileID: 8234492749045289478, guid: 06de8e223a669fe48b043983963d1e6a, type: 3}
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []

View File

@@ -119,6 +119,68 @@ NavMeshSettings:
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &205824278
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 205824280}
- component: {fileID: 205824279}
m_Layer: 0
m_Name: CardSystemTester
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &205824279
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 205824278}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 6c59c766505c4342983594dbe19f3db0, type: 3}
m_Name:
m_EditorClassIdentifier: AppleHillsScripts::AppleHills.Tests.CardSystemTester
cardAlbumUI: {fileID: 1148731766}
boosterPacksToAdd: 3
cardsToGenerate: 10
autoOpenPacksWhenAdded: 0
currentBoosterCount: 0
totalCardsInCollection: 0
lastActionMessage:
--- !u!4 &205824280
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 205824278}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 1182.0137, y: 708.06934, 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!114 &1148731766 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 2276827791912418824, guid: 840f3d8a936b39a41b5896328a692005, type: 3}
m_PrefabInstance: {fileID: 7454556111239468018}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe5ff32f529d4f24a2064ee1dfa07758, type: 3}
m_Name:
m_EditorClassIdentifier: AppleHillsScripts::AppleHills.UI.CardSystem.CardAlbumUI
--- !u!1 &1860325688
GameObject:
m_ObjectHideFlags: 0
@@ -264,10 +326,58 @@ PrefabInstance:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 392754686162327284, guid: 840f3d8a936b39a41b5896328a692005, type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 392754686162327284, guid: 840f3d8a936b39a41b5896328a692005, type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 392754686162327284, guid: 840f3d8a936b39a41b5896328a692005, type: 3}
propertyPath: m_SizeDelta.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 392754686162327284, guid: 840f3d8a936b39a41b5896328a692005, type: 3}
propertyPath: m_SizeDelta.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 392754686162327284, guid: 840f3d8a936b39a41b5896328a692005, type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 392754686162327284, guid: 840f3d8a936b39a41b5896328a692005, type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1151296155612236777, guid: 840f3d8a936b39a41b5896328a692005, type: 3}
propertyPath: m_SizeDelta.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2111181035997726038, guid: 840f3d8a936b39a41b5896328a692005, type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2111181035997726038, guid: 840f3d8a936b39a41b5896328a692005, type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2111181035997726038, guid: 840f3d8a936b39a41b5896328a692005, type: 3}
propertyPath: m_SizeDelta.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2111181035997726038, guid: 840f3d8a936b39a41b5896328a692005, type: 3}
propertyPath: m_SizeDelta.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2111181035997726038, guid: 840f3d8a936b39a41b5896328a692005, type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2111181035997726038, guid: 840f3d8a936b39a41b5896328a692005, type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3334079986954822490, guid: 840f3d8a936b39a41b5896328a692005, type: 3}
propertyPath: m_text
value: Card Album Main Page
@@ -276,6 +386,30 @@ PrefabInstance:
propertyPath: m_text
value: Browse your cards!
objectReference: {fileID: 0}
- target: {fileID: 4460458858467128264, guid: 840f3d8a936b39a41b5896328a692005, type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4460458858467128264, guid: 840f3d8a936b39a41b5896328a692005, type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4460458858467128264, guid: 840f3d8a936b39a41b5896328a692005, type: 3}
propertyPath: m_SizeDelta.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4460458858467128264, guid: 840f3d8a936b39a41b5896328a692005, type: 3}
propertyPath: m_SizeDelta.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4460458858467128264, guid: 840f3d8a936b39a41b5896328a692005, type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4460458858467128264, guid: 840f3d8a936b39a41b5896328a692005, type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4825712728562046718, guid: 840f3d8a936b39a41b5896328a692005, type: 3}
propertyPath: m_IsActive
value: 0
@@ -479,3 +613,4 @@ SceneRoots:
m_Roots:
- {fileID: 7454556111239468018}
- {fileID: 1860325691}
- {fileID: 205824280}

View File

@@ -50,7 +50,27 @@ namespace AppleHills.Data.CardSystem
/// </summary>
public List<CardData> GetAllCards()
{
return new List<CardData>(collectedCards.Values);
return collectedCards.Values.ToList();
}
/// <summary>
/// Clears all cards from the inventory
/// Primarily used for testing
/// </summary>
public void ClearAllCards()
{
collectedCards.Clear();
// Clear lookup dictionaries
foreach (var zone in cardsByZone.Keys)
{
cardsByZone[zone].Clear();
}
foreach (var rarity in cardsByRarity.Keys)
{
cardsByRarity[rarity].Clear();
}
}
/// <summary>

View File

@@ -273,5 +273,79 @@ namespace Data.CardSystem
return (float)collectedInZone / totalInZone * 100f;
}
/// <summary>
/// Returns all available card definitions in the system
/// </summary>
public List<CardDefinition> GetAllCardDefinitions()
{
return new List<CardDefinition>(availableCards);
}
/// <summary>
/// Returns direct access to the player's card inventory
/// For advanced operations and testing
/// </summary>
public CardInventory GetCardInventory()
{
return playerInventory;
}
/// <summary>
/// Returns cards filtered by both zone and rarity
/// </summary>
public List<CardData> GetCardsByZoneAndRarity(CardZone zone, CardRarity rarity)
{
List<CardData> zoneCards = GetCardsByZone(zone);
return zoneCards.FindAll(c => c.Rarity == rarity);
}
/// <summary>
/// Returns the count of cards by rarity
/// </summary>
public int GetCardCountByRarity(CardRarity rarity)
{
return playerInventory.GetCardsByRarity(rarity).Count;
}
/// <summary>
/// Returns the count of cards by zone
/// </summary>
public int GetCardCountByZone(CardZone zone)
{
return playerInventory.GetCardsByZone(zone).Count;
}
/// <summary>
/// Gets the total number of card definitions available in the system
/// </summary>
public int GetTotalCardDefinitionsCount()
{
return availableCards.Count;
}
/// <summary>
/// Gets the total collection completion percentage (0-100)
/// </summary>
public float GetTotalCompletionPercentage()
{
if (availableCards.Count == 0) return 0;
return (float)GetUniqueCardCount() / availableCards.Count * 100f;
}
/// <summary>
/// Gets total completion percentage for a specific rarity (0-100)
/// </summary>
public float GetRarityCompletionPercentage(CardRarity rarity)
{
// Count available cards of this rarity
int totalOfRarity = availableCards.FindAll(c => c.Rarity == rarity).Count;
if (totalOfRarity == 0) return 0;
// Count collected cards of this rarity
int collectedOfRarity = playerInventory.GetCardsByRarity(rarity).Count;
return (float)collectedOfRarity / totalOfRarity * 100f;
}
}
}

View File

@@ -16,7 +16,6 @@ namespace AppleHills.Tests
public class CardSystemTester : MonoBehaviour
{
[Header("References")]
[SerializeField] private CardSystemManager cardSystemManager;
[SerializeField] private CardAlbumUI cardAlbumUI;
[Header("Test Settings")]
@@ -32,16 +31,10 @@ namespace AppleHills.Tests
private void Awake()
{
// Auto-find references if needed
if (cardSystemManager == null)
cardSystemManager = FindAnyObjectByType<CardSystemManager>();
if (cardAlbumUI == null)
cardAlbumUI = FindAnyObjectByType<CardAlbumUI>();
// Log missing references
if (cardSystemManager == null)
Debug.LogError("CardSystemTester: No CardSystemManager found in the scene!");
if (cardAlbumUI == null)
Debug.LogError("CardSystemTester: No CardAlbumUI found in the scene!");
}
@@ -54,10 +47,11 @@ namespace AppleHills.Tests
// Refresh the debug information displayed in the inspector
private void RefreshDebugInfo()
{
if (cardSystemManager != null)
// Access CardSystemManager through the singleton Instance
if (CardSystemManager.Instance != null)
{
currentBoosterCount = cardSystemManager.GetBoosterPackCount();
totalCardsInCollection = cardSystemManager.GetCardInventory().GetAllCards().Count;
currentBoosterCount = CardSystemManager.Instance.GetBoosterPackCount();
totalCardsInCollection = CardSystemManager.Instance.GetCardInventory().GetAllCards().Count;
}
}
@@ -65,9 +59,10 @@ namespace AppleHills.Tests
// Custom editor buttons for testing
public void AddBoosterPacks()
{
if (cardSystemManager != null)
// Access CardSystemManager through the singleton Instance
if (CardSystemManager.Instance != null)
{
cardSystemManager.AddBoosterPack(boosterPacksToAdd);
CardSystemManager.Instance.AddBoosterPack(boosterPacksToAdd);
lastActionMessage = $"Added {boosterPacksToAdd} booster pack(s)";
Logging.Debug($"[CardSystemTester] {lastActionMessage}");
RefreshDebugInfo();
@@ -135,10 +130,11 @@ namespace AppleHills.Tests
public void GenerateRandomCards()
{
if (cardSystemManager != null)
// Access CardSystemManager through the singleton Instance
if (CardSystemManager.Instance != null)
{
int cardsAdded = 0;
List<CardDefinition> allDefinitions = cardSystemManager.GetAllCardDefinitions();
List<CardDefinition> allDefinitions = CardSystemManager.Instance.GetAllCardDefinitions();
if (allDefinitions.Count == 0)
{
@@ -154,7 +150,7 @@ namespace AppleHills.Tests
// Create a card data instance and add it to inventory
CardData newCard = randomDef.CreateCardData();
cardSystemManager.GetCardInventory().AddCard(newCard);
CardSystemManager.Instance.GetCardInventory().AddCard(newCard);
cardsAdded++;
}
@@ -166,21 +162,17 @@ namespace AppleHills.Tests
public void ClearAllCards()
{
if (cardSystemManager != null)
// Access CardSystemManager through the singleton Instance
if (CardSystemManager.Instance != null)
{
int count = cardSystemManager.GetCardInventory().GetAllCards().Count;
cardSystemManager.GetCardInventory().ClearAllCards();
int count = CardSystemManager.Instance.GetCardInventory().GetAllCards().Count;
CardSystemManager.Instance.GetCardInventory().ClearAllCards();
lastActionMessage = $"Cleared {count} cards from inventory";
Logging.Debug($"[CardSystemTester] {lastActionMessage}");
RefreshDebugInfo();
}
}
#endif
// Update is called once per frame
void Update()
{
}
}
#if UNITY_EDITOR
@@ -196,6 +188,9 @@ namespace AppleHills.Tests
EditorGUILayout.Space();
EditorGUILayout.LabelField("Test Actions", EditorStyles.boldLabel);
// Only enable buttons when in play mode
GUI.enabled = Application.isPlaying;
if (GUILayout.Button("Add Booster Packs"))
{
tester.AddBoosterPacks();
@@ -227,6 +222,13 @@ namespace AppleHills.Tests
{
tester.ClearAllCards();
}
// If not in play mode, show a hint
if (!Application.isPlaying)
{
GUI.enabled = true;
EditorGUILayout.HelpBox("Enter Play Mode to use these testing functions.", MessageType.Info);
}
}
}
#endif

View File

@@ -77,158 +77,108 @@ namespace AppleHills.UI.CardSystem
if (collectedCards.Count > 0)
{
// Create card UI elements
CreateCardStack(collectedCards);
DisplayCards(collectedCards);
}
}
/// <summary>
/// Creates UI elements for the player's collected cards
/// </summary>
private void CreateCardStack(List<CardData> cards)
private void DisplayCards(List<CardData> cards)
{
if (albumGrid == null || cardPrefab == null) return;
// Stack offset for visual effect
Vector3 stackOffset = new Vector3(5f, -5f, 0f);
Vector3 basePosition = Vector3.zero;
// Sort cards by collection index
cards.Sort((a, b) => a.CollectionIndex.CompareTo(b.CollectionIndex));
// Create card UI elements
for (int i = 0; i < cards.Count; i++)
foreach (var cardData in cards)
{
GameObject cardObj = Instantiate(cardPrefab, albumGrid.transform);
CardUIElement cardUI = cardObj.GetComponent<CardUIElement>();
// Configure the card UI with the card data
CardUIElement cardUI = cardObj.GetComponent<CardUIElement>();
if (cardUI != null)
{
// Position in stack
cardObj.GetComponent<RectTransform>().anchoredPosition = basePosition + (stackOffset * i);
// Set up card data
cardUI.SetupCard(cards[i]);
// Add drag handlers
SetupCardDragHandlers(cardUI);
// Add to tracked cards
cardUI.SetupCard(cardData);
_displayedCards.Add(cardUI);
}
}
}
/// <summary>
/// Sets up drag and drop handlers for a card
/// </summary>
private void SetupCardDragHandlers(CardUIElement cardUI)
{
// Add click listener to handle card clicks
Button cardButton = cardUI.GetComponent<Button>();
if (cardButton != null)
{
cardButton.onClick.AddListener(() => OnCardClicked(cardUI));
}
// Subscribe to the card's own click event
cardUI.OnCardClicked += OnCardClicked;
}
/// <summary>
/// Handles when a card is clicked (simplistic alternative to drag and drop)
/// </summary>
private void OnCardClicked(CardUIElement cardUI)
{
CardData cardData = cardUI.GetCardData();
// Currently, clicking a card does not perform any action
// This can be expanded to show card details or other interactions
}
/// <summary>
/// Clears all cards from the album
/// Clears all card UI elements from the album
/// </summary>
private void ClearAlbum()
{
// Clear card UI elements
foreach (var card in _displayedCards)
{
if (card != null && card.gameObject != null)
{
Destroy(card.gameObject);
}
}
_displayedCards.Clear();
}
/// <summary>
/// Initialize filtering UI and set up listeners
/// Initializes filter dropdowns
/// </summary>
private void InitializeFilters()
{
// Setup zone filter
// Setup zone filter dropdown
if (zoneFilterDropdown != null)
{
zoneFilterDropdown.ClearOptions();
// Add "All Zones" option
List<string> zoneOptions = new List<string> { "All Zones" };
List<string> zoneOptions = new List<string>() { "All Zones" };
// Add each zone
// Add options for each zone
foreach (CardZone zone in System.Enum.GetValues(typeof(CardZone)))
{
zoneOptions.Add(zone.ToString());
}
zoneFilterDropdown.AddOptions(zoneOptions);
zoneFilterDropdown.onValueChanged.AddListener(OnZoneFilterChanged);
zoneFilterDropdown.onValueChanged.AddListener(OnFilterChanged);
}
// Setup rarity filter
// Setup rarity filter dropdown
if (rarityFilterDropdown != null)
{
rarityFilterDropdown.ClearOptions();
// Add "All Rarities" option
List<string> rarityOptions = new List<string> { "All Rarities" };
List<string> rarityOptions = new List<string>() { "All Rarities" };
// Add each rarity
// Add options for each rarity
foreach (CardRarity rarity in System.Enum.GetValues(typeof(CardRarity)))
{
rarityOptions.Add(rarity.ToString());
}
rarityFilterDropdown.AddOptions(rarityOptions);
rarityFilterDropdown.onValueChanged.AddListener(OnRarityFilterChanged);
rarityFilterDropdown.onValueChanged.AddListener(OnFilterChanged);
}
// Setup reset button
// Setup reset filters button
if (resetFiltersButton != null)
{
resetFiltersButton.onClick.AddListener(ResetFilters);
resetFiltersButton.onClick.AddListener(OnResetFiltersClicked);
}
}
/// <summary>
/// Called when zone filter dropdown changes
/// Handles changes to the filter dropdowns
/// </summary>
private void OnZoneFilterChanged(int index)
private void OnFilterChanged(int value)
{
ApplyFilters();
}
/// <summary>
/// Called when rarity filter dropdown changes
/// Resets all filters to their default values
/// </summary>
private void OnRarityFilterChanged(int index)
{
ApplyFilters();
}
/// <summary>
/// Reset all filters to default values
/// </summary>
private void ResetFilters()
private void OnResetFiltersClicked()
{
if (zoneFilterDropdown != null)
zoneFilterDropdown.value = 0;
@@ -240,97 +190,68 @@ namespace AppleHills.UI.CardSystem
}
/// <summary>
/// Apply current filter settings to the displayed cards
/// Applies the current filter selections to the displayed cards
/// </summary>
private void ApplyFilters()
{
if (_cardManager == null) return;
// Clear current cards
ClearAlbum();
// Get all cards
List<CardData> allCards = _cardManager.GetAllCollectedCards();
List<CardData> filteredCards = new List<CardData>(allCards);
// Get selected filters
CardZone? selectedZone = null;
CardRarity? selectedRarity = null;
// Apply zone filter
// Get zone filter value
if (zoneFilterDropdown != null && zoneFilterDropdown.value > 0)
{
CardZone selectedZone = (CardZone)(zoneFilterDropdown.value - 1);
filteredCards = filteredCards.FindAll(card => card.Zone == selectedZone);
selectedZone = (CardZone)(zoneFilterDropdown.value - 1);
}
// Apply rarity filter
// Get rarity filter value
if (rarityFilterDropdown != null && rarityFilterDropdown.value > 0)
{
CardRarity selectedRarity = (CardRarity)(rarityFilterDropdown.value - 1);
filteredCards = filteredCards.FindAll(card => card.Rarity == selectedRarity);
selectedRarity = (CardRarity)(rarityFilterDropdown.value - 1);
}
// Update the displayed cards
ClearAlbum();
CreateCardStack(filteredCards);
// Get filtered cards
List<CardData> filteredCards = GetFilteredCards(selectedZone, selectedRarity);
// Create card UI elements for the filtered cards
DisplayCards(filteredCards);
Logging.Debug($"[AlbumViewPage] Applied filters. Showing {filteredCards.Count} cards.");
}
// Override for transition animations
protected override void DoTransitionIn(System.Action onComplete)
/// <summary>
/// Gets cards filtered by zone and/or rarity
/// </summary>
private List<CardData> GetFilteredCards(CardZone? zone, CardRarity? rarity)
{
// Reset the canvas group
if (canvasGroup != null)
List<CardData> result;
// Get all collected cards
if (zone == null && rarity == null)
{
canvasGroup.alpha = 0f;
Tween.Value(0f, 1f, (value) => canvasGroup.alpha = value, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete);
// No filters, return all cards
result = _cardManager.GetAllCollectedCards();
}
else if (zone != null && rarity != null)
{
// Both filters, get cards by zone and rarity
result = _cardManager.GetCardsByZoneAndRarity(zone.Value, rarity.Value);
}
else if (zone != null)
{
// Only zone filter
result = _cardManager.GetCardsByZone(zone.Value);
}
else
{
// Simple scale animation if no canvas group
transform.localScale = Vector3.zero;
Tween.LocalScale(transform, Vector3.one, transitionDuration, 0f, Tween.EaseOutBack, Tween.LoopType.None, null, onComplete);
// Only rarity filter
result = _cardManager.GetCardsByRarity(rarity.Value);
}
}
protected override void DoTransitionOut(System.Action onComplete)
{
// Simple fade animation
if (canvasGroup != null)
{
Tween.Value(canvasGroup.alpha, 0f, (value) => canvasGroup.alpha = value, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete);
}
else
{
Tween.LocalScale(transform, Vector3.zero, transitionDuration, 0f, Tween.EaseInBack, Tween.LoopType.None, null, onComplete);
}
}
private void OnDestroy()
{
// Clean up filter listeners
if (zoneFilterDropdown != null)
zoneFilterDropdown.onValueChanged.RemoveListener(OnZoneFilterChanged);
if (rarityFilterDropdown != null)
rarityFilterDropdown.onValueChanged.RemoveListener(OnRarityFilterChanged);
if (resetFiltersButton != null)
resetFiltersButton.onClick.RemoveListener(ResetFilters);
// Clean up back button listener
if (backButton != null)
backButton.onClick.RemoveListener(OnBackButtonClicked);
// Clean up card listeners
foreach (var card in _displayedCards)
{
if (card != null)
{
// Unsubscribe from card events
card.OnCardClicked -= OnCardClicked;
// Remove button listeners
Button cardButton = card.GetComponent<Button>();
if (cardButton != null)
{
cardButton.onClick.RemoveAllListeners();
}
}
}
return result;
}
/// <summary>
@@ -345,5 +266,66 @@ namespace AppleHills.UI.CardSystem
pageController.PopPage();
}
}
protected override void DoTransitionIn(System.Action onComplete)
{
// Simple fade in animation
if (canvasGroup != null)
{
canvasGroup.alpha = 0f;
Tween.Value(0f, 1f, (value) => canvasGroup.alpha = value, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete);
}
else
{
// Fallback if no CanvasGroup
onComplete?.Invoke();
}
}
protected override void DoTransitionOut(System.Action onComplete)
{
// Simple fade out animation
if (canvasGroup != null)
{
Tween.Value(canvasGroup.alpha, 0f, (value) => canvasGroup.alpha = value, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete);
}
else
{
// Fallback if no CanvasGroup
onComplete?.Invoke();
}
}
private void OnDestroy()
{
// Clean up button listeners
if (backButton != null)
{
backButton.onClick.RemoveListener(OnBackButtonClicked);
}
if (zoneFilterDropdown != null)
{
zoneFilterDropdown.onValueChanged.RemoveListener(OnFilterChanged);
}
if (rarityFilterDropdown != null)
{
rarityFilterDropdown.onValueChanged.RemoveListener(OnFilterChanged);
}
if (resetFiltersButton != null)
{
resetFiltersButton.onClick.RemoveListener(OnResetFiltersClicked);
}
}
private void OnEnable()
{
if (_cardManager == null)
{
_cardManager = CardSystemManager.Instance;
}
}
}
}

View File

@@ -17,9 +17,8 @@ namespace AppleHills.UI.CardSystem
{
[Header("UI Elements")]
[SerializeField] private GameObject boosterPackObject;
[SerializeField] private RectTransform cardRevealContainer; // This should have a HorizontalLayoutGroup component
[SerializeField] private RectTransform cardRevealContainer; // This should have a HorizontalLayoutGroup component with pre-populated card backs
[SerializeField] private GameObject cardPrefab;
[SerializeField] private GameObject cardBackPrefab;
[SerializeField] private Button openBoosterButton;
[SerializeField] private Button continueButton;
[SerializeField] private CanvasGroup canvasGroup;
@@ -45,7 +44,7 @@ namespace AppleHills.UI.CardSystem
private OpeningState _currentState = OpeningState.BoosterReady;
private List<CardUIElement> _revealedCards = new List<CardUIElement>();
private List<GameObject> _cardBacks = new List<GameObject>();
private List<Button> _cardBackButtons = new List<Button>();
private List<CardData> _boosterCards = new List<CardData>();
private int _revealedCardCount = 0;
private CardSystemManager _cardManager;
@@ -80,6 +79,47 @@ namespace AppleHills.UI.CardSystem
canvasGroup = GetComponent<CanvasGroup>();
if (canvasGroup == null)
canvasGroup = gameObject.AddComponent<CanvasGroup>();
// Cache card back buttons from container
CacheCardBackButtons();
// Initially hide all card backs
HideAllCardBacks();
}
/// <summary>
/// Cache all card back buttons from the container
/// </summary>
private void CacheCardBackButtons()
{
_cardBackButtons.Clear();
if (cardRevealContainer != null)
{
// Get all buttons in the container (these are our card backs)
Button[] buttonsInContainer = cardRevealContainer.GetComponentsInChildren<Button>(true);
_cardBackButtons.AddRange(buttonsInContainer);
Debug.Log($"[BoosterOpeningPage] Found {_cardBackButtons.Count} card back buttons in container");
}
else
{
Debug.LogError("[BoosterOpeningPage] Card reveal container is null, can't find card backs!");
}
}
/// <summary>
/// Hides all card backs in the container
/// </summary>
private void HideAllCardBacks()
{
foreach (var cardBack in _cardBackButtons)
{
if (cardBack != null && cardBack.gameObject != null)
{
cardBack.gameObject.SetActive(false);
}
}
}
private void OnDestroy()
@@ -148,22 +188,31 @@ namespace AppleHills.UI.CardSystem
}
_revealedCards.Clear();
// Clear card backs
foreach (var cardBack in _cardBacks)
// Re-cache card backs in case they changed
CacheCardBackButtons();
// Reset all card backs - both visibility and scale
foreach (var cardBack in _cardBackButtons)
{
if (cardBack != null)
Destroy(cardBack);
if (cardBack != null && cardBack.gameObject != null)
{
cardBack.gameObject.SetActive(false);
cardBack.transform.localScale = Vector3.one; // Reset scale
cardBack.transform.localRotation = Quaternion.identity; // Reset rotation
}
}
_cardBacks.Clear();
// Reset state
_currentState = OpeningState.BoosterReady;
_revealedCardCount = 0;
_boosterCards.Clear();
// Show booster pack, show open button, hide continue button
if (boosterPackObject != null)
{
boosterPackObject.SetActive(true);
boosterPackObject.transform.localScale = Vector3.one; // Reset scale
boosterPackObject.transform.localRotation = Quaternion.identity; // Reset rotation
}
if (openBoosterButton != null)
@@ -174,6 +223,7 @@ namespace AppleHills.UI.CardSystem
if (continueButton != null)
{
continueButton.gameObject.SetActive(false);
continueButton.transform.localScale = Vector3.one; // Reset scale
}
// Make back button visible
@@ -181,6 +231,8 @@ namespace AppleHills.UI.CardSystem
{
backButton.gameObject.SetActive(true);
}
Debug.Log("[BoosterOpeningPage] State reset complete, all scales and rotations reset to defaults");
}
/// <summary>
@@ -229,32 +281,46 @@ namespace AppleHills.UI.CardSystem
// Wait a short delay before showing card backs
yield return new WaitForSeconds(0.5f);
// Create card backs for each position (usually 3)
for (int i = 0; i < Mathf.Min(_boosterCards.Count, cardRevealContainer.childCount); i++)
// Check if we have proper container setup
if (cardRevealContainer == null)
{
if (cardBackPrefab == null || cardRevealContainer.GetChild(i) == null) continue;
Debug.LogError("[BoosterOpeningPage] Card reveal container is null!");
yield break;
}
// Instantiate card back object at the correct position
GameObject cardBackObj = Instantiate(cardBackPrefab, cardRevealContainer.GetChild(i));
cardBackObj.transform.localPosition = Vector3.zero;
_cardBacks.Add(cardBackObj);
// Check if we found any card backs
if (_cardBackButtons.Count == 0)
{
Debug.LogError("[BoosterOpeningPage] No card back buttons found in container!");
yield break;
}
// Determine how many cards to show based on the booster cards and available card backs
int cardsToShow = Mathf.Min(_boosterCards.Count, _cardBackButtons.Count);
// Activate and animate the card backs
for (int i = 0; i < cardsToShow; i++)
{
Button cardBack = _cardBackButtons[i];
if (cardBack == null) continue;
GameObject cardBackObj = cardBack.gameObject;
// Ensure the card back is active
cardBackObj.SetActive(true);
// Store the index for later reference when clicked
int cardIndex = i;
// Add click handler to the card back
Button cardBackButton = cardBackObj.GetComponent<Button>();
if (cardBackButton == null)
{
cardBackButton = cardBackObj.AddComponent<Button>();
}
// Configure the button
cardBackButton.onClick.AddListener(() => OnCardBackClicked(cardIndex));
cardBack.onClick.RemoveAllListeners(); // Clear any previous listeners
cardBack.onClick.AddListener(() => OnCardBackClicked(cardIndex));
// Set initial scale to zero for animation
cardBackObj.transform.localScale = Vector3.zero;
Debug.Log($"[BoosterOpeningPage] Card back {i} activated");
// Play reveal animation using Pixelplacement.Tween
Tween.LocalScale(cardBackObj.transform, Vector3.one, 0.5f, 0f, Tween.EaseOutBack);
@@ -264,6 +330,7 @@ namespace AppleHills.UI.CardSystem
// Update state
_currentState = OpeningState.CardBacksVisible;
Debug.Log($"[BoosterOpeningPage] All {cardsToShow} card backs should now be visible");
}
/// <summary>
@@ -271,18 +338,28 @@ namespace AppleHills.UI.CardSystem
/// </summary>
private void OnCardBackClicked(int cardIndex)
{
Logging.Debug($"[BoosterOpeningPage] Card back clicked at index {cardIndex}");
// Only respond to clicks when in the appropriate state
if (_currentState != OpeningState.CardBacksVisible) return;
if (_currentState != OpeningState.CardBacksVisible)
{
Logging.Warning($"[BoosterOpeningPage] Card clicked in wrong state: {_currentState}");
return;
}
// Ensure the index is valid
if (cardIndex < 0 || cardIndex >= _boosterCards.Count || cardIndex >= _cardBacks.Count) return;
if (cardIndex < 0 || cardIndex >= _boosterCards.Count || cardIndex >= _cardBackButtons.Count)
{
Debug.LogError($"[BoosterOpeningPage] Invalid card index: {cardIndex}");
return;
}
// Get the card data and card back
CardData cardData = _boosterCards[cardIndex];
GameObject cardBack = _cardBacks[cardIndex];
Button cardBack = _cardBackButtons[cardIndex];
// Start the reveal animation for this specific card
StartCoroutine(RevealCard(cardIndex, cardData, cardBack));
StartCoroutine(RevealCard(cardIndex, cardData, cardBack.gameObject));
}
/// <summary>
@@ -290,7 +367,8 @@ namespace AppleHills.UI.CardSystem
/// </summary>
private IEnumerator RevealCard(int cardIndex, CardData cardData, GameObject cardBack)
{
if (cardBack == null || cardRevealContainer.GetChild(cardIndex) == null) yield break;
if (cardBack == null)
yield break;
// Start flip animation
Transform cardBackTransform = cardBack.transform;
@@ -301,46 +379,96 @@ namespace AppleHills.UI.CardSystem
// Wait for half the flip duration
yield return new WaitForSeconds(flipAnimationDuration * 0.5f);
// Step 2: Remove the card back and create the actual card
Destroy(cardBack);
_cardBacks[cardIndex] = null;
// Step 2: Hide the card back and show the actual card
cardBack.SetActive(false);
// Create the actual card at the same position
GameObject cardObj = Instantiate(cardPrefab, cardRevealContainer.GetChild(cardIndex));
cardObj.transform.localPosition = Vector3.zero;
cardObj.transform.localRotation = Quaternion.Euler(0, 90, 0); // Start at 90 degrees
// Set up the card data
CardUIElement cardUI = cardObj.GetComponent<CardUIElement>();
if (cardUI != null)
// Instantiate the card prefab at the same position
if (cardPrefab != null)
{
cardUI.SetupCard(cardData);
_revealedCards.Add(cardUI);
}
// Instantiate the card in the same parent as the card back and at the same position
GameObject cardObj = Instantiate(cardPrefab, cardBack.transform.parent);
cardObj.transform.SetSiblingIndex(cardBackTransform.GetSiblingIndex()); // Keep the same order in hierarchy
cardObj.transform.position = cardBackTransform.position; // Same world position
// Step 3: Complete the flip animation
Tween.LocalRotation(cardObj.transform, Vector3.zero, flipAnimationDuration * 0.5f, 0);
// Set initial rotation to continue the flip animation
cardObj.transform.localRotation = Quaternion.Euler(0, 90, 0);
// Increment the revealed card count
_revealedCardCount++;
// If all cards have been revealed, show the continue button
if (_revealedCardCount >= _boosterCards.Count)
{
_currentState = OpeningState.CardsRevealed;
if (continueButton != null)
// Configure the card UI with the card data
CardUIElement cardUI = cardObj.GetComponent<CardUIElement>();
if (cardUI != null)
{
continueButton.gameObject.SetActive(true);
cardUI.SetupCard(cardData);
_revealedCards.Add(cardUI);
// Animate button appearance
continueButton.transform.localScale = Vector3.zero;
Tween.LocalScale(continueButton.transform, Vector3.one, 0.3f, 0f, Tween.EaseOutBack);
// Play special effects based on card rarity
PlayRevealEffect(cardObj, cardData.Rarity);
}
// Step 3: Finish the flip animation (from 90 degrees to 0)
Tween.LocalRotation(cardObj.transform, Vector3.zero, flipAnimationDuration * 0.5f, 0);
// Increment counter of revealed cards
_revealedCardCount++;
// Update state if all cards are revealed
if (_revealedCardCount >= _boosterCards.Count)
{
_currentState = OpeningState.CardsRevealed;
// Show continue button after a short delay
StartCoroutine(ShowContinueButton());
}
}
}
/// <summary>
/// Handles click on the continue button after cards are revealed
/// Plays reveal effect for a card based on its rarity
/// </summary>
private void PlayRevealEffect(GameObject cardObject, CardRarity rarity)
{
// Add visual effect based on rarity
if (rarity >= CardRarity.Rare)
{
// For rare cards and above, add a particle effect
var particleSystem = cardObject.GetComponentInChildren<ParticleSystem>();
if (particleSystem != null)
{
particleSystem.Play();
}
// Scale up and down for emphasis
Transform cardTransform = cardObject.transform;
Vector3 originalScale = cardTransform.localScale;
// Sequence: Scale up slightly, then back to normal
Tween.LocalScale(cardTransform, originalScale * 1.2f, 0.2f, 0.1f, Tween.EaseOutBack);
Tween.LocalScale(cardTransform, originalScale, 0.15f, 0.3f, Tween.EaseIn);
// Play sound effect based on rarity (if available)
// This would require audio source components to be set up
}
}
/// <summary>
/// Shows the continue button after all cards are revealed
/// </summary>
private IEnumerator ShowContinueButton()
{
// Wait for a moment to let the user see all cards
yield return new WaitForSeconds(1.0f);
if (continueButton != null)
{
// Show the continue button with a nice animation
continueButton.gameObject.SetActive(true);
continueButton.transform.localScale = Vector3.zero;
Tween.LocalScale(continueButton.transform, Vector3.one, 0.3f, 0f, Tween.EaseOutBack);
}
}
/// <summary>
/// Handles click on the continue button
/// </summary>
private void OnContinueClicked()
{
@@ -348,63 +476,75 @@ namespace AppleHills.UI.CardSystem
_currentState = OpeningState.MovingToBackpack;
// Hide continue button
if (continueButton != null)
{
continueButton.gameObject.SetActive(false);
}
// Start moving cards to backpack animation
// Hide back button during transition
if (backButton != null)
{
backButton.gameObject.SetActive(false);
}
// Start animation to move cards to backpack
_moveToBackpackCoroutine = StartCoroutine(MoveCardsToBackpack());
}
/// <summary>
/// Animates cards moving to the backpack
/// Animates cards moving to the backpack icon
/// </summary>
private IEnumerator MoveCardsToBackpack()
{
// Use the backpackIcon from CardAlbumUI as the target
Vector3 targetPosition;
if (_cardAlbumUI != null && _cardAlbumUI.transform.Find("BackpackIcon") != null)
// Find the backpack icon position if available
Transform backpackTransform = null;
if (_cardAlbumUI != null && _cardAlbumUI.BackpackIcon != null)
{
// Get the world position of the backpack icon
targetPosition = _cardAlbumUI.transform.Find("BackpackIcon").position;
}
else
{
// Fallback to a default position (lower-right corner)
targetPosition = new Vector3(Screen.width * 0.9f, Screen.height * 0.1f, 0f);
Logging.Warning("[BoosterOpeningPage] Couldn't find backpack icon, using default position.");
backpackTransform = _cardAlbumUI.BackpackIcon.transform;
}
// Move each card to backpack with animation
foreach (var cardUI in _revealedCards)
if (backpackTransform == null)
{
if (cardUI != null)
// If no backpack is found, just return to the menu
UIPageController.Instance.PopPage();
yield break;
}
// Move each card to the backpack with slight delay between cards
for (int i = 0; i < _revealedCards.Count; i++)
{
CardUIElement card = _revealedCards[i];
if (card != null)
{
// Call card's move to backpack animation
cardUI.OnMoveToBackpackAnimation();
// Get the world position of the backpack
Vector3 backpackWorldPos = backpackTransform.position;
// Animate movement to backpack
Tween.Position(cardUI.transform, targetPosition, 0.5f, 0f, Tween.EaseInBack);
Tween.LocalScale(cardUI.transform, Vector3.zero, 0.5f, 0f, Tween.EaseInBack);
// Convert to local space of the card's parent for Tween
Vector3 targetPos = card.transform.parent.InverseTransformPoint(backpackWorldPos);
// Wait for delay between cards
yield return new WaitForSeconds(0.2f);
// Start the move animation
Tween.LocalPosition(card.transform, targetPos, 0.5f, cardMoveToBackpackDelay * i);
Tween.LocalScale(card.transform, Vector3.zero, 0.5f, cardMoveToBackpackDelay * i);
}
// Wait before starting the next card
yield return new WaitForSeconds(cardMoveToBackpackDelay);
}
// Wait for final animation
// Wait a bit after the last card
yield return new WaitForSeconds(0.5f);
// Update state to completed
// Update state
_currentState = OpeningState.Completed;
// Return to previous page
// Return to the menu
UIPageController.Instance.PopPage();
}
// Override for transition animations
/// <summary>
/// Override for transition in animation using Pixelplacement.Tween
/// </summary>
protected override void DoTransitionIn(System.Action onComplete)
{
// Simple fade in animation
@@ -415,10 +555,14 @@ namespace AppleHills.UI.CardSystem
}
else
{
// Fallback if no CanvasGroup
onComplete?.Invoke();
}
}
/// <summary>
/// Override for transition out animation using Pixelplacement.Tween
/// </summary>
protected override void DoTransitionOut(System.Action onComplete)
{
// Simple fade out animation
@@ -428,8 +572,29 @@ namespace AppleHills.UI.CardSystem
}
else
{
// Fallback if no CanvasGroup
onComplete?.Invoke();
}
}
/// <summary>
/// OnEnable override to ensure proper initialization
/// </summary>
private void OnEnable()
{
if (_cardManager == null)
{
_cardManager = CardSystemManager.Instance;
}
if (_cardAlbumUI == null)
{
_cardAlbumUI = FindObjectOfType<CardAlbumUI>();
}
// Re-cache card backs in case they changed while disabled
CacheCardBackButtons();
}
}
}

View File

@@ -154,7 +154,12 @@ namespace AppleHills.UI.CardSystem
if (_hasUnseenCards)
{
_hasUnseenCards = false;
UpdateBoosterVisibility();
}
// Hide the backpack button when entering menu
if (backpackButton != null)
{
backpackButton.gameObject.SetActive(false);
}
}
else if (_pageController.CurrentPage == mainMenuPage)
@@ -176,8 +181,8 @@ namespace AppleHills.UI.CardSystem
}
else
{
if (backpackIcon != null)
backpackIcon.SetActive(false);
if (backpackButton != null)
backpackButton.gameObject.SetActive(false);
}
// Update menu if it's the main menu page
@@ -193,11 +198,19 @@ namespace AppleHills.UI.CardSystem
/// </summary>
private void ShowOnlyBackpackIcon()
{
if (backpackIcon != null)
backpackIcon.SetActive(true);
if (backpackButton != null)
{
backpackButton.gameObject.SetActive(true);
// Update booster notification visibility
UpdateBoosterVisibility();
// Update notification visibility based on booster count
bool hasBooters = _cardManager != null && _cardManager.GetBoosterPackCount() > 0;
// Show notification dot if there are boosters or unseen cards
if (boosterNotificationDot != null)
{
boosterNotificationDot.gameObject.SetActive(hasBooters || _hasUnseenCards);
}
}
}
/// <summary>

View File

@@ -0,0 +1,159 @@
# Card System Integration and Testing Guide
## Overview
This document outlines the integration between the data and UI layers of the Apple Hills card collection system, as well as the testing tools available for development purposes.
## Architecture Summary
The card system follows a clean separation of concerns:
1. **Data Layer** (Assets/Scripts/Data/CardSystem/)
- `CardSystemManager`: Singleton for managing card data, booster packs, and collection
- `CardInventory`: Player's collection of cards and booster packs
- `CardData`: Runtime instance of a collected card
- `CardDefinition`: ScriptableObject template defining card properties
- `CardVisualConfig`: Visual settings for cards based on rarity/zone
2. **UI Layer** (Assets/Scripts/UI/CardSystem/)
- `CardAlbumUI`: Main controller for the card UI system
- `UIPageController`: Stack-based navigation system
- `UIPage`: Base class for UI pages with transition animations
- Page Components:
- `CardMenuPage`: Main menu for the card system
- `AlbumViewPage`: Grid display of collected cards with filtering
- `BoosterOpeningPage`: Interactive card reveal experience
- `CardUIElement`: Individual card visual representation
- `BoosterNotificationDot`: UI element showing booster pack counts
## Integration Points
### Initialization Process
1. `CardSystemManager` initializes during the bootstrap process using `BootCompletionService`
2. UI components register with `BootCompletionService.RegisterInitAction()` for post-boot initialization
3. UI components access card data through `CardSystemManager.Instance`
### Data Flow
1. **Card Collection**:
- `CardSystemManager` manages the player's `CardInventory`
- Cards are added via `AddCardToInventory()`
- Card collection triggers `OnCardCollected` event
2. **Booster Packs**:
- Added via `CardSystemManager.AddBoosterPack()`
- Opened via `CardSystemManager.OpenBoosterPack()`
- Booster count changes trigger `OnBoosterCountChanged` event
- Opening boosters triggers `OnBoosterOpened` event
3. **Card Display**:
- `CardUIElement` displays a card using `SetupCard(cardData)`
- `AlbumViewPage` displays cards in a grid with filtering options
- `BoosterOpeningPage` handles interactive card reveals
### Event System
Key events that connect data and UI layers:
- `OnBoosterCountChanged`: Triggered when booster count changes
- `OnBoosterOpened`: Triggered when a booster is opened
- `OnCardCollected`: Triggered when a new card is added to collection
- `OnCardRarityUpgraded`: Triggered when duplicates upgrade a card's rarity
## Testing Tool: CardSystemTester
The `CardSystemTester` provides a simple interface for testing the card system without requiring full game integration.
### Features
- Adding booster packs
- Opening the card menu
- Opening booster packs
- Browsing the album view
- Generating random test cards
- Clearing the card collection
### Usage
1. Add `CardSystemTester` component to a GameObject in your test scene
2. Reference the `CardAlbumUI` component
3. Enter Play mode and use the inspector buttons
4. All buttons are disabled in edit mode
### Implementation Notes
```csharp
public class CardSystemTester : MonoBehaviour
{
// Only need reference to CardAlbumUI, the CardSystemManager is accessed via singleton
[SerializeField] private CardAlbumUI cardAlbumUI;
// Other variables for test configuration
[SerializeField] [Range(1, 10)] private int boosterPacksToAdd = 3;
[SerializeField] [Range(1, 100)] private int cardsToGenerate = 10;
// All operations use CardSystemManager.Instance
public void AddBoosterPacks() {
CardSystemManager.Instance.AddBoosterPack(boosterPacksToAdd);
// Other operations...
}
// Uses CardAlbumUI to simulate UI interactions
public void SimulateBackpackClick() {
// Trigger the backpack button's onClick event
}
// Additional test methods...
}
```
### Test Scene Setup
1. Create a new scene or use an existing test scene
2. Add a Canvas with proper UI configuration
3. Add the CardSystem prefab (containing CardAlbumUI)
4. Add the CardSystemTester component
5. Make sure you have card definitions configured
## Current Implementation Status
1. **Complete**:
- Core data management through `CardSystemManager`
- Card collection and inventory management
- Basic UI navigation system
- Booster pack opening flow
- Album view with filtering
2. **Added API Methods**:
- `GetAllCardDefinitions()`: Returns list of all card definitions
- `GetCardInventory()`: Returns reference to player's card inventory
- `ClearAllCards()`: Resets the player's collection
- Various utility methods for filtering and statistics
3. **UI Improvements**:
- Simplified card display in album view
- Properly integrated card reveal animations
- Back button functionality for all pages
## Known Issues and Considerations
1. **Performance**: Large collections may require optimization
2. **Save System**: Currently not implemented, needs integration with game save system
3. **Card Definition Loading**: Ensure card definitions are loaded before use
4. **Testing Workflow**: Test specific state scenarios using the CardSystemTester
5. **Animation Timing**: May need adjustment for smoother experience
## Next Steps
1. Implement save/load system for card collection
2. Add collection statistics display
3. Implement rarity-specific effects for card reveals
4. Create more comprehensive test coverage
## Technical References
- Bootstrap system: Use `BootCompletionService.RegisterInitAction(InitializePostBoot)` for initialization
- Data access: Always use `CardSystemManager.Instance` for data access
- Page navigation: Use `UIPageController.Instance.PushPage()` and `PopPage()`
- Card UI: Use `CardUIElement.SetupCard()` to configure card display