Merge branch 'main' of https://homelab.tailf7f81b.ts.net/tschesky/AppleHillsProduction
This commit is contained in:
@@ -40,7 +40,7 @@ RectTransform:
|
||||
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: 200, y: 270}
|
||||
m_SizeDelta: {x: 200, y: 200}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &2127389269465269351
|
||||
MonoBehaviour:
|
||||
@@ -143,6 +143,7 @@ GameObject:
|
||||
- component: {fileID: 581410895551808339}
|
||||
- component: {fileID: 9061673992343081870}
|
||||
- component: {fileID: 2391223799317068879}
|
||||
- component: {fileID: 3335061902473626590}
|
||||
m_Layer: 0
|
||||
m_Name: Visual
|
||||
m_TagString: Untagged
|
||||
@@ -164,10 +165,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 8730990344497138252}
|
||||
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_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 200, y: 200}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &581410895551808339
|
||||
MonoBehaviour:
|
||||
@@ -220,6 +221,20 @@ MonoBehaviour:
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!114 &3335061902473626590
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3963317030246886356}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 86710e43de46f6f4bac7c8e50813a599, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.AspectRatioFitter
|
||||
m_AspectMode: 1
|
||||
m_AspectRatio: 1
|
||||
--- !u!1 &4127399957670380340
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@@ -55,7 +55,6 @@ MonoBehaviour:
|
||||
occupantScale: {x: 1, y: 1, z: 1}
|
||||
scaleTransitionDuration: 0.3
|
||||
boxType: 0
|
||||
boxSprite: {fileID: 0}
|
||||
--- !u!1 &6923066319076554151
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -132,8 +131,8 @@ SpriteRenderer:
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_GlobalIlluminationMeshLod: 0
|
||||
m_SortingLayerID: -1132846201
|
||||
m_SortingLayer: 1
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_Sprite: {fileID: -7843813406500067289, guid: bd1c641e7bfe53145820bb64b08f8fc8, type: 3}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
|
||||
@@ -35,7 +35,7 @@ RectTransform:
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 200, y: 50}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &6535475175108777945
|
||||
CanvasRenderer:
|
||||
@@ -65,7 +65,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: 0000
|
||||
m_text: 'Score: 0'
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 4aca0db6ec111b5418bdc747168f9474, type: 2}
|
||||
m_sharedMaterial: {fileID: -1441574381962284772, guid: 4aca0db6ec111b5418bdc747168f9474, type: 2}
|
||||
@@ -92,15 +92,15 @@ MonoBehaviour:
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 100
|
||||
m_fontSizeBase: 100
|
||||
m_fontSize: 75
|
||||
m_fontSizeBase: 75
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 0
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 1
|
||||
m_HorizontalAlignment: 1
|
||||
m_VerticalAlignment: 256
|
||||
m_HorizontalAlignment: 2
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_wordSpacing: 0
|
||||
@@ -171,7 +171,7 @@ RectTransform:
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 200, y: 50}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &6186147173729892847
|
||||
CanvasRenderer:
|
||||
@@ -201,7 +201,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: 0%
|
||||
m_text: 'Accuracy: 0%'
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 4aca0db6ec111b5418bdc747168f9474, type: 2}
|
||||
m_sharedMaterial: {fileID: -1441574381962284772, guid: 4aca0db6ec111b5418bdc747168f9474, type: 2}
|
||||
@@ -228,15 +228,15 @@ MonoBehaviour:
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 100
|
||||
m_fontSizeBase: 100
|
||||
m_fontSize: 75
|
||||
m_fontSizeBase: 75
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 0
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 1
|
||||
m_HorizontalAlignment: 1
|
||||
m_VerticalAlignment: 256
|
||||
m_HorizontalAlignment: 2
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_wordSpacing: 0
|
||||
@@ -307,10 +307,10 @@ RectTransform:
|
||||
m_Father: {fileID: 707190640386266950}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 150}
|
||||
m_Pivot: {x: 0.5, y: 1}
|
||||
m_SizeDelta: {x: 1200, y: 94}
|
||||
m_Pivot: {x: 0, y: 1}
|
||||
--- !u!114 &3416581373676611538
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -324,19 +324,98 @@ MonoBehaviour:
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.HorizontalLayoutGroup
|
||||
m_Padding:
|
||||
m_Left: 0
|
||||
m_Left: 150
|
||||
m_Right: 0
|
||||
m_Top: 0
|
||||
m_Top: 50
|
||||
m_Bottom: 0
|
||||
m_ChildAlignment: 4
|
||||
m_Spacing: 150
|
||||
m_ChildForceExpandWidth: 0
|
||||
m_Spacing: 25
|
||||
m_ChildForceExpandWidth: 1
|
||||
m_ChildForceExpandHeight: 1
|
||||
m_ChildControlWidth: 1
|
||||
m_ChildControlHeight: 1
|
||||
m_ChildScaleWidth: 0
|
||||
m_ChildScaleHeight: 0
|
||||
m_ReverseArrangement: 0
|
||||
--- !u!1 &3087548688493085045
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3245381937614859990}
|
||||
- component: {fileID: 1428588550372337553}
|
||||
- component: {fileID: 7088646692690443534}
|
||||
m_Layer: 5
|
||||
m_Name: HealthBar
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &3245381937614859990
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3087548688493085045}
|
||||
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:
|
||||
- {fileID: 3256183770156166523}
|
||||
m_Father: {fileID: 707190640386266950}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 1, y: 1}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 559.7, y: 150}
|
||||
m_Pivot: {x: 1, y: 1}
|
||||
--- !u!114 &1428588550372337553
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3087548688493085045}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.HorizontalLayoutGroup
|
||||
m_Padding:
|
||||
m_Left: 0
|
||||
m_Right: 50
|
||||
m_Top: 50
|
||||
m_Bottom: 0
|
||||
m_ChildAlignment: 2
|
||||
m_Spacing: 25
|
||||
m_ChildForceExpandWidth: 0
|
||||
m_ChildForceExpandHeight: 0
|
||||
m_ChildControlWidth: 0
|
||||
m_ChildControlHeight: 0
|
||||
m_ChildScaleWidth: 0
|
||||
m_ChildScaleHeight: 0
|
||||
m_ReverseArrangement: 0
|
||||
--- !u!114 &7088646692690443534
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3087548688493085045}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: e8bcb252540442e593cc6467c518ff75, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: AppleHillsScripts::Minigames.CardSorting.UI.LivesDisplay
|
||||
layoutGroup: {fileID: 1428588550372337553}
|
||||
animationDuration: 0.8
|
||||
scaleMultiplier: 1.5
|
||||
--- !u!1 &5517642253100401386
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -372,7 +451,7 @@ RectTransform:
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 200, y: 50}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &6941393494789352809
|
||||
CanvasRenderer:
|
||||
@@ -429,15 +508,15 @@ MonoBehaviour:
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 100
|
||||
m_fontSizeBase: 100
|
||||
m_fontSize: 75
|
||||
m_fontSizeBase: 75
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 0
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 1
|
||||
m_HorizontalAlignment: 1
|
||||
m_VerticalAlignment: 256
|
||||
m_HorizontalAlignment: 2
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_wordSpacing: 0
|
||||
@@ -473,6 +552,81 @@ MonoBehaviour:
|
||||
m_hasFontAssetChanged: 0
|
||||
m_baseMaterial: {fileID: 0}
|
||||
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||
--- !u!1 &5874089027455915553
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3256183770156166523}
|
||||
- component: {fileID: 8780034033757607403}
|
||||
- component: {fileID: 5667348465997950205}
|
||||
m_Layer: 5
|
||||
m_Name: Image
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &3256183770156166523
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5874089027455915553}
|
||||
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: 3245381937614859990}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 100, y: 100}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &8780034033757607403
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5874089027455915553}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &5667348465997950205
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5874089027455915553}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 6741082507358000137, guid: 2406a20d35d3e8946b1e3f83ecd269c2, type: 3}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!1 &7537653696112211670
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -503,6 +657,7 @@ RectTransform:
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 8952171418799244803}
|
||||
- {fileID: 3245381937614859990}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
|
||||
@@ -1059,8 +1059,8 @@ RectTransform:
|
||||
- {fileID: 5196078022198364906}
|
||||
m_Father: {fileID: 5616388183832902964}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.2, y: 0.12}
|
||||
m_AnchorMax: {x: 0.9, y: 0.85}
|
||||
m_AnchorMin: {x: 0.15, y: 0.15}
|
||||
m_AnchorMax: {x: 0.9, y: 0.8}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
@@ -1083,7 +1083,7 @@ MonoBehaviour:
|
||||
m_Bottom: 0
|
||||
m_ChildAlignment: 0
|
||||
m_Spacing: 10
|
||||
m_ChildForceExpandWidth: 1
|
||||
m_ChildForceExpandWidth: 0
|
||||
m_ChildForceExpandHeight: 0
|
||||
m_ChildControlWidth: 1
|
||||
m_ChildControlHeight: 0
|
||||
|
||||
@@ -160,6 +160,7 @@ MonoBehaviour:
|
||||
- {fileID: 254614580}
|
||||
- {fileID: 222800744}
|
||||
impulseSource: {fileID: 90351797}
|
||||
livesDisplay: {fileID: 934831599}
|
||||
--- !u!4 &90351796
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -1025,6 +1026,134 @@ MonoBehaviour:
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
CustomBlends: {fileID: 0}
|
||||
--- !u!114 &934831599 stripped
|
||||
MonoBehaviour:
|
||||
m_CorrespondingSourceObject: {fileID: 7088646692690443534, guid: acc5a752dcc18834b984fe78b6926dad, type: 3}
|
||||
m_PrefabInstance: {fileID: 384779534298969466}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: e8bcb252540442e593cc6467c518ff75, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: AppleHillsScripts::Minigames.CardSorting.UI.LivesDisplay
|
||||
--- !u!1 &1018422025
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1018422026}
|
||||
- component: {fileID: 1018422030}
|
||||
- component: {fileID: 1018422029}
|
||||
- component: {fileID: 1018422028}
|
||||
- component: {fileID: 1018422027}
|
||||
m_Layer: 0
|
||||
m_Name: CanvasHitbox
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1018422026
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1018422025}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 0.010527978, y: 0.04, z: 0.08}
|
||||
m_ConstrainProportionsScale: 1
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1020017635}
|
||||
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: 800, y: 113.2}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1018422027
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1018422025}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 0.003921569}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 0}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!222 &1018422028
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1018422025}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &1018422029
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1018422025}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.GraphicRaycaster
|
||||
m_IgnoreReversedGraphics: 1
|
||||
m_BlockingObjects: 0
|
||||
m_BlockingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
--- !u!223 &1018422030
|
||||
Canvas:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1018422025}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 3
|
||||
m_RenderMode: 2
|
||||
m_Camera: {fileID: 0}
|
||||
m_PlaneDistance: 100
|
||||
m_PixelPerfect: 0
|
||||
m_ReceivesEvents: 1
|
||||
m_OverrideSorting: 0
|
||||
m_OverridePixelPerfect: 0
|
||||
m_SortingBucketNormalizedSize: 0
|
||||
m_VertexColorAlwaysGammaSpace: 0
|
||||
m_AdditionalShaderChannelsFlag: 0
|
||||
m_UpdateRectTransformForStandalone: 0
|
||||
m_SortingLayerID: 0
|
||||
m_SortingOrder: 0
|
||||
m_TargetDisplay: 0
|
||||
--- !u!1 &1020017633
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -1034,6 +1163,7 @@ GameObject:
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1020017635}
|
||||
- component: {fileID: 1020017636}
|
||||
- component: {fileID: 1020017634}
|
||||
m_Layer: 0
|
||||
m_Name: ConveyorBeltVisual
|
||||
@@ -1086,8 +1216,8 @@ SpriteRenderer:
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_GlobalIlluminationMeshLod: 0
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingLayerID: 622133659
|
||||
m_SortingLayer: -1
|
||||
m_SortingOrder: 0
|
||||
m_Sprite: {fileID: -7171755534009967257, guid: b382c7219ff059c499bdeba018f5a93f, type: 3}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
@@ -1109,15 +1239,36 @@ Transform:
|
||||
m_GameObject: {fileID: 1020017633}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: -10.39, z: 0}
|
||||
m_LocalScale: {x: 7.5988007, y: 1.4, z: 1}
|
||||
m_LocalPosition: {x: 0, y: -10.08, z: 0}
|
||||
m_LocalScale: {x: 7.5988007, y: 2, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 1122663370}
|
||||
- {fileID: 1595343397}
|
||||
- {fileID: 1992305141}
|
||||
- {fileID: 1018422026}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &1020017636
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1020017633}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 9304d17587314133a4d8d1e582cfbf81, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: AppleHillsScripts::Minigames.CardSorting.Core.ConveyorBeltSlot
|
||||
slotIndex: -1
|
||||
isLocked: 0
|
||||
hideImageOnPlay: 0
|
||||
filterByType: 0
|
||||
allowedTypeNames: []
|
||||
occupantSizeMode: 0
|
||||
occupantScale: {x: 1, y: 1, z: 1}
|
||||
scaleTransitionDuration: 0.3
|
||||
--- !u!1 &1122663369
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -1438,34 +1589,6 @@ PrefabInstance:
|
||||
propertyPath: m_LocalEulerAnglesHint.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1653089319504497253, guid: acc5a752dcc18834b984fe78b6926dad, type: 3}
|
||||
propertyPath: m_fontSize
|
||||
value: 100
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1653089319504497253, guid: acc5a752dcc18834b984fe78b6926dad, type: 3}
|
||||
propertyPath: m_enableAutoSizing
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1653089319504497253, guid: acc5a752dcc18834b984fe78b6926dad, type: 3}
|
||||
propertyPath: m_VerticalAlignment
|
||||
value: 512
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1653089319504497253, guid: acc5a752dcc18834b984fe78b6926dad, type: 3}
|
||||
propertyPath: m_HorizontalAlignment
|
||||
value: 2
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1929638711813240478, guid: acc5a752dcc18834b984fe78b6926dad, type: 3}
|
||||
propertyPath: m_text
|
||||
value: 'Accuracy: 0%'
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1929638711813240478, guid: acc5a752dcc18834b984fe78b6926dad, type: 3}
|
||||
propertyPath: m_VerticalAlignment
|
||||
value: 512
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1929638711813240478, guid: acc5a752dcc18834b984fe78b6926dad, type: 3}
|
||||
propertyPath: m_HorizontalAlignment
|
||||
value: 2
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 3193587684358315289, guid: acc5a752dcc18834b984fe78b6926dad, type: 3}
|
||||
propertyPath: m_AnchorMax.y
|
||||
value: 0
|
||||
@@ -1476,7 +1599,7 @@ PrefabInstance:
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 3193587684358315289, guid: acc5a752dcc18834b984fe78b6926dad, type: 3}
|
||||
propertyPath: m_SizeDelta.x
|
||||
value: 400
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 3193587684358315289, guid: acc5a752dcc18834b984fe78b6926dad, type: 3}
|
||||
propertyPath: m_SizeDelta.y
|
||||
@@ -1490,25 +1613,21 @@ PrefabInstance:
|
||||
propertyPath: m_AnchoredPosition.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 3416581373676611538, guid: acc5a752dcc18834b984fe78b6926dad, type: 3}
|
||||
propertyPath: m_ChildControlHeight
|
||||
value: 1
|
||||
- target: {fileID: 3256183770156166523, guid: acc5a752dcc18834b984fe78b6926dad, type: 3}
|
||||
propertyPath: m_AnchorMax.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 3416581373676611538, guid: acc5a752dcc18834b984fe78b6926dad, type: 3}
|
||||
propertyPath: m_ChildForceExpandHeight
|
||||
value: 1
|
||||
- target: {fileID: 3256183770156166523, guid: acc5a752dcc18834b984fe78b6926dad, type: 3}
|
||||
propertyPath: m_AnchorMin.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4139981089598238079, guid: acc5a752dcc18834b984fe78b6926dad, type: 3}
|
||||
propertyPath: m_text
|
||||
value: 'Score: 0'
|
||||
- target: {fileID: 3256183770156166523, guid: acc5a752dcc18834b984fe78b6926dad, type: 3}
|
||||
propertyPath: m_AnchoredPosition.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4139981089598238079, guid: acc5a752dcc18834b984fe78b6926dad, type: 3}
|
||||
propertyPath: m_VerticalAlignment
|
||||
value: 512
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4139981089598238079, guid: acc5a752dcc18834b984fe78b6926dad, type: 3}
|
||||
propertyPath: m_HorizontalAlignment
|
||||
value: 2
|
||||
- target: {fileID: 3256183770156166523, guid: acc5a752dcc18834b984fe78b6926dad, type: 3}
|
||||
propertyPath: m_AnchoredPosition.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4881154979794857029, guid: acc5a752dcc18834b984fe78b6926dad, type: 3}
|
||||
propertyPath: m_AnchorMax.y
|
||||
@@ -1518,6 +1637,10 @@ PrefabInstance:
|
||||
propertyPath: m_AnchorMin.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4881154979794857029, guid: acc5a752dcc18834b984fe78b6926dad, type: 3}
|
||||
propertyPath: m_SizeDelta.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4881154979794857029, guid: acc5a752dcc18834b984fe78b6926dad, type: 3}
|
||||
propertyPath: m_SizeDelta.y
|
||||
value: 0
|
||||
@@ -1544,7 +1667,7 @@ PrefabInstance:
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 8294328820939081367, guid: acc5a752dcc18834b984fe78b6926dad, type: 3}
|
||||
propertyPath: m_SizeDelta.x
|
||||
value: 600
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 8294328820939081367, guid: acc5a752dcc18834b984fe78b6926dad, type: 3}
|
||||
propertyPath: m_SizeDelta.y
|
||||
@@ -2013,11 +2136,11 @@ PrefabInstance:
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 9145507277845748449, guid: c8846509eba59f84aa047197fe02375b, type: 3}
|
||||
propertyPath: m_SizeDelta.x
|
||||
value: 1000
|
||||
value: 1200
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 9145507277845748449, guid: c8846509eba59f84aa047197fe02375b, type: 3}
|
||||
propertyPath: m_SizeDelta.y
|
||||
value: 1000
|
||||
value: 1200
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 9145507277845748449, guid: c8846509eba59f84aa047197fe02375b, type: 3}
|
||||
propertyPath: m_LocalPosition.x
|
||||
|
||||
@@ -55,10 +55,24 @@ namespace Core.Settings
|
||||
[Tooltip("Points deducted when item falls off belt")]
|
||||
[SerializeField] private int missedItemPenalty = -3;
|
||||
|
||||
[Header("Lives")]
|
||||
[Tooltip("Maximum number of lives player has")]
|
||||
[SerializeField] private int maxLives = 3;
|
||||
|
||||
[Header("Rewards")]
|
||||
[Tooltip("Booster packs awarded per correct sort")]
|
||||
[SerializeField] private int boosterPacksPerCorrectItem = 1;
|
||||
|
||||
[Header("Visual")]
|
||||
[Tooltip("Size of spawned cards (width, height)")]
|
||||
[SerializeField] private Vector2 cardSize = new Vector2(100f, 140f);
|
||||
|
||||
[Tooltip("Random offset range for spawn distance X (min, max). Range: -10 to 10")]
|
||||
[SerializeField] private Vector2 spawnOffsetX = new Vector2(-5f, 5f);
|
||||
|
||||
[Tooltip("Random offset range for spawn Y position (min, max). Range: -10 to 10")]
|
||||
[SerializeField] private Vector2 spawnOffsetY = new Vector2(-10f, 10f);
|
||||
|
||||
// Interface implementation
|
||||
public float GameDuration => gameDuration;
|
||||
|
||||
@@ -75,7 +89,11 @@ namespace Core.Settings
|
||||
public int CorrectSortPoints => correctSortPoints;
|
||||
public int IncorrectSortPenalty => incorrectSortPenalty;
|
||||
public int MissedItemPenalty => missedItemPenalty;
|
||||
public int MaxLives => maxLives;
|
||||
public int BoosterPacksPerCorrectItem => boosterPacksPerCorrectItem;
|
||||
public Vector2 CardSize => cardSize;
|
||||
public Vector2 SpawnOffsetX => spawnOffsetX;
|
||||
public Vector2 SpawnOffsetY => spawnOffsetY;
|
||||
|
||||
public override void OnValidate()
|
||||
{
|
||||
@@ -86,6 +104,15 @@ namespace Core.Settings
|
||||
maxBeltSpeed = Mathf.Max(initialBeltSpeed, maxBeltSpeed);
|
||||
correctSortPoints = Mathf.Max(0, correctSortPoints);
|
||||
boosterPacksPerCorrectItem = Mathf.Max(0, boosterPacksPerCorrectItem);
|
||||
maxLives = Mathf.Max(1, maxLives);
|
||||
cardSize.x = Mathf.Max(1f, cardSize.x);
|
||||
cardSize.y = Mathf.Max(1f, cardSize.y);
|
||||
|
||||
// Clamp spawn offsets between -10 and 10
|
||||
spawnOffsetX.x = Mathf.Clamp(spawnOffsetX.x, -10f, 10f);
|
||||
spawnOffsetX.y = Mathf.Clamp(spawnOffsetX.y, -10f, 10f);
|
||||
spawnOffsetY.x = Mathf.Clamp(spawnOffsetY.x, -10f, 10f);
|
||||
spawnOffsetY.y = Mathf.Clamp(spawnOffsetY.y, -10f, 10f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,8 +32,16 @@ namespace Core.Settings
|
||||
int IncorrectSortPenalty { get; }
|
||||
int MissedItemPenalty { get; }
|
||||
|
||||
// Lives
|
||||
int MaxLives { get; }
|
||||
|
||||
// Rewards
|
||||
int BoosterPacksPerCorrectItem { get; }
|
||||
|
||||
// Visual
|
||||
Vector2 CardSize { get; }
|
||||
Vector2 SpawnOffsetX { get; } // Min/Max range for X offset (distance)
|
||||
Vector2 SpawnOffsetY { get; } // Min/Max range for Y offset (position)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ using Data.CardSystem;
|
||||
using Minigames.CardSorting.Core;
|
||||
using Minigames.CardSorting.Data;
|
||||
using System.Collections.Generic;
|
||||
using UI.DragAndDrop.Core;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Minigames.CardSorting.Controllers
|
||||
@@ -27,6 +28,8 @@ namespace Minigames.CardSorting.Controllers
|
||||
private HashSet<SortableItem> missedItems = new HashSet<SortableItem>(); // Items past visual end, moving to despawn
|
||||
private float currentSpeed;
|
||||
private SortableItem lastSpawnedItem; // Track last spawned item for distance-based spawning
|
||||
private float cachedSpawnOffsetX; // Cached random offset for next spawn
|
||||
private bool isGameOver = false; // Flag to stop conveyor when game ends
|
||||
|
||||
// Events - conveyor owns item lifecycle
|
||||
public event System.Action<SortableItem> OnItemSpawned; // Fired when new item spawns
|
||||
@@ -37,6 +40,7 @@ namespace Minigames.CardSorting.Controllers
|
||||
|
||||
public float CurrentSpeed => currentSpeed;
|
||||
public int ActiveItemCount => activeItems.Count;
|
||||
public bool IsGameOver => isGameOver;
|
||||
|
||||
public ConveyorBeltController(
|
||||
Transform spawnPoint,
|
||||
@@ -55,6 +59,9 @@ namespace Minigames.CardSorting.Controllers
|
||||
|
||||
this.currentSpeed = settings.InitialBeltSpeed;
|
||||
this.lastSpawnedItem = null; // No items spawned yet
|
||||
|
||||
// Initialize first cached offset
|
||||
this.cachedSpawnOffsetX = Random.Range(settings.SpawnOffsetX.x, settings.SpawnOffsetX.y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -62,6 +69,9 @@ namespace Minigames.CardSorting.Controllers
|
||||
/// </summary>
|
||||
public void Update(float deltaTime, float gameProgress)
|
||||
{
|
||||
// Stop processing if game is over
|
||||
if (isGameOver) return;
|
||||
|
||||
UpdateBeltSpeed(gameProgress);
|
||||
CheckItemsOffBelt();
|
||||
CheckDistanceBasedSpawn(gameProgress);
|
||||
@@ -70,6 +80,7 @@ namespace Minigames.CardSorting.Controllers
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// Uses cached random X offset for spawn distance variation.
|
||||
/// </summary>
|
||||
private void CheckDistanceBasedSpawn(float gameProgress)
|
||||
{
|
||||
@@ -77,15 +88,24 @@ namespace Minigames.CardSorting.Controllers
|
||||
if (lastSpawnedItem == null)
|
||||
{
|
||||
SpawnNewItem(gameProgress);
|
||||
|
||||
// Generate new offset for next spawn
|
||||
cachedSpawnOffsetX = Random.Range(settings.SpawnOffsetX.x, settings.SpawnOffsetX.y);
|
||||
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
|
||||
// Use cached offset for required distance
|
||||
float requiredDistance = settings.SpawnDistance + cachedSpawnOffsetX;
|
||||
|
||||
if (distanceFromSpawn >= requiredDistance)
|
||||
{
|
||||
SpawnNewItem(gameProgress);
|
||||
|
||||
// Generate new offset for next spawn
|
||||
cachedSpawnOffsetX = Random.Range(settings.SpawnOffsetX.x, settings.SpawnOffsetX.y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,16 +165,27 @@ namespace Minigames.CardSorting.Controllers
|
||||
|
||||
GarbageItemDefinition garbage = SelectRandomGarbage();
|
||||
|
||||
GameObject obj = Object.Instantiate(garbagePrefab, spawnPoint.position, Quaternion.identity);
|
||||
// Apply random Y offset to spawn position
|
||||
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);
|
||||
SortableItem item = obj.GetComponent<SortableItem>();
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
item.SetupAsGarbage(garbage);
|
||||
|
||||
// Apply card size (garbage items use same size as cards)
|
||||
ApplyCardSize(item);
|
||||
|
||||
// Subscribe to item events
|
||||
item.OnItemDroppedInBox += HandleItemDroppedInBox;
|
||||
item.OnItemDroppedOnFloor += HandleItemDroppedOnFloor;
|
||||
item.OnItemReturnedToConveyor += HandleItemReturnedToConveyor;
|
||||
|
||||
// Subscribe to drag events to remove from tracking
|
||||
item.OnDragStarted += HandleItemDragStarted;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -177,16 +208,27 @@ namespace Minigames.CardSorting.Controllers
|
||||
return null;
|
||||
}
|
||||
|
||||
GameObject obj = Object.Instantiate(cardPrefab, spawnPoint.position, Quaternion.identity);
|
||||
// Apply random Y offset to spawn position
|
||||
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);
|
||||
SortableItem item = obj.GetComponent<SortableItem>();
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
item.SetupAsCard(cardData);
|
||||
|
||||
// Apply card size
|
||||
ApplyCardSize(item);
|
||||
|
||||
// Subscribe to item events
|
||||
item.OnItemDroppedInBox += HandleItemDroppedInBox;
|
||||
item.OnItemDroppedOnFloor += HandleItemDroppedOnFloor;
|
||||
item.OnItemReturnedToConveyor += HandleItemReturnedToConveyor;
|
||||
|
||||
// Subscribe to drag events to remove from tracking
|
||||
item.OnDragStarted += HandleItemDragStarted;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -296,55 +338,86 @@ namespace Minigames.CardSorting.Controllers
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Handle when an item starts being dragged.
|
||||
/// Remove from tracking to prevent "fell off belt" detection while dragging.
|
||||
/// </summary>
|
||||
private void HandleItemDragStarted(DraggableObject draggableObj)
|
||||
{
|
||||
SortableItem item = draggableObj as SortableItem;
|
||||
if (item == null) return;
|
||||
|
||||
RemoveItemFromTracking(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle when an item is dropped in a box (correct or incorrect).
|
||||
/// Note: Item was already removed from activeItems when dragging started (HandleItemDragStarted).
|
||||
/// </summary>
|
||||
private void HandleItemDroppedInBox(SortableItem item, SortingBox box, bool correct)
|
||||
{
|
||||
// Remove from tracking and unsubscribe
|
||||
if (activeItems.Remove(item))
|
||||
// Clean up tracking (item already removed from activeItems when picked up)
|
||||
activeItems.Remove(item);
|
||||
missedItems.Remove(item);
|
||||
|
||||
// Clear lastSpawnedItem reference if this was it
|
||||
if (lastSpawnedItem == item)
|
||||
{
|
||||
// Also remove from missed items if it was there
|
||||
missedItems.Remove(item);
|
||||
lastSpawnedItem = null;
|
||||
}
|
||||
|
||||
// Clear lastSpawnedItem reference if this was it
|
||||
if (lastSpawnedItem == item)
|
||||
{
|
||||
lastSpawnedItem = null;
|
||||
}
|
||||
// Unsubscribe from events
|
||||
item.OnItemDroppedInBox -= HandleItemDroppedInBox;
|
||||
item.OnItemDroppedOnFloor -= HandleItemDroppedOnFloor;
|
||||
item.OnItemReturnedToConveyor -= HandleItemReturnedToConveyor;
|
||||
item.OnDragStarted -= HandleItemDragStarted;
|
||||
|
||||
item.OnItemDroppedInBox -= HandleItemDroppedInBox;
|
||||
item.OnItemReturnedToConveyor -= HandleItemReturnedToConveyor;
|
||||
// Emit event for game manager to handle scoring, passing box and correctness
|
||||
OnItemSorted?.Invoke(item, box, correct);
|
||||
}
|
||||
|
||||
// Emit event for game manager to handle scoring, passing box and correctness
|
||||
OnItemSorted?.Invoke(item, box, correct);
|
||||
/// <summary>
|
||||
/// Handle when an item is returned to conveyor (dropped back on conveyor belt).
|
||||
/// Re-adds item to tracking so it continues moving along the belt.
|
||||
/// </summary>
|
||||
private void HandleItemReturnedToConveyor(SortableItem item)
|
||||
{
|
||||
if (item == null) return;
|
||||
|
||||
// Re-add to active tracking
|
||||
if (!activeItems.Contains(item))
|
||||
{
|
||||
activeItems.Add(item);
|
||||
Debug.Log($"[ConveyorBeltController] Item returned to conveyor: {item.CardData?.Name ?? item.GarbageItem?.DisplayName}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle when an item is returned to conveyor (dropped outside box).
|
||||
/// Handle when an item is dropped on floor (dropped outside box).
|
||||
/// Item transitions to DroppedOnFloorState and gets destroyed.
|
||||
/// Note: Item was already removed from activeItems when dragging started (HandleItemDragStarted).
|
||||
/// </summary>
|
||||
private void HandleItemReturnedToConveyor(SortableItem item)
|
||||
private void HandleItemDroppedOnFloor(SortableItem item)
|
||||
{
|
||||
// Remove from tracking and unsubscribe (item will be destroyed)
|
||||
if (activeItems.Remove(item))
|
||||
// Clean up tracking (item already removed from activeItems when picked up)
|
||||
activeItems.Remove(item);
|
||||
missedItems.Remove(item);
|
||||
|
||||
if (lastSpawnedItem == 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}");
|
||||
lastSpawnedItem = null;
|
||||
}
|
||||
|
||||
// Unsubscribe from events
|
||||
item.OnItemDroppedInBox -= HandleItemDroppedInBox;
|
||||
item.OnItemDroppedOnFloor -= HandleItemDroppedOnFloor;
|
||||
item.OnItemReturnedToConveyor -= HandleItemReturnedToConveyor;
|
||||
item.OnDragStarted -= HandleItemDragStarted;
|
||||
|
||||
// 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)
|
||||
@@ -365,6 +438,65 @@ namespace Minigames.CardSorting.Controllers
|
||||
{
|
||||
return settings.GarbageItems[Random.Range(0, settings.GarbageItems.Length)];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply configured card size to spawned item.
|
||||
/// </summary>
|
||||
private void ApplyCardSize(SortableItem item)
|
||||
{
|
||||
if (item == null || item.Context == null || item.Context.RootTransform == null)
|
||||
return;
|
||||
|
||||
// Get the RectTransform to resize (root object)
|
||||
var rectTransform = item.Context.RootTransform.GetComponent<RectTransform>();
|
||||
if (rectTransform != null)
|
||||
{
|
||||
rectTransform.sizeDelta = settings.CardSize;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove an item from tracking (called when picked up via event).
|
||||
/// Prevents item from being subject to belt end detection while being dragged.
|
||||
/// </summary>
|
||||
private void RemoveItemFromTracking(SortableItem item)
|
||||
{
|
||||
if (item == null) return;
|
||||
|
||||
bool wasTracked = activeItems.Remove(item);
|
||||
missedItems.Remove(item);
|
||||
|
||||
// Clear lastSpawnedItem reference if this was it
|
||||
if (lastSpawnedItem == item)
|
||||
{
|
||||
lastSpawnedItem = null;
|
||||
}
|
||||
|
||||
if (wasTracked)
|
||||
{
|
||||
Debug.Log($"[ConveyorBeltController] Item removed from tracking (picked up): {item.CardData?.Name ?? item.GarbageItem?.DisplayName}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop the conveyor belt when game ends.
|
||||
/// Disables dragging on all active items so they can't be interacted with.
|
||||
/// </summary>
|
||||
public void StopConveyor()
|
||||
{
|
||||
isGameOver = true;
|
||||
|
||||
// Disable dragging on all active items
|
||||
foreach (var item in activeItems)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
item.SetDraggingEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log("[ConveyorBeltController] Conveyor stopped - all items disabled");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
using UI.DragAndDrop.Core;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Minigames.CardSorting.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Slot component for the conveyor belt.
|
||||
/// Allows detection when items are dropped back onto the conveyor.
|
||||
/// Place this on a UI element (Image/Panel) that covers the conveyor belt area.
|
||||
/// </summary>
|
||||
public class ConveyorBeltSlot : DraggableSlot
|
||||
{
|
||||
/// <summary>
|
||||
/// Check if this slot can accept a specific draggable type.
|
||||
/// ConveyorBeltSlot accepts all SortableItems.
|
||||
/// </summary>
|
||||
public new bool CanAccept(DraggableObject draggable)
|
||||
{
|
||||
// Accept all sortable items
|
||||
return draggable is SortableItem;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when an item is dropped on the conveyor.
|
||||
/// Items dropped here should return to their conveyor state.
|
||||
/// </summary>
|
||||
public void OnItemDroppedOnConveyor(SortableItem item)
|
||||
{
|
||||
if (item == null) return;
|
||||
|
||||
Debug.Log($"[ConveyorBeltSlot] Item dropped back on conveyor: {item.CardData?.Name ?? item.GarbageItem?.DisplayName}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9304d17587314133a4d8d1e582cfbf81
|
||||
timeCreated: 1763590821
|
||||
@@ -28,7 +28,8 @@ namespace Minigames.CardSorting.Core
|
||||
|
||||
// Events - item emits notifications, conveyor subscribes
|
||||
public event System.Action<SortableItem, SortingBox, bool> OnItemDroppedInBox;
|
||||
public event System.Action<SortableItem> OnItemReturnedToConveyor;
|
||||
public event System.Action<SortableItem> OnItemDroppedOnFloor;
|
||||
public event System.Action<SortableItem> OnItemReturnedToConveyor; // Fired when dropped back on conveyor
|
||||
|
||||
// Public accessors
|
||||
public SortableItemContext Context => context;
|
||||
@@ -142,9 +143,10 @@ namespace Minigames.CardSorting.Core
|
||||
{
|
||||
base.OnDragEndedHook();
|
||||
|
||||
// Validate drop on sorting box
|
||||
// Check what type of slot we're over
|
||||
if (CurrentSlot is SortingBox box)
|
||||
{
|
||||
// Dropped in sorting box
|
||||
bool correctSort = box.ValidateItem(this);
|
||||
|
||||
// Fire event IMMEDIATELY when card is released over bin
|
||||
@@ -162,10 +164,28 @@ namespace Minigames.CardSorting.Core
|
||||
ChangeState("SortedIncorrectlyState");
|
||||
}
|
||||
}
|
||||
else if (CurrentSlot is ConveyorBeltSlot conveyorSlot)
|
||||
{
|
||||
// Dropped back on conveyor - return to conveyor state
|
||||
Logging.Debug("[SortableItem] Dropped back on conveyor, returning to OnConveyorState");
|
||||
|
||||
// Notify conveyor slot
|
||||
conveyorSlot.OnItemDroppedOnConveyor(this);
|
||||
|
||||
// Fire event for conveyor controller to re-add to tracking
|
||||
OnItemReturnedToConveyor?.Invoke(this);
|
||||
|
||||
// Return to conveyor state
|
||||
ChangeState("OnConveyorState");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Dropped outside valid box - transition to dropped on floor state
|
||||
Logging.Debug("[SortableItem] Dropped outside box, transitioning to floor state");
|
||||
// Dropped outside valid box or conveyor - fire event then transition to dropped on floor state
|
||||
Logging.Debug("[SortableItem] Dropped outside box/conveyor, transitioning to floor state");
|
||||
|
||||
// Fire event for conveyor controller to handle scoring
|
||||
OnItemDroppedOnFloor?.Invoke(this);
|
||||
|
||||
ChangeState("DroppedOnFloorState");
|
||||
}
|
||||
}
|
||||
@@ -174,6 +194,7 @@ namespace Minigames.CardSorting.Core
|
||||
/// <summary>
|
||||
/// Detect which slot (if any) is under the pointer during drag.
|
||||
/// Updates CurrentSlot for drop detection.
|
||||
/// Scans for both SortingBox and ConveyorBeltSlot.
|
||||
/// </summary>
|
||||
private void DetectSlotUnderPointer(UnityEngine.EventSystems.PointerEventData eventData)
|
||||
{
|
||||
@@ -181,29 +202,46 @@ namespace Minigames.CardSorting.Core
|
||||
var raycastResults = new System.Collections.Generic.List<UnityEngine.EventSystems.RaycastResult>();
|
||||
UnityEngine.EventSystems.EventSystem.current.RaycastAll(eventData, raycastResults);
|
||||
|
||||
SortingBox hoveredBox = null;
|
||||
DraggableSlot hoveredSlot = null;
|
||||
|
||||
// Find first SortingBox in raycast results
|
||||
// Find first slot (SortingBox or ConveyorBeltSlot) in raycast results
|
||||
foreach (var result in raycastResults)
|
||||
{
|
||||
// Check for SortingBox first (higher priority)
|
||||
var box = result.gameObject.GetComponentInParent<SortingBox>();
|
||||
if (box != null)
|
||||
{
|
||||
hoveredBox = box;
|
||||
hoveredSlot = box;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check for ConveyorBeltSlot if no box found
|
||||
var conveyorSlot = result.gameObject.GetComponentInParent<ConveyorBeltSlot>();
|
||||
if (conveyorSlot != null)
|
||||
{
|
||||
hoveredSlot = conveyorSlot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Update current slot (used in OnDragEndedHook)
|
||||
if (hoveredBox != null && hoveredBox != CurrentSlot)
|
||||
if (hoveredSlot != null && hoveredSlot != CurrentSlot)
|
||||
{
|
||||
_currentSlot = hoveredBox;
|
||||
Logging.Debug($"[SortableItem] Now hovering over {hoveredBox.BoxType} box");
|
||||
_currentSlot = hoveredSlot;
|
||||
|
||||
if (hoveredSlot is SortingBox sortBox)
|
||||
{
|
||||
Logging.Debug($"[SortableItem] Now hovering over {sortBox.BoxType} box");
|
||||
}
|
||||
else if (hoveredSlot is ConveyorBeltSlot)
|
||||
{
|
||||
Logging.Debug("[SortableItem] Now hovering over conveyor belt");
|
||||
}
|
||||
}
|
||||
else if (hoveredBox == null && CurrentSlot != null)
|
||||
else if (hoveredSlot == null && CurrentSlot != null)
|
||||
{
|
||||
_currentSlot = null;
|
||||
Logging.Debug("[SortableItem] No longer over any box");
|
||||
Logging.Debug("[SortableItem] No longer over any slot");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,9 +29,15 @@ namespace Minigames.CardSorting.Core
|
||||
[Header("Effects")]
|
||||
[SerializeField] private CinemachineImpulseSource impulseSource; // Screen shake on incorrect sort
|
||||
|
||||
[Header("UI References")]
|
||||
[SerializeField] private UI.LivesDisplay livesDisplay;
|
||||
|
||||
// Settings
|
||||
private ICardSortingSettings _settings;
|
||||
|
||||
// Lives tracking
|
||||
private int currentLives;
|
||||
|
||||
// Controllers (lazy init)
|
||||
private ConveyorBeltController _conveyorController;
|
||||
private ConveyorBeltController Conveyor => _conveyorController ??= new ConveyorBeltController(
|
||||
@@ -43,6 +49,9 @@ namespace Minigames.CardSorting.Core
|
||||
_settings
|
||||
);
|
||||
|
||||
// Public accessor for states to check game over status
|
||||
public ConveyorBeltController ConveyorController => Conveyor;
|
||||
|
||||
private SortingScoreController _scoreController;
|
||||
private SortingScoreController Score => _scoreController ??= new SortingScoreController(_settings);
|
||||
|
||||
@@ -152,6 +161,13 @@ namespace Minigames.CardSorting.Core
|
||||
// Reset score
|
||||
Score.Reset();
|
||||
|
||||
// Initialize lives
|
||||
currentLives = _settings.MaxLives;
|
||||
if (livesDisplay != null)
|
||||
{
|
||||
livesDisplay.Initialize(currentLives);
|
||||
}
|
||||
|
||||
OnGameStarted?.Invoke();
|
||||
|
||||
// Set input mode to game
|
||||
@@ -163,6 +179,61 @@ namespace Minigames.CardSorting.Core
|
||||
Logging.Debug("[SortingGameManager] Game started!");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unified feedback for wrong actions (trash penalties).
|
||||
/// Plays blink animation on item and triggers camera shake.
|
||||
/// </summary>
|
||||
public void PlayWrongStateFeedback(SortableItem item)
|
||||
{
|
||||
// Camera shake
|
||||
if (impulseSource != null)
|
||||
{
|
||||
impulseSource.GenerateImpulse();
|
||||
}
|
||||
|
||||
// Blink the item red (if it still exists)
|
||||
if (item != null && item.Context != null && item.Context.Animator != null)
|
||||
{
|
||||
UnityEngine.UI.Image imageToBlink = null;
|
||||
|
||||
if (item.Context.CardDisplay != null)
|
||||
{
|
||||
imageToBlink = item.Context.CardDisplay.GetComponent<UnityEngine.UI.Image>();
|
||||
}
|
||||
else if (item.Context.GarbageVisual != null)
|
||||
{
|
||||
imageToBlink = item.Context.GarbageVisual.GetComponent<UnityEngine.UI.Image>();
|
||||
}
|
||||
|
||||
if (imageToBlink != null)
|
||||
{
|
||||
item.Context.Animator.BlinkRed(imageToBlink, 0.15f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lose a life. If lives reach 0, end the game.
|
||||
/// </summary>
|
||||
private void LoseLife()
|
||||
{
|
||||
currentLives--;
|
||||
|
||||
if (livesDisplay != null)
|
||||
{
|
||||
livesDisplay.RemoveLife();
|
||||
}
|
||||
|
||||
Logging.Debug($"[SortingGameManager] Life lost! Remaining lives: {currentLives}");
|
||||
|
||||
// Check for game over
|
||||
if (currentLives <= 0)
|
||||
{
|
||||
Logging.Debug("[SortingGameManager] No lives remaining - Game Over!");
|
||||
EndGame();
|
||||
}
|
||||
}
|
||||
|
||||
public void EndGame()
|
||||
{
|
||||
if (isGameOver) return;
|
||||
@@ -170,6 +241,9 @@ namespace Minigames.CardSorting.Core
|
||||
isGameOver = true;
|
||||
isGameActive = false;
|
||||
|
||||
// Stop the conveyor and disable all items
|
||||
Conveyor.StopConveyor();
|
||||
|
||||
// Calculate rewards
|
||||
int boosterReward = Score.CalculateBoosterReward();
|
||||
|
||||
@@ -201,7 +275,7 @@ namespace Minigames.CardSorting.Core
|
||||
/// 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)
|
||||
/// - Trash fell off: Negative score (penalty) + lose life
|
||||
/// - Card fell off: Neutral (no score change)
|
||||
/// </summary>
|
||||
private void OnConveyorItemFellOff(SortableItem item)
|
||||
@@ -211,6 +285,8 @@ namespace Minigames.CardSorting.Core
|
||||
if (item.IsGarbage)
|
||||
{
|
||||
Score.RecordMissedItem();
|
||||
PlayWrongStateFeedback(item);
|
||||
LoseLife();
|
||||
Logging.Debug($"[SortingGameManager] Trash fell off belt! {item.GarbageItem?.DisplayName} - PENALTY");
|
||||
}
|
||||
else
|
||||
@@ -228,7 +304,7 @@ namespace Minigames.CardSorting.Core
|
||||
/// <summary>
|
||||
/// Called when item is dropped on floor (via conveyor event).
|
||||
/// Scoring rules:
|
||||
/// - Trash dropped on floor: Negative score (penalty)
|
||||
/// - Trash dropped on floor: Negative score (penalty) + lose life
|
||||
/// - Card dropped on floor: Neutral (no score change)
|
||||
/// </summary>
|
||||
private void OnConveyorItemDroppedOnFloor(SortableItem item)
|
||||
@@ -238,13 +314,9 @@ namespace Minigames.CardSorting.Core
|
||||
if (item.IsGarbage)
|
||||
{
|
||||
Score.RecordIncorrectSort();
|
||||
PlayWrongStateFeedback(item);
|
||||
LoseLife();
|
||||
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
|
||||
{
|
||||
@@ -270,7 +342,7 @@ namespace Minigames.CardSorting.Core
|
||||
/// 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 trash: Negative score (trash in wrong box) + lose life
|
||||
/// - Incorrect card: Neutral (no score change)
|
||||
/// </summary>
|
||||
private void OnConveyorItemSorted(SortableItem item, SortingBox box, bool correct)
|
||||
@@ -290,16 +362,12 @@ namespace Minigames.CardSorting.Core
|
||||
if (item.IsGarbage)
|
||||
{
|
||||
Score.RecordIncorrectSort();
|
||||
PlayWrongStateFeedback(item);
|
||||
LoseLife();
|
||||
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
|
||||
{
|
||||
|
||||
@@ -13,10 +13,12 @@ namespace Minigames.CardSorting.StateMachine.States
|
||||
public class BeingDraggedState : AppleState
|
||||
{
|
||||
private SortableItemContext _context;
|
||||
private SortableItem _item;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_context = GetComponentInParent<SortableItemContext>();
|
||||
_item = GetComponentInParent<SortableItem>();
|
||||
}
|
||||
|
||||
public override void OnEnterState()
|
||||
@@ -25,8 +27,6 @@ namespace Minigames.CardSorting.StateMachine.States
|
||||
|
||||
_context.IsOnConveyor = false;
|
||||
|
||||
// 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)
|
||||
{
|
||||
Vector3 targetScale = _context.OriginalScale * 1.1f;
|
||||
|
||||
@@ -25,45 +25,11 @@ namespace Minigames.CardSorting.StateMachine.States
|
||||
|
||||
_context.IsOnConveyor = false;
|
||||
|
||||
Logging.Debug("[DroppedOnFloorState] Item dropped on floor, blinking red then disappearing");
|
||||
Logging.Debug("[DroppedOnFloorState] Item dropped on floor, 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<UnityEngine.UI.Image>();
|
||||
}
|
||||
else if (_context.GarbageVisual != null)
|
||||
{
|
||||
imageToBlink = _context.GarbageVisual.GetComponent<UnityEngine.UI.Image>();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
// Feedback (blink + shake) already triggered by game manager when scoring (for trash)
|
||||
// Just play disappear animation
|
||||
PlayDisappearAnimation();
|
||||
}
|
||||
|
||||
private void PlayDisappearAnimation()
|
||||
|
||||
@@ -44,6 +44,12 @@ namespace Minigames.CardSorting.StateMachine.States
|
||||
{
|
||||
if (_context == null || !_context.IsOnConveyor) return;
|
||||
|
||||
// Stop moving if game is over
|
||||
if (SortingGameManager.Instance.ConveyorController.IsGameOver)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Continue moving item toward despawn point (same logic as OnConveyorState)
|
||||
Vector3 movement = Vector3.right * _context.ConveyorSpeed * Time.deltaTime;
|
||||
_context.RootTransform.position += movement;
|
||||
|
||||
@@ -40,6 +40,12 @@ namespace Minigames.CardSorting.StateMachine.States
|
||||
{
|
||||
if (_context == null || !_context.IsOnConveyor) return;
|
||||
|
||||
// Stop moving if game is over
|
||||
if (SortingGameManager.Instance.ConveyorController.IsGameOver)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Move item along conveyor (right direction)
|
||||
Vector3 movement = Vector3.right * _context.ConveyorSpeed * Time.deltaTime;
|
||||
_context.RootTransform.position += movement;
|
||||
|
||||
@@ -26,45 +26,11 @@ namespace Minigames.CardSorting.StateMachine.States
|
||||
|
||||
_context.IsOnConveyor = false;
|
||||
|
||||
Logging.Debug("[SortedIncorrectlyState] Item incorrectly sorted, blinking red then tweening to box");
|
||||
Logging.Debug("[SortedIncorrectlyState] Item incorrectly sorted, tweening to box then falling in");
|
||||
|
||||
// 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<UnityEngine.UI.Image>();
|
||||
}
|
||||
else if (_context.GarbageVisual != null)
|
||||
{
|
||||
imageToBlink = _context.GarbageVisual.GetComponent<UnityEngine.UI.Image>();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
// Feedback (blink + shake) already triggered by game manager when scoring
|
||||
// Just proceed with animation
|
||||
TweenToBoxThenFall();
|
||||
}
|
||||
|
||||
private void TweenToBoxThenFall()
|
||||
|
||||
208
Assets/Scripts/Minigames/CardSorting/UI/LivesDisplay.cs
Normal file
208
Assets/Scripts/Minigames/CardSorting/UI/LivesDisplay.cs
Normal file
@@ -0,0 +1,208 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Minigames.CardSorting.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Displays and animates lives for the card sorting minigame.
|
||||
/// Manages a layout group of life icons with add/remove animations.
|
||||
/// </summary>
|
||||
public class LivesDisplay : MonoBehaviour
|
||||
{
|
||||
[Header("Configuration")]
|
||||
[SerializeField] private LayoutGroup layoutGroup;
|
||||
|
||||
[Header("Animation Settings")]
|
||||
[SerializeField] private float animationDuration = 0.3f;
|
||||
[SerializeField] private float scaleMultiplier = 1.5f;
|
||||
|
||||
private GameObject lifeIconPrefab;
|
||||
private List<GameObject> lifeIcons = new List<GameObject>();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (layoutGroup == null)
|
||||
{
|
||||
layoutGroup = GetComponent<LayoutGroup>();
|
||||
}
|
||||
|
||||
// Find the prefab (first child) if not assigned
|
||||
if (lifeIconPrefab == null && layoutGroup != null && layoutGroup.transform.childCount > 0)
|
||||
{
|
||||
lifeIconPrefab = layoutGroup.transform.GetChild(0).gameObject;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the display with the maximum number of lives.
|
||||
/// Clones the prefab element multiple times.
|
||||
/// </summary>
|
||||
public void Initialize(int maxLives)
|
||||
{
|
||||
// Clear existing lives
|
||||
ClearAllLives();
|
||||
|
||||
if (lifeIconPrefab == null)
|
||||
{
|
||||
Debug.LogError("[LivesDisplay] No life icon prefab assigned!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (layoutGroup == null)
|
||||
{
|
||||
Debug.LogError("[LivesDisplay] No layout group assigned!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure prefab is active to use as template
|
||||
bool wasActive = lifeIconPrefab.activeSelf;
|
||||
lifeIconPrefab.SetActive(true);
|
||||
lifeIcons.Add(lifeIconPrefab);
|
||||
|
||||
// Create life icons
|
||||
for (int i = 0; i < maxLives - 1; i++)
|
||||
{
|
||||
GameObject icon = Instantiate(lifeIconPrefab, layoutGroup.transform);
|
||||
icon.SetActive(true);
|
||||
lifeIcons.Add(icon);
|
||||
}
|
||||
|
||||
// Hide the original prefab
|
||||
lifeIconPrefab.SetActive(wasActive);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a life with animation.
|
||||
/// </summary>
|
||||
public void RemoveLife()
|
||||
{
|
||||
if (lifeIcons.Count == 0)
|
||||
{
|
||||
Debug.LogWarning("[LivesDisplay] No lives left to remove!");
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject icon = lifeIcons[0];
|
||||
lifeIcons.RemoveAt(0);
|
||||
|
||||
// Play removal animation
|
||||
StartCoroutine(AnimateLifeRemoval(icon));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a life with animation.
|
||||
/// </summary>
|
||||
public void AddLife()
|
||||
{
|
||||
if (lifeIconPrefab == null || layoutGroup == null)
|
||||
{
|
||||
Debug.LogError("[LivesDisplay] Cannot add life - missing prefab or layout group!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create new life icon
|
||||
GameObject icon = Instantiate(lifeIconPrefab, layoutGroup.transform);
|
||||
icon.SetActive(true);
|
||||
lifeIcons.Add(icon);
|
||||
|
||||
// Play addition animation
|
||||
StartCoroutine(AnimateLifeAddition(icon));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear all lives (for reset).
|
||||
/// </summary>
|
||||
private void ClearAllLives()
|
||||
{
|
||||
foreach (var icon in lifeIcons)
|
||||
{
|
||||
if (icon != null)
|
||||
{
|
||||
Destroy(icon);
|
||||
}
|
||||
}
|
||||
lifeIcons.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Animate life removal: scale up, then scale down and destroy.
|
||||
/// </summary>
|
||||
private IEnumerator AnimateLifeRemoval(GameObject icon)
|
||||
{
|
||||
if (icon == null) yield break;
|
||||
|
||||
Vector3 originalScale = icon.transform.localScale;
|
||||
Vector3 targetScale = originalScale * scaleMultiplier;
|
||||
|
||||
// Scale up
|
||||
yield return AnimateScale(icon.transform, originalScale, targetScale, animationDuration * 0.5f);
|
||||
|
||||
// Scale down to zero
|
||||
yield return AnimateScale(icon.transform, targetScale, Vector3.zero, animationDuration * 0.5f);
|
||||
|
||||
// Destroy
|
||||
if (icon != null)
|
||||
{
|
||||
Destroy(icon);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Animate life addition: start at zero, scale up beyond target, then settle to normal.
|
||||
/// </summary>
|
||||
private IEnumerator AnimateLifeAddition(GameObject icon)
|
||||
{
|
||||
if (icon == null) yield break;
|
||||
|
||||
Vector3 originalScale = icon.transform.localScale;
|
||||
Vector3 overshootScale = originalScale * scaleMultiplier;
|
||||
|
||||
// Start at zero
|
||||
icon.transform.localScale = Vector3.zero;
|
||||
|
||||
// Scale up to overshoot
|
||||
yield return AnimateScale(icon.transform, Vector3.zero, overshootScale, animationDuration * 0.5f);
|
||||
|
||||
// Settle back to original scale
|
||||
yield return AnimateScale(icon.transform, overshootScale, originalScale, animationDuration * 0.5f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generic scale animation coroutine.
|
||||
/// </summary>
|
||||
private IEnumerator AnimateScale(Transform target, Vector3 from, Vector3 to, float duration)
|
||||
{
|
||||
float elapsed = 0f;
|
||||
|
||||
while (elapsed < duration)
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
float t = Mathf.Clamp01(elapsed / duration);
|
||||
|
||||
// Use ease-in-out curve for smooth animation
|
||||
t = t * t * (3f - 2f * t); // Smoothstep
|
||||
|
||||
if (target != null)
|
||||
{
|
||||
target.localScale = Vector3.Lerp(from, to, t);
|
||||
}
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
// Ensure final scale is set
|
||||
if (target != null)
|
||||
{
|
||||
target.localScale = to;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current number of lives displayed.
|
||||
/// </summary>
|
||||
public int CurrentLives => lifeIcons.Count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e8bcb252540442e593cc6467c518ff75
|
||||
timeCreated: 1763586518
|
||||
@@ -99,7 +99,8 @@ namespace Minigames.CardSorting.UI
|
||||
{
|
||||
if (scoreText == null) return;
|
||||
|
||||
scoreText.text = $"Score: {newScore}";
|
||||
// Only display numerical value (label is separate UI element)
|
||||
scoreText.text = $"Score: {newScore.ToString()}";
|
||||
|
||||
// Color based on positive/negative
|
||||
if (newScore >= 0)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using Minigames.CardSorting.Core;
|
||||
using System;
|
||||
using Core;
|
||||
using Minigames.CardSorting.Core;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
@@ -70,26 +72,26 @@ namespace Minigames.CardSorting.UI
|
||||
|
||||
if (gameManager == null) return;
|
||||
|
||||
// Populate data
|
||||
// Populate data - only numerical values (labels are separate UI elements)
|
||||
if (finalScoreText != null)
|
||||
finalScoreText.text = $"Final Score: {gameManager.CurrentScore}";
|
||||
finalScoreText.text = gameManager.CurrentScore.ToString();
|
||||
|
||||
if (correctSortsText != null)
|
||||
correctSortsText.text = $"Correct: {gameManager.CorrectSorts}";
|
||||
correctSortsText.text = gameManager.CorrectSorts.ToString();
|
||||
|
||||
if (incorrectSortsText != null)
|
||||
incorrectSortsText.text = $"Incorrect: {gameManager.IncorrectSorts}";
|
||||
incorrectSortsText.text = gameManager.IncorrectSorts.ToString();
|
||||
|
||||
if (missedItemsText != null)
|
||||
missedItemsText.text = $"Missed: {gameManager.MissedItems}";
|
||||
missedItemsText.text = gameManager.MissedItems.ToString();
|
||||
|
||||
if (accuracyText != null)
|
||||
accuracyText.text = $"Accuracy: {gameManager.Accuracy:P0}";
|
||||
accuracyText.text = gameManager.Accuracy.ToString("P0");
|
||||
|
||||
// Calculate boosters (already granted by manager)
|
||||
int boosters = gameManager.CorrectSorts; // Simple 1:1 ratio
|
||||
if (boostersEarnedText != null)
|
||||
boostersEarnedText.text = $"Boosters Earned: {boosters}";
|
||||
boostersEarnedText.text = boosters.ToString();
|
||||
|
||||
// Show screen
|
||||
if (canvasGroup != null)
|
||||
@@ -104,7 +106,7 @@ namespace Minigames.CardSorting.UI
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCloseClicked()
|
||||
private async void OnCloseClicked()
|
||||
{
|
||||
// Hide screen
|
||||
if (canvasGroup != null)
|
||||
@@ -118,8 +120,9 @@ namespace Minigames.CardSorting.UI
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
// Could also trigger scene transition, return to menu, etc.
|
||||
Debug.Log("[SortingResultsScreen] Closed results screen");
|
||||
// TODO: Smarter replay?
|
||||
var progress = new Progress<float>(p => Logging.Debug($"Loading progress: {p * 100:F0}%"));
|
||||
await SceneManagerService.Instance.ReloadCurrentScene(progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,11 @@ MonoBehaviour:
|
||||
rareCardWeight: 30
|
||||
legendCardWeight: 20
|
||||
garbageWeight: 40
|
||||
correctSortPoints: 10
|
||||
incorrectSortPenalty: -5
|
||||
missedItemPenalty: -3
|
||||
correctSortPoints: 1
|
||||
incorrectSortPenalty: -1
|
||||
missedItemPenalty: 0
|
||||
maxLives: 3
|
||||
boosterPacksPerCorrectItem: 1
|
||||
cardSize: {x: 100, y: 140}
|
||||
spawnOffsetX: {x: -5, y: 5}
|
||||
spawnOffsetY: {x: -2.5, y: 2.5}
|
||||
|
||||
Reference in New Issue
Block a user