Add a semi-finished booster opening sequence
This commit is contained in:
@@ -34,7 +34,8 @@ RectTransform:
|
||||
- {fileID: 6998531714563205983}
|
||||
- {fileID: 2081116343754364062}
|
||||
- {fileID: 4830022034953347571}
|
||||
- {fileID: 5285839430634762799}
|
||||
- {fileID: 7968396929263690413}
|
||||
- {fileID: 6421996619962684991}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
@@ -272,6 +273,85 @@ MonoBehaviour:
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!1 &5977149977482844087
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 7968396929263690413}
|
||||
- component: {fileID: 3201204740095265044}
|
||||
m_Layer: 0
|
||||
m_Name: CenterSlotContainer
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &7968396929263690413
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5977149977482844087}
|
||||
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: 5285839430634762799}
|
||||
m_Father: {fileID: 5228380266581535650}
|
||||
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_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &3201204740095265044
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5977149977482844087}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f1347da8005d4687a85dbc4db9a1bbbb, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: AppleHillsScripts::UI.DragAndDrop.Core.SlotContainer
|
||||
layoutType: 0
|
||||
spacing: 100
|
||||
centerSlots: 1
|
||||
autoRegisterChildren: 1
|
||||
useCurveLayout: 0
|
||||
positionCurve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 0
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 0
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
- serializedVersion: 3
|
||||
time: 1
|
||||
value: 0
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 0
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
curveHeight: 50
|
||||
--- !u!1 &6017052972121068920
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -973,6 +1053,116 @@ RectTransform:
|
||||
m_CorrespondingSourceObject: {fileID: 4310919426181576387, guid: 561f7c561a416e54e9bf1c2af2f3f4ef, type: 3}
|
||||
m_PrefabInstance: {fileID: 3020147864556123455}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
--- !u!1001 &5916465061944119399
|
||||
PrefabInstance:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
serializedVersion: 3
|
||||
m_TransformParent: {fileID: 5228380266581535650}
|
||||
m_Modifications:
|
||||
- target: {fileID: 793761934373733976, guid: a04075d06f231594292595e90a69cbb1, type: 3}
|
||||
propertyPath: m_LocalPosition.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 793761934373733976, guid: a04075d06f231594292595e90a69cbb1, type: 3}
|
||||
propertyPath: m_LocalPosition.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 793761934373733976, guid: a04075d06f231594292595e90a69cbb1, type: 3}
|
||||
propertyPath: m_LocalPosition.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 793761934373733976, guid: a04075d06f231594292595e90a69cbb1, type: 3}
|
||||
propertyPath: m_LocalRotation.w
|
||||
value: 0.7071068
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 793761934373733976, guid: a04075d06f231594292595e90a69cbb1, type: 3}
|
||||
propertyPath: m_LocalRotation.x
|
||||
value: -0.7071068
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 793761934373733976, guid: a04075d06f231594292595e90a69cbb1, type: 3}
|
||||
propertyPath: m_LocalRotation.y
|
||||
value: -0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 793761934373733976, guid: a04075d06f231594292595e90a69cbb1, type: 3}
|
||||
propertyPath: m_LocalRotation.z
|
||||
value: -0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 793761934373733976, guid: a04075d06f231594292595e90a69cbb1, type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.x
|
||||
value: -90
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 793761934373733976, guid: a04075d06f231594292595e90a69cbb1, type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 793761934373733976, guid: a04075d06f231594292595e90a69cbb1, type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2325046327999825244, guid: a04075d06f231594292595e90a69cbb1, type: 3}
|
||||
propertyPath: m_Name
|
||||
value: VFX_ConfettiBurst_WIP
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4983040125055815969, guid: a04075d06f231594292595e90a69cbb1, type: 3}
|
||||
propertyPath: looping
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4983040125055815969, guid: a04075d06f231594292595e90a69cbb1, type: 3}
|
||||
propertyPath: InitialModule.size3D
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4983040125055815969, guid: a04075d06f231594292595e90a69cbb1, type: 3}
|
||||
propertyPath: InitialModule.startSize.scalar
|
||||
value: 10
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4983040125055815969, guid: a04075d06f231594292595e90a69cbb1, type: 3}
|
||||
propertyPath: InitialModule.startSizeY.scalar
|
||||
value: 10
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4983040125055815969, guid: a04075d06f231594292595e90a69cbb1, type: 3}
|
||||
propertyPath: InitialModule.startSizeZ.scalar
|
||||
value: 10
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4983040125055815969, guid: a04075d06f231594292595e90a69cbb1, type: 3}
|
||||
propertyPath: InitialModule.startSpeed.scalar
|
||||
value: 300
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4983040125055815969, guid: a04075d06f231594292595e90a69cbb1, type: 3}
|
||||
propertyPath: InitialModule.startSize.minScalar
|
||||
value: 20
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4983040125055815969, guid: a04075d06f231594292595e90a69cbb1, type: 3}
|
||||
propertyPath: InitialModule.startSizeY.minScalar
|
||||
value: 20
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4983040125055815969, guid: a04075d06f231594292595e90a69cbb1, type: 3}
|
||||
propertyPath: InitialModule.startSizeZ.minScalar
|
||||
value: 20
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4983040125055815969, guid: a04075d06f231594292595e90a69cbb1, type: 3}
|
||||
propertyPath: InitialModule.startSpeed.minScalar
|
||||
value: 200
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4983040125055815969, guid: a04075d06f231594292595e90a69cbb1, type: 3}
|
||||
propertyPath: InitialModule.gravityModifier.scalar
|
||||
value: 10
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 5980722886308389101, guid: a04075d06f231594292595e90a69cbb1, type: 3}
|
||||
propertyPath: m_SortingLayer
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects: []
|
||||
m_AddedComponents: []
|
||||
m_SourcePrefab: {fileID: 100100000, guid: a04075d06f231594292595e90a69cbb1, type: 3}
|
||||
--- !u!224 &6421996619962684991 stripped
|
||||
RectTransform:
|
||||
m_CorrespondingSourceObject: {fileID: 793761934373733976, guid: a04075d06f231594292595e90a69cbb1, type: 3}
|
||||
m_PrefabInstance: {fileID: 5916465061944119399}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
--- !u!1001 &6217258165417062746
|
||||
PrefabInstance:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -1094,7 +1284,7 @@ PrefabInstance:
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
serializedVersion: 3
|
||||
m_TransformParent: {fileID: 5228380266581535650}
|
||||
m_TransformParent: {fileID: 7968396929263690413}
|
||||
m_Modifications:
|
||||
- target: {fileID: 4310919426181576387, guid: 561f7c561a416e54e9bf1c2af2f3f4ef, type: 3}
|
||||
propertyPath: m_Pivot.x
|
||||
@@ -1180,7 +1370,32 @@ PrefabInstance:
|
||||
propertyPath: m_Name
|
||||
value: CenterBoosterSlot
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
- target: {fileID: 6647899082618247385, guid: 561f7c561a416e54e9bf1c2af2f3f4ef, type: 3}
|
||||
propertyPath: hideImageOnPlay
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6647899082618247385, guid: 561f7c561a416e54e9bf1c2af2f3f4ef, type: 3}
|
||||
propertyPath: occupantScale.x
|
||||
value: 1.5
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6647899082618247385, guid: 561f7c561a416e54e9bf1c2af2f3f4ef, type: 3}
|
||||
propertyPath: occupantScale.y
|
||||
value: 1.5
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6647899082618247385, guid: 561f7c561a416e54e9bf1c2af2f3f4ef, type: 3}
|
||||
propertyPath: occupantScale.z
|
||||
value: 1.5
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6647899082618247385, guid: 561f7c561a416e54e9bf1c2af2f3f4ef, type: 3}
|
||||
propertyPath: occupantSizeMode
|
||||
value: 2
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 8654772933823231677, guid: 561f7c561a416e54e9bf1c2af2f3f4ef, type: 3}
|
||||
propertyPath: m_Enabled
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents:
|
||||
- {fileID: 8654772933823231677, guid: 561f7c561a416e54e9bf1c2af2f3f4ef, type: 3}
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects: []
|
||||
m_AddedComponents: []
|
||||
|
||||
@@ -86,16 +86,19 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: f95c1542aaa549d1867b43f6dc21e90f, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: AppleHillsScripts::UI.CardSystem.DragDrop.BoosterPackDraggable
|
||||
moveSpeed: 50
|
||||
smoothMovement: 1
|
||||
moveSpeed: 1500
|
||||
smoothMovement: 0
|
||||
snapDuration: 0.3
|
||||
visual: {fileID: 7621119673479996768}
|
||||
isSelectable: 1
|
||||
selectionOffset: 50
|
||||
canOpenOnDrop: 1
|
||||
canOpenOnDoubleClick: 1
|
||||
canTapToOpen: 1
|
||||
selectionOffset: 10
|
||||
canOpenOnDrop: 0
|
||||
canOpenOnDoubleClick: 0
|
||||
canTapToOpen: 0
|
||||
maxTapsToOpen: 3
|
||||
tapPulseScale: 1.15
|
||||
tapPulseDuration: 0.2
|
||||
openingParticleSystem: {fileID: 0}
|
||||
--- !u!1 &7174819457781356441
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -143,7 +146,6 @@ GameObject:
|
||||
- component: {fileID: 3011670408481256992}
|
||||
- component: {fileID: 7621119673479996768}
|
||||
- component: {fileID: 7579137834975743343}
|
||||
- component: {fileID: 6982163843775578079}
|
||||
m_Layer: 0
|
||||
m_Name: Visual
|
||||
m_TagString: Untagged
|
||||
@@ -184,16 +186,16 @@ MonoBehaviour:
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: AppleHillsScripts::UI.CardSystem.DragDrop.BoosterPackVisual
|
||||
canvas: {fileID: 7579137834975743343}
|
||||
canvasGroup: {fileID: 6982163843775578079}
|
||||
canvasGroup: {fileID: 0}
|
||||
tiltParent: {fileID: 5686487750795060323}
|
||||
shakeParent: {fileID: 5816619084030964884}
|
||||
followSpeed: 30
|
||||
followSpeed: 3
|
||||
useFollowDelay: 1
|
||||
rotationAmount: 20
|
||||
rotationSpeed: 20
|
||||
autoTiltAmount: 30
|
||||
manualTiltAmount: 20
|
||||
tiltSpeed: 20
|
||||
rotationAmount: 10
|
||||
rotationSpeed: 10
|
||||
autoTiltAmount: 15
|
||||
manualTiltAmount: 10
|
||||
tiltSpeed: 5
|
||||
useScaleAnimations: 1
|
||||
scaleOnHover: 1.15
|
||||
scaleOnDrag: 1.25
|
||||
@@ -230,18 +232,6 @@ Canvas:
|
||||
m_SortingLayerID: 0
|
||||
m_SortingOrder: 0
|
||||
m_TargetDisplay: 0
|
||||
--- !u!225 &6982163843775578079
|
||||
CanvasGroup:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8049593174403022815}
|
||||
m_Enabled: 1
|
||||
m_Alpha: 1
|
||||
m_Interactable: 1
|
||||
m_BlocksRaycasts: 1
|
||||
m_IgnoreParentGroups: 0
|
||||
--- !u!1 &8644026751513010577
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@@ -1506,6 +1506,10 @@ PrefabInstance:
|
||||
propertyPath: m_SizeDelta.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 245933177249891519, guid: 8ebde0b07986e69419b050433d30ccd2, type: 3}
|
||||
propertyPath: openingParticleSystem
|
||||
value:
|
||||
objectReference: {fileID: 6207392896650453636}
|
||||
- target: {fileID: 498445838423597154, guid: 8ebde0b07986e69419b050433d30ccd2, type: 3}
|
||||
propertyPath: m_Name
|
||||
value: BoosterOpeningPage
|
||||
@@ -1514,6 +1518,10 @@ PrefabInstance:
|
||||
propertyPath: m_SizeDelta.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1530993938104875321, guid: 8ebde0b07986e69419b050433d30ccd2, type: 3}
|
||||
propertyPath: openingParticleSystem
|
||||
value:
|
||||
objectReference: {fileID: 6207392896650453636}
|
||||
- target: {fileID: 1670660734182863341, guid: 8ebde0b07986e69419b050433d30ccd2, type: 3}
|
||||
propertyPath: m_SizeDelta.x
|
||||
value: 0
|
||||
@@ -1618,6 +1626,10 @@ PrefabInstance:
|
||||
propertyPath: m_SizeDelta.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6433114534737680452, guid: 8ebde0b07986e69419b050433d30ccd2, type: 3}
|
||||
propertyPath: openingParticleSystem
|
||||
value:
|
||||
objectReference: {fileID: 6207392896650453636}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects: []
|
||||
@@ -1639,6 +1651,11 @@ RectTransform:
|
||||
m_CorrespondingSourceObject: {fileID: 5228380266581535650, guid: 8ebde0b07986e69419b050433d30ccd2, type: 3}
|
||||
m_PrefabInstance: {fileID: 4691000134302573506}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
--- !u!198 &6207392896650453636 stripped
|
||||
ParticleSystem:
|
||||
m_CorrespondingSourceObject: {fileID: 1674443196371304774, guid: 8ebde0b07986e69419b050433d30ccd2, type: 3}
|
||||
m_PrefabInstance: {fileID: 4691000134302573506}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
--- !u!1001 &5549612182461073321
|
||||
PrefabInstance:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
4900
Assets/Prefabs/UI/CardsSystem/VFX/VFX_ConfettiBurst_WIP.prefab
Normal file
4900
Assets/Prefabs/UI/CardsSystem/VFX/VFX_ConfettiBurst_WIP.prefab
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a04075d06f231594292595e90a69cbb1
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -174,7 +174,7 @@ namespace UI.CardSystem
|
||||
{
|
||||
// Only store and switch input mode if this is the first time entering
|
||||
// (when _previousInputMode hasn't been set yet)
|
||||
if (Input.InputManager.Instance != null && _previousInputMode == default(Input.InputMode))
|
||||
if (Input.InputManager.Instance != null)
|
||||
{
|
||||
// Store the current input mode before switching
|
||||
_previousInputMode = Input.InputMode.GameAndUI;
|
||||
|
||||
@@ -195,12 +195,29 @@ namespace UI.CardSystem
|
||||
|
||||
_currentBoosterInCenter = booster;
|
||||
|
||||
// Lock the slot so it can't be dragged out
|
||||
// Lock the slot so it can't be dragged out
|
||||
centerOpeningSlot.SetLocked(true);
|
||||
|
||||
// Enable tap-to-open and reset tap count
|
||||
booster.ResetTapCount();
|
||||
booster.SetTapToOpenEnabled(true);
|
||||
// Configure booster for opening (disables drag, enables tapping, resets tap count)
|
||||
booster.SetInOpeningSlot(true);
|
||||
|
||||
// Subscribe to tap events for visual feedback
|
||||
booster.OnTapped += OnBoosterTapped;
|
||||
booster.OnReadyToOpen += OnBoosterReadyToOpen;
|
||||
|
||||
Debug.Log($"[BoosterOpeningPage] Booster placed in center, ready for {booster.CurrentTapCount} taps");
|
||||
}
|
||||
|
||||
private void OnBoosterTapped(BoosterPackDraggable booster, int currentTaps, int maxTaps)
|
||||
{
|
||||
Debug.Log($"[BoosterOpeningPage] Booster tapped: {currentTaps}/{maxTaps}");
|
||||
|
||||
// Calculate shake intensity (increases with each tap)
|
||||
float shakeIntensity = currentTaps / (float)maxTaps;
|
||||
float shakeAmount = 10f + (shakeIntensity * 30f); // 10 to 40 units
|
||||
|
||||
// TODO: Shake visual feedback
|
||||
// This would be handled by BoosterPackVisual if we add a shake method
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -222,6 +239,10 @@ namespace UI.CardSystem
|
||||
{
|
||||
if (_isProcessingOpening) return;
|
||||
|
||||
Debug.Log($"[BoosterOpeningPage] Booster ready to open!");
|
||||
|
||||
// Trigger the actual opening sequence
|
||||
booster.TriggerOpen();
|
||||
StartCoroutine(ProcessBoosterOpening(booster));
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,11 @@ namespace UI.CardSystem.DragDrop
|
||||
[Header("Tap to Open")]
|
||||
[SerializeField] private bool canTapToOpen = true;
|
||||
[SerializeField] private int maxTapsToOpen = 3;
|
||||
[SerializeField] private float tapPulseScale = 1.15f;
|
||||
[SerializeField] private float tapPulseDuration = 0.2f;
|
||||
[SerializeField] private ParticleSystem openingParticleSystem;
|
||||
|
||||
// Events
|
||||
// ...existing code...
|
||||
public event System.Action<BoosterPackDraggable> OnBoosterOpened;
|
||||
public event System.Action<BoosterPackDraggable, int, int> OnTapped; // (booster, currentTap, maxTaps)
|
||||
public event System.Action<BoosterPackDraggable> OnReadyToOpen; // Final tap reached
|
||||
@@ -33,11 +36,30 @@ namespace UI.CardSystem.DragDrop
|
||||
{
|
||||
base.OnPointerUpHook(longPress);
|
||||
|
||||
// Handle tap-to-open logic (only when in slot and not dragged)
|
||||
if (canTapToOpen && !_wasDragged && !longPress && CurrentSlot != null)
|
||||
// Handle tap-to-open logic (only when in slot and not a long press)
|
||||
if (canTapToOpen && !longPress && CurrentSlot != null)
|
||||
{
|
||||
_currentTapCount++;
|
||||
|
||||
// Pulse effect on tap (scales visual up and back down)
|
||||
if (Visual != null)
|
||||
{
|
||||
// Calculate pulse intensity based on tap progress
|
||||
float tapProgress = _currentTapCount / (float)maxTapsToOpen;
|
||||
float currentPulseScale = 1f + (tapPulseScale - 1f) * (0.5f + tapProgress * 0.5f); // Increases from 1.075 to 1.15
|
||||
|
||||
// Save the current scale before pulsing
|
||||
Vector3 baseScale = Visual.transform.localScale;
|
||||
|
||||
Pixelplacement.Tween.Cancel(Visual.transform.GetInstanceID());
|
||||
Pixelplacement.Tween.LocalScale(Visual.transform, baseScale * currentPulseScale, tapPulseDuration * 0.5f, 0f,
|
||||
Pixelplacement.Tween.EaseOutBack, completeCallback: () =>
|
||||
{
|
||||
// Return to the base scale we had before pulsing
|
||||
Pixelplacement.Tween.LocalScale(Visual.transform, baseScale, tapPulseDuration * 0.5f, 0f, Pixelplacement.Tween.EaseInBack);
|
||||
});
|
||||
}
|
||||
|
||||
OnTapped?.Invoke(this, _currentTapCount, maxTapsToOpen);
|
||||
|
||||
if (_currentTapCount >= maxTapsToOpen)
|
||||
@@ -48,8 +70,8 @@ namespace UI.CardSystem.DragDrop
|
||||
return; // Don't process double-click if tap-to-open is active
|
||||
}
|
||||
|
||||
// Check for double click
|
||||
if (canOpenOnDoubleClick && !longPress && !_wasDragged)
|
||||
// ...existing code...
|
||||
if (canOpenOnDoubleClick && !longPress)
|
||||
{
|
||||
float timeSinceLastClick = Time.time - _lastClickTime;
|
||||
|
||||
@@ -84,6 +106,12 @@ namespace UI.CardSystem.DragDrop
|
||||
|
||||
_isOpening = true;
|
||||
|
||||
// Play particle effect
|
||||
if (openingParticleSystem != null)
|
||||
{
|
||||
openingParticleSystem.Play();
|
||||
}
|
||||
|
||||
OnBoosterOpened?.Invoke(this);
|
||||
|
||||
// The actual opening logic (calling CardSystemManager) should be handled
|
||||
@@ -98,8 +126,27 @@ namespace UI.CardSystem.DragDrop
|
||||
public void ResetOpeningState()
|
||||
{
|
||||
_isOpening = false;
|
||||
_currentTapCount = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set whether this booster is in the opening slot (disables dragging, enables tapping)
|
||||
/// </summary>
|
||||
public void SetInOpeningSlot(bool inSlot)
|
||||
{
|
||||
SetDraggingEnabled(!inSlot); // Disable dragging when in opening slot
|
||||
canTapToOpen = inSlot; // Enable tap-to-open when in opening slot
|
||||
|
||||
if (inSlot)
|
||||
{
|
||||
_currentTapCount = 0; // Reset tap counter when placed
|
||||
}
|
||||
else
|
||||
{
|
||||
ResetOpeningState(); // Reset completely when removed
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset tap count (useful when starting a new opening sequence)
|
||||
/// </summary>
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace UI.DragAndDrop.Core
|
||||
{
|
||||
[Header("Draggable Settings")]
|
||||
[SerializeField] protected float moveSpeed = 50f;
|
||||
[SerializeField] protected bool smoothMovement = true;
|
||||
[SerializeField] protected bool smoothMovement = false; // Disabled for instant cursor tracking
|
||||
[SerializeField] protected float snapDuration = 0.3f;
|
||||
|
||||
[Header("Visual")]
|
||||
@@ -36,6 +36,7 @@ namespace UI.DragAndDrop.Core
|
||||
protected bool _isHovering;
|
||||
protected bool _isSelected;
|
||||
protected bool _wasDragged;
|
||||
protected bool _isDraggingEnabled = true;
|
||||
|
||||
// References
|
||||
protected Canvas _canvas;
|
||||
@@ -87,6 +88,16 @@ namespace UI.DragAndDrop.Core
|
||||
_canvasGroup = GetComponent<CanvasGroup>();
|
||||
_raycaster = _canvas?.GetComponent<GraphicRaycaster>();
|
||||
|
||||
// If no Image component exists, add an invisible one for raycast detection
|
||||
// Unity UI requires a Graphic component to receive pointer events
|
||||
if (_imageComponent == null && _canvasGroup != null)
|
||||
{
|
||||
_imageComponent = gameObject.AddComponent<Image>();
|
||||
_imageComponent.color = new Color(1, 1, 1, 0.01f); // Nearly transparent (0 doesn't work)
|
||||
_imageComponent.raycastTarget = true;
|
||||
Debug.Log($"[DraggableObject] Added invisible Image to {name} for raycast detection");
|
||||
}
|
||||
|
||||
// Use assigned visual, or find in children recursively if not assigned
|
||||
if (visual != null)
|
||||
{
|
||||
@@ -118,25 +129,44 @@ namespace UI.DragAndDrop.Core
|
||||
SmoothMoveTowardPointer();
|
||||
}
|
||||
|
||||
ClampToScreen();
|
||||
// Only clamp for non-overlay canvases (WorldSpace/ScreenSpaceCamera)
|
||||
if (_canvas != null && _canvas.renderMode != RenderMode.ScreenSpaceOverlay)
|
||||
{
|
||||
ClampToScreen();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void SmoothMoveTowardPointer()
|
||||
{
|
||||
Vector3 targetPosition = _lastPointerPosition - _dragOffset;
|
||||
Vector3 direction = (targetPosition - transform.position).normalized;
|
||||
float distance = Vector3.Distance(transform.position, targetPosition);
|
||||
float speed = Mathf.Min(moveSpeed, distance / Time.deltaTime);
|
||||
|
||||
transform.Translate(direction * speed * Time.deltaTime, Space.World);
|
||||
if (RectTransform == null)
|
||||
return;
|
||||
|
||||
// For ScreenSpaceOverlay, work with screen/anchoredPosition
|
||||
if (_canvas != null && _canvas.renderMode == RenderMode.ScreenSpaceOverlay)
|
||||
{
|
||||
Vector2 targetPos = (Vector2)_lastPointerPosition - (Vector2)_dragOffset;
|
||||
Vector2 currentPos = RectTransform.position;
|
||||
Vector2 direction = (targetPos - currentPos).normalized;
|
||||
float distance = Vector2.Distance(currentPos, targetPos);
|
||||
float speed = Mathf.Min(moveSpeed, distance / Time.deltaTime);
|
||||
|
||||
RectTransform.position = currentPos + direction * speed * Time.deltaTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
// For WorldSpace/ScreenSpaceCamera, use world coordinates
|
||||
Vector3 targetPosition = _lastPointerPosition - _dragOffset;
|
||||
Vector3 direction = (targetPosition - transform.position).normalized;
|
||||
float distance = Vector3.Distance(transform.position, targetPosition);
|
||||
float speed = Mathf.Min(moveSpeed, distance / Time.deltaTime);
|
||||
|
||||
transform.Translate(direction * speed * Time.deltaTime, Space.World);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void ClampToScreen()
|
||||
{
|
||||
// Skip clamping for ScreenSpaceOverlay - it doesn't use world coordinates
|
||||
if (_canvas != null && _canvas.renderMode == RenderMode.ScreenSpaceOverlay)
|
||||
return;
|
||||
|
||||
// This method is only called for WorldSpace/ScreenSpaceCamera canvases
|
||||
if (Camera.main == null || RectTransform == null)
|
||||
return;
|
||||
|
||||
@@ -159,14 +189,31 @@ namespace UI.DragAndDrop.Core
|
||||
{
|
||||
if (eventData.button != PointerEventData.InputButton.Left)
|
||||
return;
|
||||
|
||||
// Check if dragging is enabled BEFORE setting any state
|
||||
if (!_isDraggingEnabled)
|
||||
return;
|
||||
|
||||
_isDragging = true;
|
||||
_wasDragged = true;
|
||||
|
||||
// Calculate offset
|
||||
Vector3 worldPointer = GetWorldPosition(eventData);
|
||||
_dragOffset = worldPointer - transform.position;
|
||||
_lastPointerPosition = worldPointer;
|
||||
// ...existing code...
|
||||
if (_canvas != null && _canvas.renderMode == RenderMode.ScreenSpaceOverlay && RectTransform != null)
|
||||
{
|
||||
// For overlay, use screen position directly
|
||||
_dragOffset = (Vector3)eventData.position - RectTransform.position;
|
||||
_lastPointerPosition = eventData.position;
|
||||
}
|
||||
else
|
||||
{
|
||||
// For WorldSpace/ScreenSpaceCamera, convert to world coords
|
||||
Vector3 worldPointer = GetWorldPosition(eventData);
|
||||
_dragOffset = worldPointer - transform.position;
|
||||
_lastPointerPosition = worldPointer;
|
||||
}
|
||||
|
||||
// Reset base rotation to identity (0°) for clean dragging
|
||||
Tween.Rotation(transform, Quaternion.identity, 0.2f, 0f, Tween.EaseOutBack);
|
||||
|
||||
// Disable raycasting to allow detecting slots underneath
|
||||
if (_raycaster != null)
|
||||
@@ -190,12 +237,25 @@ namespace UI.DragAndDrop.Core
|
||||
{
|
||||
if (!_isDragging)
|
||||
return;
|
||||
|
||||
_lastPointerPosition = GetWorldPosition(eventData);
|
||||
|
||||
if (!smoothMovement)
|
||||
// Update last pointer position based on canvas type
|
||||
if (_canvas != null && _canvas.renderMode == RenderMode.ScreenSpaceOverlay)
|
||||
{
|
||||
transform.position = _lastPointerPosition - _dragOffset;
|
||||
_lastPointerPosition = eventData.position;
|
||||
|
||||
if (!smoothMovement && RectTransform != null)
|
||||
{
|
||||
RectTransform.position = (Vector2)_lastPointerPosition - (Vector2)_dragOffset;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_lastPointerPosition = GetWorldPosition(eventData);
|
||||
|
||||
if (!smoothMovement)
|
||||
{
|
||||
transform.position = _lastPointerPosition - _dragOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,6 +277,12 @@ namespace UI.DragAndDrop.Core
|
||||
// Find closest slot and snap
|
||||
FindAndSnapToSlot();
|
||||
|
||||
// Snap base rotation back to slot rotation (if in a slot)
|
||||
if (_currentSlot != null)
|
||||
{
|
||||
Tween.Rotation(transform, _currentSlot.transform.rotation, 0.3f, 0f, Tween.EaseOutBack);
|
||||
}
|
||||
|
||||
OnDragEnded?.Invoke(this);
|
||||
OnDragEndedHook();
|
||||
|
||||
@@ -276,12 +342,18 @@ namespace UI.DragAndDrop.Core
|
||||
DraggableSlot closestSlot = null;
|
||||
float closestDistance = float.MaxValue;
|
||||
|
||||
// Use RectTransform.position for overlay, transform.position for others
|
||||
Vector3 myPosition = (_canvas != null && _canvas.renderMode == RenderMode.ScreenSpaceOverlay && RectTransform != null)
|
||||
? RectTransform.position
|
||||
: transform.position;
|
||||
|
||||
foreach (var container in containers)
|
||||
{
|
||||
DraggableSlot slot = container.FindClosestSlot(transform.position, this);
|
||||
DraggableSlot slot = container.FindClosestSlot(myPosition, this);
|
||||
if (slot != null)
|
||||
{
|
||||
float distance = Vector3.Distance(transform.position, slot.WorldPosition);
|
||||
Vector3 slotPosition = slot.RectTransform != null ? slot.RectTransform.position : slot.transform.position;
|
||||
float distance = Vector3.Distance(myPosition, slotPosition);
|
||||
if (distance < closestDistance)
|
||||
{
|
||||
closestDistance = distance;
|
||||
@@ -419,6 +491,18 @@ namespace UI.DragAndDrop.Core
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dragging Control
|
||||
|
||||
/// <summary>
|
||||
/// Enable or disable dragging functionality
|
||||
/// </summary>
|
||||
public virtual void SetDraggingEnabled(bool enabled)
|
||||
{
|
||||
_isDraggingEnabled = enabled;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper Methods
|
||||
|
||||
protected Vector3 GetWorldPosition(PointerEventData eventData)
|
||||
|
||||
@@ -89,6 +89,12 @@ namespace UI.DragAndDrop.Core
|
||||
|
||||
case OccupantSizeMode.Scale:
|
||||
Tween.LocalScale(draggable.transform, occupantScale, scaleTransitionDuration, 0f, Tween.EaseOutBack);
|
||||
|
||||
// Also scale the visual if it exists (since visual is now independent)
|
||||
if (draggable.Visual != null)
|
||||
{
|
||||
Tween.LocalScale(draggable.Visual.transform, occupantScale, scaleTransitionDuration, 0f, Tween.EaseOutBack);
|
||||
}
|
||||
break;
|
||||
|
||||
case OccupantSizeMode.None:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Pixelplacement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem; // Added for new Input System
|
||||
|
||||
namespace UI.DragAndDrop.Core
|
||||
{
|
||||
@@ -23,7 +24,7 @@ namespace UI.DragAndDrop.Core
|
||||
[Header("Rotation/Tilt Parameters")]
|
||||
[SerializeField] protected float rotationAmount = 20f;
|
||||
[SerializeField] protected float rotationSpeed = 20f;
|
||||
[SerializeField] protected float autoTiltAmount = 30f;
|
||||
[SerializeField] protected float autoTiltAmount = 10f; // Reduced from 30f
|
||||
[SerializeField] protected float manualTiltAmount = 20f;
|
||||
[SerializeField] protected float tiltSpeed = 20f;
|
||||
|
||||
@@ -35,7 +36,7 @@ namespace UI.DragAndDrop.Core
|
||||
|
||||
[Header("Idle Animation")]
|
||||
[SerializeField] protected bool useIdleAnimation = true;
|
||||
[SerializeField] protected float idleAnimationSpeed = 1f;
|
||||
[SerializeField] protected float idleAnimationSpeed = 0.5f; // Slowed down from 1f
|
||||
|
||||
// State
|
||||
protected DraggableObject _parentDraggable;
|
||||
@@ -59,6 +60,14 @@ namespace UI.DragAndDrop.Core
|
||||
Canvas parentCanvas = parent.GetComponentInParent<Canvas>();
|
||||
Debug.Log($"[DraggableVisual] Initializing visual for {parent.name} at world pos {parent.transform.position}, parent canvas: {(parentCanvas != null ? parentCanvas.name + " (renderMode: " + parentCanvas.renderMode + ")" : "NULL")}");
|
||||
|
||||
// CRITICAL: Reparent visual to canvas (not base) so it can move independently
|
||||
// This enables the delayed follow effect
|
||||
if (parentCanvas != null)
|
||||
{
|
||||
transform.SetParent(parentCanvas.transform, true); // worldPositionStays = true
|
||||
Debug.Log($"[DraggableVisual] Reparented visual {name} to canvas {parentCanvas.name} for independent movement");
|
||||
}
|
||||
|
||||
// Get components if assigned (don't auto-create Canvas to avoid Unity's auto-reparenting)
|
||||
if (canvas == null)
|
||||
canvas = GetComponent<Canvas>();
|
||||
@@ -71,11 +80,24 @@ namespace UI.DragAndDrop.Core
|
||||
// Subscribe to parent events
|
||||
SubscribeToParentEvents();
|
||||
|
||||
// Initial position
|
||||
// Initial position to match parent
|
||||
transform.position = parent.transform.position;
|
||||
_lastPosition = transform.position;
|
||||
|
||||
Debug.Log($"[DraggableVisual] Visual {name} initialized at world pos {transform.position}, local pos {transform.localPosition}, parent at world pos {parent.transform.position}, local pos {parent.transform.localPosition}");
|
||||
// Set rotation to match base's current rotation (will be maintained via separate rotation management)
|
||||
transform.rotation = parent.transform.rotation;
|
||||
|
||||
// Reset shake and tilt parent rotations to zero (local space) for clean wobble
|
||||
if (shakeParent != null)
|
||||
{
|
||||
shakeParent.localRotation = Quaternion.identity;
|
||||
}
|
||||
if (tiltParent != null)
|
||||
{
|
||||
tiltParent.localRotation = Quaternion.identity;
|
||||
}
|
||||
|
||||
Debug.Log($"[DraggableVisual] Visual {name} initialized at world pos {transform.position}, local pos {transform.localPosition}, local rotation {transform.localRotation.eulerAngles}, parent at world pos {parent.transform.position}, local pos {parent.transform.localPosition}, rotation {parent.transform.rotation.eulerAngles}");
|
||||
|
||||
_isInitialized = true;
|
||||
|
||||
@@ -116,6 +138,7 @@ namespace UI.DragAndDrop.Core
|
||||
return;
|
||||
|
||||
UpdateFollowPosition();
|
||||
UpdateFollowRotation(); // Track base rotation changes
|
||||
UpdateRotation();
|
||||
UpdateTilt();
|
||||
UpdateVisualContent();
|
||||
@@ -123,36 +146,100 @@ namespace UI.DragAndDrop.Core
|
||||
|
||||
#region Position & Movement
|
||||
|
||||
protected virtual void UpdateFollowRotation()
|
||||
{
|
||||
if (_parentDraggable == null)
|
||||
return;
|
||||
|
||||
// Smoothly follow base rotation (since we're no longer a child)
|
||||
// Base rotation changes when picking up (→ 0°) or dropping (→ slot rotation)
|
||||
transform.rotation = Quaternion.Lerp(transform.rotation, _parentDraggable.transform.rotation, 10f * Time.deltaTime);
|
||||
}
|
||||
|
||||
protected virtual void UpdateFollowPosition()
|
||||
{
|
||||
if (_parentDraggable == null)
|
||||
return;
|
||||
|
||||
Vector3 targetPosition = GetTargetPosition();
|
||||
|
||||
// Debug log if position is drastically different (likely a clustering issue)
|
||||
if (Vector3.Distance(transform.position, targetPosition) > 500f)
|
||||
{
|
||||
Debug.LogWarning($"[DraggableVisual] Large position delta detected! Visual {name} at {transform.position}, target {targetPosition}, parent {_parentDraggable.name} at {_parentDraggable.transform.position}");
|
||||
}
|
||||
// For ScreenSpaceOverlay, use RectTransform.position consistently
|
||||
Canvas parentCanvas = _parentDraggable.GetComponentInParent<Canvas>();
|
||||
bool isOverlay = parentCanvas != null && parentCanvas.renderMode == RenderMode.ScreenSpaceOverlay;
|
||||
|
||||
if (useFollowDelay)
|
||||
Vector3 targetPosition;
|
||||
Vector3 currentPosition;
|
||||
|
||||
if (isOverlay && _parentDraggable.RectTransform != null && GetComponent<RectTransform>() != null)
|
||||
{
|
||||
transform.position = Vector3.Lerp(transform.position, targetPosition, followSpeed * Time.deltaTime);
|
||||
// Use RectTransform.position for overlay (screen space)
|
||||
RectTransform myRect = GetComponent<RectTransform>();
|
||||
targetPosition = _parentDraggable.RectTransform.position;
|
||||
currentPosition = myRect.position;
|
||||
}
|
||||
else
|
||||
{
|
||||
transform.position = targetPosition;
|
||||
// Use transform.position for WorldSpace/ScreenSpaceCamera
|
||||
targetPosition = _parentDraggable.transform.position;
|
||||
currentPosition = transform.position;
|
||||
}
|
||||
|
||||
// Debug log if position is drastically different (likely a clustering issue)
|
||||
float distance = Vector3.Distance(currentPosition, targetPosition);
|
||||
if (distance > 500f)
|
||||
{
|
||||
Debug.LogWarning($"[DraggableVisual] Large position delta detected! Visual {name} at {currentPosition}, target {targetPosition}, parent {_parentDraggable.name}, distance: {distance}");
|
||||
}
|
||||
|
||||
// Apply follow logic with snappy easing
|
||||
if (useFollowDelay)
|
||||
{
|
||||
// Calculate lerp factor with snappy ease
|
||||
float rawT = followSpeed * Time.deltaTime;
|
||||
|
||||
// Apply EaseOutCubic for snappier movement: 1 - (1-t)^3
|
||||
float t = 1f - Mathf.Pow(1f - rawT, 3f);
|
||||
|
||||
Vector3 newPosition = Vector3.Lerp(currentPosition, targetPosition, t);
|
||||
|
||||
if (isOverlay && GetComponent<RectTransform>() != null)
|
||||
{
|
||||
GetComponent<RectTransform>().position = newPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
transform.position = newPosition;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isOverlay && GetComponent<RectTransform>() != null)
|
||||
{
|
||||
GetComponent<RectTransform>().position = targetPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
transform.position = targetPosition;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate movement delta for tilt
|
||||
Vector3 movement = transform.position - _lastPosition;
|
||||
Vector3 actualCurrentPos = isOverlay && GetComponent<RectTransform>() != null
|
||||
? GetComponent<RectTransform>().position
|
||||
: transform.position;
|
||||
Vector3 movement = actualCurrentPos - _lastPosition;
|
||||
_movementDelta = Vector3.Lerp(_movementDelta, movement, 25f * Time.deltaTime);
|
||||
_lastPosition = transform.position;
|
||||
_lastPosition = actualCurrentPos;
|
||||
}
|
||||
|
||||
protected virtual Vector3 GetTargetPosition()
|
||||
{
|
||||
Canvas parentCanvas = _parentDraggable.GetComponentInParent<Canvas>();
|
||||
bool isOverlay = parentCanvas != null && parentCanvas.renderMode == RenderMode.ScreenSpaceOverlay;
|
||||
|
||||
if (isOverlay && _parentDraggable.RectTransform != null)
|
||||
{
|
||||
return _parentDraggable.RectTransform.position;
|
||||
}
|
||||
|
||||
return _parentDraggable.transform.position;
|
||||
}
|
||||
|
||||
@@ -162,59 +249,93 @@ namespace UI.DragAndDrop.Core
|
||||
|
||||
protected virtual void UpdateRotation()
|
||||
{
|
||||
if (_parentDraggable == null)
|
||||
if (_parentDraggable == null || shakeParent == null)
|
||||
return;
|
||||
|
||||
// Rotation based on movement direction (like Balatro)
|
||||
Vector3 movementRotation = _parentDraggable.IsDragging
|
||||
? _movementDelta * rotationAmount
|
||||
: (_lastPosition - _parentDraggable.transform.position) * rotationAmount;
|
||||
|
||||
// Apply rotation based on movement to shakeParent (not main transform)
|
||||
// This way it's additive on top of the base rotation in transform.rotation
|
||||
// Negated to make the bottom "drag behind" instead of leading
|
||||
Vector3 movementRotation = _movementDelta * -rotationAmount; // Flipped direction
|
||||
|
||||
_rotationDelta = Vector3.Lerp(_rotationDelta, movementRotation, rotationSpeed * Time.deltaTime);
|
||||
|
||||
// Apply Z-axis rotation to shakeParent as local rotation
|
||||
float clampedZ = Mathf.Clamp(_rotationDelta.x, -60f, 60f);
|
||||
transform.eulerAngles = new Vector3(transform.eulerAngles.x, transform.eulerAngles.y, clampedZ);
|
||||
shakeParent.localEulerAngles = new Vector3(0, 0, clampedZ);
|
||||
}
|
||||
|
||||
protected virtual void UpdateTilt()
|
||||
{
|
||||
if (tiltParent == null)
|
||||
return;
|
||||
|
||||
|
||||
// Save slot index when not dragging for idle animation
|
||||
_savedSlotIndex = _parentDraggable.IsDragging
|
||||
? _savedSlotIndex
|
||||
: _parentDraggable.GetSlotIndex();
|
||||
|
||||
// Idle animation (sine/cosine wobble)
|
||||
// Idle animation (sine/cosine wobble with different frequencies)
|
||||
float idleMultiplier = _parentDraggable.IsHovering ? 0.2f : 1f;
|
||||
float time = Time.time * idleAnimationSpeed + _savedSlotIndex;
|
||||
float sineWobble = Mathf.Sin(time) * idleMultiplier;
|
||||
float cosineWobble = Mathf.Cos(time) * idleMultiplier;
|
||||
|
||||
// Use sine for X wobble, cosine for Y wobble (different phases)
|
||||
float sineWobbleX = Mathf.Sin(time) * idleMultiplier;
|
||||
float cosineWobbleY = Mathf.Cos(time) * idleMultiplier;
|
||||
|
||||
// Use slower cosine for Z rotation wobble (half speed for subtle rotation)
|
||||
float cosineWobbleZ = Mathf.Cos(time * 0.5f) * idleMultiplier * 0.3f; // Much subtler
|
||||
|
||||
// Manual tilt based on pointer position (when hovering)
|
||||
float manualTiltX = 0f;
|
||||
float manualTiltY = 0f;
|
||||
|
||||
if (_parentDraggable.IsHovering && Camera.main != null)
|
||||
if (_parentDraggable.IsHovering)
|
||||
{
|
||||
Vector3 mouseWorldPos = Camera.main.ScreenToWorldPoint(UnityEngine.Input.mousePosition);
|
||||
Vector3 offset = transform.position - mouseWorldPos;
|
||||
Canvas parentCanvas = _parentDraggable.GetComponentInParent<Canvas>();
|
||||
bool isOverlay = parentCanvas != null && parentCanvas.renderMode == RenderMode.ScreenSpaceOverlay;
|
||||
|
||||
Vector3 mousePos;
|
||||
Vector3 myPos;
|
||||
|
||||
// Get mouse position using new Input System
|
||||
Vector2 mouseScreenPos = Mouse.current != null ? Mouse.current.position.ReadValue() : Vector2.zero;
|
||||
|
||||
if (isOverlay)
|
||||
{
|
||||
// For overlay, use screen coordinates directly
|
||||
mousePos = mouseScreenPos;
|
||||
myPos = GetComponent<RectTransform>() != null
|
||||
? GetComponent<RectTransform>().position
|
||||
: transform.position;
|
||||
}
|
||||
else if (Camera.main != null)
|
||||
{
|
||||
// For WorldSpace/ScreenSpaceCamera, convert to world coords
|
||||
mousePos = Camera.main.ScreenToWorldPoint(mouseScreenPos);
|
||||
myPos = transform.position;
|
||||
}
|
||||
else
|
||||
{
|
||||
mousePos = myPos = Vector3.zero;
|
||||
}
|
||||
|
||||
Vector3 offset = myPos - mousePos;
|
||||
manualTiltX = (offset.y * -1f) * manualTiltAmount;
|
||||
manualTiltY = offset.x * manualTiltAmount;
|
||||
}
|
||||
|
||||
// Combine auto and manual tilt
|
||||
float targetTiltX = manualTiltX + (useIdleAnimation ? sineWobble * autoTiltAmount : 0f);
|
||||
float targetTiltY = manualTiltY + (useIdleAnimation ? cosineWobble * autoTiltAmount : 0f);
|
||||
float targetTiltZ = _parentDraggable.IsDragging ? tiltParent.eulerAngles.z : 0f;
|
||||
// X uses sine wobble, Y uses cosine wobble, Z uses slower cosine for rotation
|
||||
float targetTiltX = manualTiltX + (useIdleAnimation ? sineWobbleX * autoTiltAmount : 0f);
|
||||
float targetTiltY = manualTiltY + (useIdleAnimation ? cosineWobbleY * autoTiltAmount : 0f);
|
||||
float targetTiltZ = _parentDraggable.IsDragging ? tiltParent.localEulerAngles.z : (useIdleAnimation ? cosineWobbleZ * autoTiltAmount : 0f);
|
||||
|
||||
// Lerp to target tilt
|
||||
float lerpX = Mathf.LerpAngle(tiltParent.eulerAngles.x, targetTiltX, tiltSpeed * Time.deltaTime);
|
||||
float lerpY = Mathf.LerpAngle(tiltParent.eulerAngles.y, targetTiltY, tiltSpeed * Time.deltaTime);
|
||||
float lerpZ = Mathf.LerpAngle(tiltParent.eulerAngles.z, targetTiltZ, (tiltSpeed / 2f) * Time.deltaTime);
|
||||
// Lerp to target tilt using LOCAL rotation
|
||||
float lerpX = Mathf.LerpAngle(tiltParent.localEulerAngles.x, targetTiltX, tiltSpeed * Time.deltaTime);
|
||||
float lerpY = Mathf.LerpAngle(tiltParent.localEulerAngles.y, targetTiltY, tiltSpeed * Time.deltaTime);
|
||||
float lerpZ = Mathf.LerpAngle(tiltParent.localEulerAngles.z, targetTiltZ, (tiltSpeed / 2f) * Time.deltaTime);
|
||||
|
||||
tiltParent.eulerAngles = new Vector3(lerpX, lerpY, lerpZ);
|
||||
tiltParent.localEulerAngles = new Vector3(lerpX, lerpY, lerpZ);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -233,6 +354,21 @@ namespace UI.DragAndDrop.Core
|
||||
canvas.overrideSorting = true;
|
||||
}
|
||||
|
||||
// Reset shake parent rotation (movement wobble)
|
||||
if (shakeParent != null)
|
||||
{
|
||||
Tween.LocalRotation(shakeParent, Quaternion.identity, 0.2f, 0f, Tween.EaseOutBack);
|
||||
}
|
||||
|
||||
// Reset tilt parent rotation (idle wobble)
|
||||
if (tiltParent != null)
|
||||
{
|
||||
Tween.LocalRotation(tiltParent, Quaternion.identity, 0.2f, 0f, Tween.EaseOutBack);
|
||||
}
|
||||
|
||||
// Reset rotation delta for fresh movement wobble
|
||||
_rotationDelta = Vector3.zero;
|
||||
|
||||
OnDragStartedVisual();
|
||||
}
|
||||
|
||||
@@ -243,7 +379,24 @@ namespace UI.DragAndDrop.Core
|
||||
canvas.overrideSorting = false;
|
||||
}
|
||||
|
||||
Tween.LocalScale(transform, Vector3.one, scaleTransitionDuration, 0f, Tween.EaseOutBack);
|
||||
// Only reset scale if NOT in a slot (let slots handle their own scaling)
|
||||
if (draggable.CurrentSlot == null)
|
||||
{
|
||||
Tween.LocalScale(transform, Vector3.one, scaleTransitionDuration, 0f, Tween.EaseOutBack);
|
||||
}
|
||||
|
||||
|
||||
// Reset shake parent (movement wobble) to zero for fresh start
|
||||
if (shakeParent != null)
|
||||
{
|
||||
Tween.LocalRotation(shakeParent, Quaternion.identity, 0.3f, 0f, Tween.EaseOutBack);
|
||||
}
|
||||
|
||||
// Reset tilt parent (idle wobble) to zero for fresh start
|
||||
if (tiltParent != null)
|
||||
{
|
||||
Tween.LocalRotation(tiltParent, Quaternion.identity, 0.3f, 0f, Tween.EaseOutBack);
|
||||
}
|
||||
|
||||
OnDragEndedVisual();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user