From 5305c20b003dec2f18f2fe245a714ad42ee358c5 Mon Sep 17 00:00:00 2001 From: tschesky Date: Mon, 22 Sep 2025 12:16:32 +0000 Subject: [PATCH] Create a diving minigame MVP (#6) - Obstacles - Tiles - Object pooling - Monster spawns - Scoring - Minigame End Co-authored-by: Michal Pikulski Co-authored-by: AlexanderT Reviewed-on: https://homelab.tailf7f81b.ts.net/tschesky/AppleHillsProduction/pulls/6 --- Assets/Art/Textures/DivingBackground.png | Bin 0 -> 26555 bytes Assets/Art/Textures/DivingBackground.png.meta | 195 +++ Assets/Editor/DivingGameManagerEditor.cs | 48 + Assets/Editor/DivingGameManagerEditor.cs.meta | 3 + Assets/Editor/TrenchTileSpawnerEditor.cs | 42 + Assets/Editor/TrenchTileSpawnerEditor.cs.meta | 3 + .../OptimizedRope.asmdef | 3 + .../OptimizedRope.asmdef.meta | 7 + .../OptimizedRopesAndCables/Script/Rope.cs | 140 +- Assets/Playables.meta | 8 + Assets/Playables/SurfacingTimeline.playable | 1248 +++++++++++++++++ .../Playables/SurfacingTimeline.playable.meta | 8 + .../Scenes/MiniGames/DivingForPictures.unity | 434 +++++- Assets/Scripts/AppleHillsScripts.asmdef | 3 +- .../DivingForPictures/BubbleSpawner.cs | 37 +- .../DivingForPictures/DivingGameManager.cs | 422 ++++++ .../DivingForPictures/FloatingObstacle.cs | 60 +- .../DivingForPictures/ObstacleSpawner.cs | 112 +- .../DivingForPictures/RopeBreaker.cs | 331 +++++ .../DivingForPictures/RopeBreaker.cs.meta | 3 + .../RopeEndPhysicsFollower.cs | 306 ++++ .../RopeEndPhysicsFollower.cs.meta | 3 + .../DivingForPictures/TrenchTileSpawner.cs | 214 ++- ProjectSettings/TagManager.asset | 1 + 24 files changed, 3466 insertions(+), 165 deletions(-) create mode 100644 Assets/Art/Textures/DivingBackground.png create mode 100644 Assets/Art/Textures/DivingBackground.png.meta create mode 100644 Assets/Editor/DivingGameManagerEditor.cs create mode 100644 Assets/Editor/DivingGameManagerEditor.cs.meta create mode 100644 Assets/Editor/TrenchTileSpawnerEditor.cs create mode 100644 Assets/Editor/TrenchTileSpawnerEditor.cs.meta create mode 100644 Assets/External/OptimizedRopesAndCables/OptimizedRope.asmdef create mode 100644 Assets/External/OptimizedRopesAndCables/OptimizedRope.asmdef.meta create mode 100644 Assets/Playables.meta create mode 100644 Assets/Playables/SurfacingTimeline.playable create mode 100644 Assets/Playables/SurfacingTimeline.playable.meta create mode 100644 Assets/Scripts/Minigames/DivingForPictures/RopeBreaker.cs create mode 100644 Assets/Scripts/Minigames/DivingForPictures/RopeBreaker.cs.meta create mode 100644 Assets/Scripts/Minigames/DivingForPictures/RopeEndPhysicsFollower.cs create mode 100644 Assets/Scripts/Minigames/DivingForPictures/RopeEndPhysicsFollower.cs.meta diff --git a/Assets/Art/Textures/DivingBackground.png b/Assets/Art/Textures/DivingBackground.png new file mode 100644 index 0000000000000000000000000000000000000000..8b0a5782adc891abce199d7fcf67ae979e5cb3fd GIT binary patch literal 26555 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 H_Rs$VN)c~` literal 0 HcmV?d00001 diff --git a/Assets/Art/Textures/DivingBackground.png.meta b/Assets/Art/Textures/DivingBackground.png.meta new file mode 100644 index 00000000..b080923e --- /dev/null +++ b/Assets/Art/Textures/DivingBackground.png.meta @@ -0,0 +1,195 @@ +fileFormatVersion: 2 +guid: ad9b785acb09cb247ae2c8cd895863de +TextureImporter: + internalIDToNameTable: + - first: + 213: 5958968447627082961 + second: DivingBackground_0 + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 2 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: iOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: WindowsStoreApps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: DivingBackground_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1080 + height: 1981 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 1dcb29c2b3282b250800000000000000 + internalID: 5958968447627082961 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + DivingBackground_0: 5958968447627082961 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Editor/DivingGameManagerEditor.cs b/Assets/Editor/DivingGameManagerEditor.cs new file mode 100644 index 00000000..53bde798 --- /dev/null +++ b/Assets/Editor/DivingGameManagerEditor.cs @@ -0,0 +1,48 @@ +using UnityEditor; +using UnityEngine; +using Minigames.DivingForPictures; + +/// +/// Custom editor for DivingGameManager that adds runtime buttons for testing surfacing and other functionality +/// +[CustomEditor(typeof(DivingGameManager))] +public class DivingGameManagerEditor : UnityEditor.Editor +{ + public override void OnInspectorGUI() + { + // Draw the default inspector + DrawDefaultInspector(); + + // Get the target DivingGameManager + DivingGameManager manager = (DivingGameManager)target; + + // Add space between default inspector and custom buttons + EditorGUILayout.Space(10); + + // Separator line + EditorGUILayout.LabelField("", GUI.skin.horizontalSlider); + + // Add a label for the runtime testing section + EditorGUILayout.LabelField("Runtime Testing", EditorStyles.boldLabel); + + // Only enable the buttons during play mode + EditorGUI.BeginDisabledGroup(!Application.isPlaying); + + // Add the button to call StartSurfacing + if (GUILayout.Button("Start Surfacing", GUILayout.Height(30))) + { + manager.StartSurfacing(); + } + + // Add a button for breaking a rope (for testing damage) + if (GUILayout.Button("Break Rope (Test Damage)", GUILayout.Height(30))) + { + manager.ForceBreakRope(); + } + + EditorGUI.EndDisabledGroup(); + + // Add explanatory text + EditorGUILayout.HelpBox("These buttons only work in Play Mode. 'Start Surfacing' will reverse the trench direction, slow bubbles, and reverse obstacles. 'Break Rope' simulates player taking damage.", MessageType.Info); + } +} diff --git a/Assets/Editor/DivingGameManagerEditor.cs.meta b/Assets/Editor/DivingGameManagerEditor.cs.meta new file mode 100644 index 00000000..cde212bf --- /dev/null +++ b/Assets/Editor/DivingGameManagerEditor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8bbb340d8d9b4af581770757e86cc1f8 +timeCreated: 1758532258 \ No newline at end of file diff --git a/Assets/Editor/TrenchTileSpawnerEditor.cs b/Assets/Editor/TrenchTileSpawnerEditor.cs new file mode 100644 index 00000000..1178e8ad --- /dev/null +++ b/Assets/Editor/TrenchTileSpawnerEditor.cs @@ -0,0 +1,42 @@ +using UnityEditor; +using UnityEngine; +using Minigames.DivingForPictures; + +/// +/// Custom editor for TrenchTileSpawner that adds a runtime button to test the StartSurfacing function +/// +[CustomEditor(typeof(TrenchTileSpawner))] +public class TrenchTileSpawnerEditor : UnityEditor.Editor +{ + public override void OnInspectorGUI() + { + // Draw the default inspector + DrawDefaultInspector(); + + // Get the target TrenchTileSpawner + TrenchTileSpawner spawner = (TrenchTileSpawner)target; + + // Add space between default inspector and custom button + EditorGUILayout.Space(10); + + // Separator line + EditorGUILayout.LabelField("", GUI.skin.horizontalSlider); + + // Add a label for the runtime testing section + EditorGUILayout.LabelField("Runtime Testing", EditorStyles.boldLabel); + + // Only enable the button during play mode + EditorGUI.BeginDisabledGroup(!Application.isPlaying); + + // Add the button to call StartSurfacing + if (GUILayout.Button("Start Surfacing", GUILayout.Height(30))) + { + spawner.StartSurfacing(); + } + + EditorGUI.EndDisabledGroup(); + + // Add explanatory text + EditorGUILayout.HelpBox("This button will reverse the direction of the trench movement, making the player surface instead of descend. Only works in Play Mode.", MessageType.Info); + } +} diff --git a/Assets/Editor/TrenchTileSpawnerEditor.cs.meta b/Assets/Editor/TrenchTileSpawnerEditor.cs.meta new file mode 100644 index 00000000..99db4891 --- /dev/null +++ b/Assets/Editor/TrenchTileSpawnerEditor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9fb1a138e45d4720ba5c95da894b4491 +timeCreated: 1758531024 \ No newline at end of file diff --git a/Assets/External/OptimizedRopesAndCables/OptimizedRope.asmdef b/Assets/External/OptimizedRopesAndCables/OptimizedRope.asmdef new file mode 100644 index 00000000..ad3635d4 --- /dev/null +++ b/Assets/External/OptimizedRopesAndCables/OptimizedRope.asmdef @@ -0,0 +1,3 @@ +{ + "name": "OptimizedRope" +} diff --git a/Assets/External/OptimizedRopesAndCables/OptimizedRope.asmdef.meta b/Assets/External/OptimizedRopesAndCables/OptimizedRope.asmdef.meta new file mode 100644 index 00000000..ae3e171c --- /dev/null +++ b/Assets/External/OptimizedRopesAndCables/OptimizedRope.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f7c43f01316c63c43a8b70a1dd6bdfac +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/External/OptimizedRopesAndCables/Script/Rope.cs b/Assets/External/OptimizedRopesAndCables/Script/Rope.cs index 4ed753da..91853ad7 100644 --- a/Assets/External/OptimizedRopesAndCables/Script/Rope.cs +++ b/Assets/External/OptimizedRopesAndCables/Script/Rope.cs @@ -75,8 +75,20 @@ namespace GogoGaga.OptimizedRopesAndCables public bool IsPrefab => gameObject.scene.rootCount == 0; - private void Start() + // Track initialization state + private bool isInitialized = false; + + /// + /// Public method to explicitly initialize the rope. + /// Call this after setting up endpoints if creating ropes at runtime. + /// + /// True if initialization was successful, false otherwise + public bool Initialize() { + // Skip if already initialized + if (isInitialized) + return true; + InitializeLineRenderer(); if (AreEndPointsValid()) { @@ -84,7 +96,17 @@ namespace GogoGaga.OptimizedRopesAndCables targetValue = currentValue; currentVelocity = Vector3.zero; SetSplinePoint(); // Ensure initial spline point is set correctly + isInitialized = true; + return true; } + + return false; + } + + private void Start() + { + // Use the same initialization method to avoid code duplication + Initialize(); } private void OnValidate() @@ -208,15 +230,62 @@ namespace GogoGaga.OptimizedRopesAndCables return point; } - public Vector3 GetPointAt(float t) + /// + /// Set the start point of the rope + /// + public void SetStartPoint(Transform newStartPoint, bool recalculateRope = false) { - if (!AreEndPointsValid()) - { - Debug.LogError("StartPoint or EndPoint is not assigned.", gameObject); - return Vector3.zero; - } + startPoint = newStartPoint; + if (recalculateRope) + RecalculateRope(); + } - return GetRationalBezierPoint(startPoint.position, currentValue, endPoint.position, t, StartPointWeight, midPointWeight, EndPointWeight); + /// + /// Set the end point of the rope + /// + public void SetEndPoint(Transform newEndPoint, bool recalculateRope = false) + { + endPoint = newEndPoint; + if (recalculateRope) + RecalculateRope(); + } + + /// + /// Set the mid point of the rope + /// + public void SetMidPoint(Transform newMidPoint, bool recalculateRope = false) + { + midPoint = newMidPoint; + if (recalculateRope) + RecalculateRope(); + } + + /// + /// Get a point along the rope at the specified position (0-1) + /// + public Vector3 GetPointAt(float position) + { + position = Mathf.Clamp01(position); + Vector3 mid = GetMidPoint(); + return GetRationalBezierPoint(startPoint.position, mid, endPoint.position, position, StartPointWeight, midPointWeight, EndPointWeight); + } + + /// + /// Force recalculation of the rope + /// + public void RecalculateRope() + { + if (!isInitialized) + { + Initialize(); + } + + if (AreEndPointsValid()) + { + SetSplinePoint(); + SimulatePhysics(); + NotifyPointsChanged(); + } } private void FixedUpdate() @@ -262,61 +331,6 @@ namespace GogoGaga.OptimizedRopesAndCables // Gizmos.DrawSphere(midPos, 0.2f); } - // New API methods for setting start and end points - // with instantAssign parameter to recalculate the rope immediately, without - // animating the rope to the new position. - // When newStartPoint or newEndPoint is null, the rope will be recalculated immediately - - public void SetStartPoint(Transform newStartPoint, bool instantAssign = false) - { - startPoint = newStartPoint; - prevStartPointPosition = startPoint == null ? Vector3.zero : startPoint.position; - - if (instantAssign || newStartPoint == null) - { - RecalculateRope(); - } - - NotifyPointsChanged(); - } - public void SetMidPoint(Transform newMidPoint, bool instantAssign = false) - { - midPoint = newMidPoint; - prevMidPointPosition = midPoint == null ? 0.5f : midPointPosition; - - if (instantAssign || newMidPoint == null) - { - RecalculateRope(); - } - NotifyPointsChanged(); - } - - public void SetEndPoint(Transform newEndPoint, bool instantAssign = false) - { - endPoint = newEndPoint; - prevEndPointPosition = endPoint == null ? Vector3.zero : endPoint.position; - - if (instantAssign || newEndPoint == null) - { - RecalculateRope(); - } - - NotifyPointsChanged(); - } - - public void RecalculateRope() - { - if (!AreEndPointsValid()) - { - lineRenderer.positionCount = 0; - return; - } - - currentValue = GetMidPoint(); - targetValue = currentValue; - currentVelocity = Vector3.zero; - SetSplinePoint(); - } private void NotifyPointsChanged() { diff --git a/Assets/Playables.meta b/Assets/Playables.meta new file mode 100644 index 00000000..f6a6ecf6 --- /dev/null +++ b/Assets/Playables.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2c0088270c13b3a4e8ce04a3f672887d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Playables/SurfacingTimeline.playable b/Assets/Playables/SurfacingTimeline.playable new file mode 100644 index 00000000..1138b302 --- /dev/null +++ b/Assets/Playables/SurfacingTimeline.playable @@ -0,0 +1,1248 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-4039891455399305819 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (2) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: [] + m_Clips: [] + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 1 + m_InfiniteClipPostExtrapolation: 1 + m_InfiniteClipOffsetPosition: {x: 0, y: 0, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: 0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: -1120528782975220419} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!74 &-3085705704792956194 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Recorded (1) + serializedVersion: 7 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.95 + value: {x: 0, y: 0.60010004, z: 0} + inSlope: {x: 0, y: 0, z: 0} + outSlope: {x: 0, y: 0, z: 0} + tangentMode: 0 + weightedMode: 0 + inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + - serializedVersion: 3 + time: 1.0833334 + value: {x: 0, y: 0.16010022, z: 0} + inSlope: {x: 0, y: -3.2999988, z: 0} + outSlope: {x: 0, y: -3.2999988, z: 0} + tangentMode: 0 + weightedMode: 0 + inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + - serializedVersion: 3 + time: 1.4833333 + value: {x: 0, y: -3.8999, z: 0} + inSlope: {x: 0, y: 0, z: 0} + outSlope: {x: 0, y: 0, z: 0} + tangentMode: 0 + weightedMode: 0 + inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + - serializedVersion: 3 + time: 1.7 + value: {x: 0, y: -3.3298998, z: 0} + inSlope: {x: 0, y: 0, z: 0} + outSlope: {x: 0, y: 0, z: 0} + tangentMode: 0 + weightedMode: 0 + inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + - serializedVersion: 3 + time: 1.9833333 + value: {x: 0, y: -4.5899, z: 0} + inSlope: {x: 0, y: 0, z: 0} + outSlope: {x: 0, y: 0, z: 0} + tangentMode: 0 + weightedMode: 0 + inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + - serializedVersion: 3 + time: 2.3166666 + value: {x: 0, y: -3.7998998, z: 0} + inSlope: {x: 0, y: 0, z: 0} + outSlope: {x: 0, y: 0, z: 0} + tangentMode: 0 + weightedMode: 0 + inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + - serializedVersion: 3 + time: 2.5833333 + value: {x: 0, y: -4.6099, z: 0} + inSlope: {x: 0, y: 0, z: 0} + outSlope: {x: 0, y: 0, z: 0} + tangentMode: 0 + weightedMode: 0 + inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + - serializedVersion: 3 + time: 2.8166666 + value: {x: 0, y: -4.0298996, z: 0} + inSlope: {x: 0, y: 0, z: 0} + outSlope: {x: 0, y: 0, z: 0} + tangentMode: 0 + weightedMode: 0 + inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + path: + m_ScaleCurves: [] + m_FloatCurves: + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.95 + value: 0 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Enabled + path: + classID: 114 + script: {fileID: 11500000, guid: d39dbaae819c4a128a11ca60fbbc98c9, type: 3} + flags: 0 + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.95 + value: 0 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Enabled + path: + classID: 114 + script: {fileID: 11500000, guid: 9072050a53fc4b539f4f4716bab53c07, type: 3} + flags: 0 + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.95 + value: 0 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Enabled + path: + classID: 114 + script: {fileID: 11500000, guid: 8222f0e3aeeb4fc4975aaead6cf7afbe, type: 3} + flags: 0 + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.95 + value: 0 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Enabled + path: + classID: 114 + script: {fileID: 11500000, guid: c9c18dbd013d42ae8c221e6205e4d49c, type: 3} + flags: 0 + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.95 + value: 0 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Enabled + path: + classID: 114 + script: {fileID: 11500000, guid: d8ea29cc80524de8affe17b930cd75c1, type: 3} + flags: 0 + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.95 + value: 0 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Enabled + path: + classID: 60 + script: {fileID: 0} + flags: 0 + m_PPtrCurves: [] + m_SampleRate: 60 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 1 + script: {fileID: 0} + typeID: 4 + customType: 0 + isPPtrCurve: 0 + isIntCurve: 0 + isSerializeReferenceCurve: 0 + - serializedVersion: 2 + path: 0 + attribute: 3305885265 + script: {fileID: 11500000, guid: d39dbaae819c4a128a11ca60fbbc98c9, type: 3} + typeID: 114 + customType: 24 + isPPtrCurve: 0 + isIntCurve: 0 + isSerializeReferenceCurve: 0 + - serializedVersion: 2 + path: 0 + attribute: 3305885265 + script: {fileID: 11500000, guid: 9072050a53fc4b539f4f4716bab53c07, type: 3} + typeID: 114 + customType: 24 + isPPtrCurve: 0 + isIntCurve: 0 + isSerializeReferenceCurve: 0 + - serializedVersion: 2 + path: 0 + attribute: 3305885265 + script: {fileID: 11500000, guid: 8222f0e3aeeb4fc4975aaead6cf7afbe, type: 3} + typeID: 114 + customType: 24 + isPPtrCurve: 0 + isIntCurve: 0 + isSerializeReferenceCurve: 0 + - serializedVersion: 2 + path: 0 + attribute: 3305885265 + script: {fileID: 11500000, guid: c9c18dbd013d42ae8c221e6205e4d49c, type: 3} + typeID: 114 + customType: 24 + isPPtrCurve: 0 + isIntCurve: 0 + isSerializeReferenceCurve: 0 + - serializedVersion: 2 + path: 0 + attribute: 3305885265 + script: {fileID: 11500000, guid: d8ea29cc80524de8affe17b930cd75c1, type: 3} + typeID: 114 + customType: 24 + isPPtrCurve: 0 + isIntCurve: 0 + isSerializeReferenceCurve: 0 + - serializedVersion: 2 + path: 0 + attribute: 3305885265 + script: {fileID: 0} + typeID: 60 + customType: 0 + isPPtrCurve: 0 + isIntCurve: 0 + isSerializeReferenceCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 2.8166666 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.95 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.0833334 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.4833333 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.7 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.9833333 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 2.3166666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 2.5833333 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 2.8166666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_LocalPosition.x + path: + classID: 4 + script: {fileID: 0} + flags: 0 + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.95 + value: 0.60010004 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.0833334 + value: 0.16010022 + inSlope: -3.2999988 + outSlope: -3.2999988 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.4833333 + value: -3.8999 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.7 + value: -3.3298998 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.9833333 + value: -4.5899 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 2.3166666 + value: -3.7998998 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 2.5833333 + value: -4.6099 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 2.8166666 + value: -4.0298996 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_LocalPosition.y + path: + classID: 4 + script: {fileID: 0} + flags: 0 + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.95 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.0833334 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.4833333 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.7 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.9833333 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 2.3166666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 2.5833333 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 2.8166666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_LocalPosition.z + path: + classID: 4 + script: {fileID: 0} + flags: 0 + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.95 + value: 0 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Enabled + path: + classID: 114 + script: {fileID: 11500000, guid: d39dbaae819c4a128a11ca60fbbc98c9, type: 3} + flags: 0 + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.95 + value: 0 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Enabled + path: + classID: 114 + script: {fileID: 11500000, guid: 9072050a53fc4b539f4f4716bab53c07, type: 3} + flags: 0 + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.95 + value: 0 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Enabled + path: + classID: 114 + script: {fileID: 11500000, guid: 8222f0e3aeeb4fc4975aaead6cf7afbe, type: 3} + flags: 0 + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.95 + value: 0 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Enabled + path: + classID: 114 + script: {fileID: 11500000, guid: c9c18dbd013d42ae8c221e6205e4d49c, type: 3} + flags: 0 + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.95 + value: 0 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Enabled + path: + classID: 114 + script: {fileID: 11500000, guid: d8ea29cc80524de8affe17b930cd75c1, type: 3} + flags: 0 + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 0.95 + value: 0 + inSlope: Infinity + outSlope: Infinity + tangentMode: 103 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_Enabled + path: + classID: 60 + script: {fileID: 0} + flags: 0 + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 1 + m_HasMotionFloatCurves: 0 + m_Events: [] +--- !u!74 &-1120528782975220419 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Recorded (2) + serializedVersion: 7 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 1 + value: 6.75 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 2.8166666 + value: 3 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: Lens.OrthographicSize + path: + classID: 114 + script: {fileID: 11500000, guid: f9dfa5b682dcd46bda6128250e975f58, type: 3} + flags: 0 + m_PPtrCurves: [] + m_SampleRate: 60 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 2514370844 + script: {fileID: 11500000, guid: f9dfa5b682dcd46bda6128250e975f58, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 0 + isIntCurve: 0 + isSerializeReferenceCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 2.8166666 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 1 + value: 6.75 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 2.8166666 + value: 3 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: Lens.OrthographicSize + path: + classID: 114 + script: {fileID: 11500000, guid: f9dfa5b682dcd46bda6128250e975f58, type: 3} + flags: 0 + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bfda56da833e2384a9677cd3c976a436, type: 3} + m_Name: SurfacingTimeline + m_EditorClassIdentifier: + m_Version: 0 + m_Tracks: + - {fileID: 7536617106820686252} + - {fileID: 1284158391674687369} + - {fileID: -4039891455399305819} + m_FixedDuration: 0 + m_EditorSettings: + m_Framerate: 60 + m_ScenePreview: 1 + m_DurationMode: 0 + m_MarkerTrack: {fileID: 0} +--- !u!114 &1284158391674687369 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track (1) + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: [] + m_Clips: [] + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 1 + m_InfiniteClipPostExtrapolation: 1 + m_InfiniteClipOffsetPosition: {x: 0, y: 1.24, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: -0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: 3844679312356863604} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 +--- !u!74 &3844679312356863604 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Recorded + serializedVersion: 7 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: {x: 0, y: 0, z: 0} + inSlope: {x: 0, y: 0, z: 0} + outSlope: {x: 0, y: 0, z: 0} + tangentMode: 0 + weightedMode: 0 + inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + - serializedVersion: 3 + time: 1.8333334 + value: {x: 0, y: -9.16, z: 0} + inSlope: {x: 0, y: 0, z: 0} + outSlope: {x: 0, y: 0, z: 0} + tangentMode: 0 + weightedMode: 0 + inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + path: + m_ScaleCurves: [] + m_FloatCurves: [] + m_PPtrCurves: [] + m_SampleRate: 60 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 1 + script: {fileID: 0} + typeID: 4 + customType: 0 + isPPtrCurve: 0 + isIntCurve: 0 + isSerializeReferenceCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 1.8333334 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.8333334 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_LocalPosition.x + path: + classID: 4 + script: {fileID: 0} + flags: 0 + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.8333334 + value: -9.16 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_LocalPosition.y + path: + classID: 4 + script: {fileID: 0} + flags: 0 + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.8333334 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_LocalPosition.z + path: + classID: 4 + script: {fileID: 0} + flags: 0 + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 1 + m_HasMotionFloatCurves: 0 + m_Events: [] +--- !u!114 &7536617106820686252 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d21dcc2386d650c4597f3633c75a1f98, type: 3} + m_Name: Animation Track + m_EditorClassIdentifier: + m_Version: 3 + m_AnimClip: {fileID: 0} + m_Locked: 0 + m_Muted: 0 + m_CustomPlayableFullTypename: + m_Curves: {fileID: 0} + m_Parent: {fileID: 11400000} + m_Children: [] + m_Clips: [] + m_Markers: + m_Objects: [] + m_InfiniteClipPreExtrapolation: 1 + m_InfiniteClipPostExtrapolation: 1 + m_InfiniteClipOffsetPosition: {x: 0, y: 2.9799, z: 0} + m_InfiniteClipOffsetEulerAngles: {x: -0, y: 0, z: 0} + m_InfiniteClipTimeOffset: 0 + m_InfiniteClipRemoveOffset: 0 + m_InfiniteClipApplyFootIK: 1 + mInfiniteClipLoop: 0 + m_MatchTargetFields: 63 + m_Position: {x: 0, y: 0, z: 0} + m_EulerAngles: {x: 0, y: 0, z: 0} + m_AvatarMask: {fileID: 0} + m_ApplyAvatarMask: 1 + m_TrackOffset: 0 + m_InfiniteClip: {fileID: -3085705704792956194} + m_OpenClipOffsetRotation: {x: 0, y: 0, z: 0, w: 1} + m_Rotation: {x: 0, y: 0, z: 0, w: 1} + m_ApplyOffsets: 0 diff --git a/Assets/Playables/SurfacingTimeline.playable.meta b/Assets/Playables/SurfacingTimeline.playable.meta new file mode 100644 index 00000000..7f454016 --- /dev/null +++ b/Assets/Playables/SurfacingTimeline.playable.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5ecd3cfdb172df5439e4522c15c48f75 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/MiniGames/DivingForPictures.unity b/Assets/Scenes/MiniGames/DivingForPictures.unity index 36a7fbf4..8ea86f34 100644 --- a/Assets/Scenes/MiniGames/DivingForPictures.unity +++ b/Assets/Scenes/MiniGames/DivingForPictures.unity @@ -248,6 +248,7 @@ GameObject: - component: {fileID: 173052725} - component: {fileID: 173052727} - component: {fileID: 173052726} + - component: {fileID: 173052728} m_Layer: 0 m_Name: Rope2 m_TagString: Untagged @@ -339,15 +340,15 @@ LineRenderer: m_SortingOrder: 0 m_Positions: - {x: 0, y: 4.1716814, z: 0} - - {x: -0.0011514801, y: 3.9187107, z: 0} - - {x: -0.00230296, y: 3.6922278, z: 0} - - {x: -0.0034544398, y: 3.4922323, z: 0} - - {x: -0.00460592, y: 3.3187256, z: 0} - - {x: -0.0057574, y: 3.1717062, z: 0} - - {x: -0.0069088796, y: 3.0511749, z: 0} - - {x: -0.008060359, y: 2.9571314, z: 0} - - {x: -0.00921184, y: 2.8895762, z: 0} - - {x: -0.010363319, y: 2.8485086, z: 0} + - {x: -0.0011514801, y: 3.9551861, z: 0} + - {x: -0.00230296, y: 3.757073, z: 0} + - {x: -0.0034544398, y: 3.577342, z: 0} + - {x: -0.00460592, y: 3.4159937, z: 0} + - {x: -0.0057574, y: 3.273027, z: 0} + - {x: -0.0069088796, y: 3.1484427, z: 0} + - {x: -0.008060359, y: 3.042241, z: 0} + - {x: -0.00921184, y: 2.9544215, z: 0} + - {x: -0.010363319, y: 2.884984, z: 0} - {x: -0.0115148, y: 2.833929, z: 0} m_Parameters: serializedVersion: 3 @@ -417,6 +418,28 @@ LineRenderer: m_UseWorldSpace: 1 m_Loop: 0 m_ApplyActiveColorSpace: 1 +--- !u!114 &173052728 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 173052724} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 30919200017f4879867c3b6289429924, type: 3} + m_Name: + m_EditorClassIdentifier: + breakPosition: 0.5 + breakEffect: {fileID: 0} + breakSound: {fileID: 0} + ropeFollowSpeed: 5 + ropeTrailing: 0.2 + ropeGravityStrength: 9.8 + ropeVerticalHangStrength: 2 + ropeDamping: 0.3 + initialSeparationDistance: 0.1 + initialFallImpulse: 2 --- !u!1 &224729330 GameObject: m_ObjectHideFlags: 0 @@ -427,6 +450,7 @@ GameObject: m_Component: - component: {fileID: 224729333} - component: {fileID: 224729332} + - component: {fileID: 224729334} m_Layer: 0 m_Name: CinemachineCamera m_TagString: Untagged @@ -492,6 +516,28 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!95 &224729334 +Animator: + serializedVersion: 7 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 224729330} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 0} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_AnimatePhysics: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 + m_WriteDefaultValuesOnDisable: 0 --- !u!1 &323864663 GameObject: m_ObjectHideFlags: 0 @@ -600,6 +646,14 @@ MonoBehaviour: spawnCooldown: 5 basePoints: 10 depthMultiplier: 2 + playerRopes: + - {fileID: 1435210811} + - {fileID: 1062017697} + - {fileID: 173052728} + speedTransitionDuration: 2 + surfacingSpeedFactor: 3 + surfacingSpawnDelay: 3 + surfacingTimeline: {fileID: 2064311130} --- !u!4 &424805726 Transform: m_ObjectHideFlags: 0 @@ -615,6 +669,116 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &461301695 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 461301697} + - component: {fileID: 461301696} + - component: {fileID: 461301698} + m_Layer: 0 + m_Name: DivingBackground_0 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!212 &461301696 +SpriteRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 461301695} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 0 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 0 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 622133659 + m_SortingLayer: -1 + m_SortingOrder: 0 + m_Sprite: {fileID: 5958968447627082961, guid: ad9b785acb09cb247ae2c8cd895863de, type: 3} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_FlipX: 0 + m_FlipY: 0 + m_DrawMode: 0 + m_Size: {x: 10.803711, y: 19.81} + m_AdaptiveModeThreshold: 0.5 + m_SpriteTileMode: 0 + m_WasSpriteAssigned: 1 + m_MaskInteraction: 0 + m_SpriteSortPoint: 0 +--- !u!4 &461301697 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 461301695} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1.24, z: 0} + m_LocalScale: {x: 0.81438, y: 0.81438, z: 0.81438} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!95 &461301698 +Animator: + serializedVersion: 7 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 461301695} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 0} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_AnimatePhysics: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 + m_WriteDefaultValuesOnDisable: 0 --- !u!1 &730962732 GameObject: m_ObjectHideFlags: 0 @@ -718,6 +882,7 @@ GameObject: - component: {fileID: 747976402} - component: {fileID: 747976403} - component: {fileID: 747976404} + - component: {fileID: 747976405} m_Layer: 0 m_Name: BottleMarine m_TagString: Player @@ -948,6 +1113,28 @@ MonoBehaviour: blinkRate: 0.15 damageColorAlpha: 0.7 targetSpriteRenderer: {fileID: 730962734} +--- !u!95 &747976405 +Animator: + serializedVersion: 7 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 747976396} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 0} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_AnimatePhysics: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 + m_WriteDefaultValuesOnDisable: 0 --- !u!1 &824396214 GameObject: m_ObjectHideFlags: 0 @@ -1076,6 +1263,7 @@ MonoBehaviour: useObjectPooling: 1 initialPoolSize: 10 maxPoolSize: 30 + surfacingSpeedFactor: 0.5 --- !u!4 &1003335105 Transform: m_ObjectHideFlags: 0 @@ -1102,6 +1290,7 @@ GameObject: - component: {fileID: 1062017694} - component: {fileID: 1062017696} - component: {fileID: 1062017695} + - component: {fileID: 1062017697} m_Layer: 0 m_Name: Rope3 m_TagString: Untagged @@ -1193,15 +1382,15 @@ LineRenderer: m_SortingOrder: 0 m_Positions: - {x: 0, y: 4.1716814, z: 0} - - {x: 0.036271624, y: 3.927396, z: 0} - - {x: 0.07254324, y: 3.7076683, z: 0} - - {x: 0.10881486, y: 3.5124984, z: 0} - - {x: 0.14508648, y: 3.3418865, z: 0} - - {x: 0.1813581, y: 3.195832, z: 0} - - {x: 0.21762972, y: 3.0743358, z: 0} - - {x: 0.25390133, y: 2.9773972, z: 0} - - {x: 0.29017296, y: 2.905017, z: 0} - - {x: 0.32644457, y: 2.857194, z: 0} + - {x: 0.036271624, y: 3.9653695, z: 0} + - {x: 0.07254324, y: 3.7751768, z: 0} + - {x: 0.10881486, y: 3.6011028, z: 0} + - {x: 0.14508648, y: 3.443149, z: 0} + - {x: 0.1813581, y: 3.3013139, z: 0} + - {x: 0.21762972, y: 3.1755984, z: 0} + - {x: 0.25390133, y: 3.066002, z: 0} + - {x: 0.29017296, y: 2.9725251, z: 0} + - {x: 0.32644457, y: 2.8951674, z: 0} - {x: 0.3627162, y: 2.833929, z: 0} m_Parameters: serializedVersion: 3 @@ -1271,6 +1460,28 @@ LineRenderer: m_UseWorldSpace: 1 m_Loop: 0 m_ApplyActiveColorSpace: 1 +--- !u!114 &1062017697 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1062017693} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 30919200017f4879867c3b6289429924, type: 3} + m_Name: + m_EditorClassIdentifier: + breakPosition: 0.5 + breakEffect: {fileID: 0} + breakSound: {fileID: 0} + ropeFollowSpeed: 5 + ropeTrailing: 0.2 + ropeGravityStrength: 9.8 + ropeVerticalHangStrength: 2 + ropeDamping: 0.3 + initialSeparationDistance: 0.1 + initialFallImpulse: 2 --- !u!1 &1063641111 GameObject: m_ObjectHideFlags: 0 @@ -1283,6 +1494,7 @@ GameObject: - component: {fileID: 1063641113} - component: {fileID: 1063641112} - component: {fileID: 1063641115} + - component: {fileID: 1063641116} m_Layer: 0 m_Name: Main Camera m_TagString: MainCamera @@ -1307,8 +1519,8 @@ Camera: m_GameObject: {fileID: 1063641111} m_Enabled: 1 serializedVersion: 2 - m_ClearFlags: 1 - m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_ClearFlags: 2 + m_BackGroundColor: {r: 0.5722232, g: 0.6321867, b: 0.7264151, a: 0} m_projectionMatrixMode: 1 m_GateFitMode: 2 m_FOVAxisMode: 0 @@ -1396,6 +1608,50 @@ MonoBehaviour: m_PostInfinity: 2 m_RotationOrder: 4 CustomBlends: {fileID: 0} +--- !u!114 &1063641116 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1063641111} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_RenderShadows: 1 + m_RequiresDepthTextureOption: 2 + m_RequiresOpaqueTextureOption: 2 + m_CameraType: 0 + m_Cameras: [] + m_RendererIndex: -1 + m_VolumeLayerMask: + serializedVersion: 2 + m_Bits: 1 + m_VolumeTrigger: {fileID: 0} + m_VolumeFrameworkUpdateModeOption: 2 + m_RenderPostProcessing: 0 + m_Antialiasing: 0 + m_AntialiasingQuality: 2 + m_StopNaN: 0 + m_Dithering: 0 + m_ClearDepth: 1 + m_AllowXRRendering: 1 + m_AllowHDROutput: 1 + m_UseScreenCoordOverride: 0 + m_ScreenSizeOverride: {x: 0, y: 0, z: 0, w: 0} + m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0} + m_RequiresDepthTexture: 0 + m_RequiresColorTexture: 0 + m_Version: 2 + m_TaaSettings: + m_Quality: 3 + m_FrameInfluence: 0.1 + m_JitterScale: 1 + m_MipBias: 0 + m_VarianceClampScale: 0.9 + m_ContrastAdaptiveSharpening: 0 --- !u!1 &1224833348 GameObject: m_ObjectHideFlags: 0 @@ -1666,15 +1922,15 @@ LineRenderer: m_SortingOrder: 0 m_Positions: - {x: 0, y: 4.1716814, z: 0} - - {x: -0.03339292, y: 3.9260902, z: 0} - - {x: -0.066785835, y: 3.705347, z: 0} - - {x: -0.10017875, y: 3.5094519, z: 0} - - {x: -0.13357168, y: 3.3384047, z: 0} - - {x: -0.16696459, y: 3.1922054, z: 0} - - {x: -0.20035751, y: 3.0708542, z: 0} - - {x: -0.2337504, y: 2.9743507, z: 0} - - {x: -0.26714337, y: 2.9026957, z: 0} - - {x: -0.30053627, y: 2.8558884, z: 0} + - {x: -0.03339292, y: 3.9638388, z: 0} + - {x: -0.066785835, y: 3.7724557, z: 0} + - {x: -0.10017875, y: 3.5975313, z: 0} + - {x: -0.13357168, y: 3.4390674, z: 0} + - {x: -0.16696459, y: 3.2970622, z: 0} + - {x: -0.20035751, y: 3.1715167, z: 0} + - {x: -0.2337504, y: 3.0624304, z: 0} + - {x: -0.26714337, y: 2.969804, z: 0} + - {x: -0.30053627, y: 2.8936367, z: 0} - {x: -0.33392918, y: 2.833929, z: 0} m_Parameters: serializedVersion: 3 @@ -1744,51 +2000,28 @@ LineRenderer: m_UseWorldSpace: 1 m_Loop: 0 m_ApplyActiveColorSpace: 1 ---- !u!23 &1435210811 -MeshRenderer: +--- !u!114 &1435210811 +MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1435210807} m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RayTracingAccelStructBuildFlagsOverride: 0 - m_RayTracingAccelStructBuildFlags: 1 - m_SmallMeshCulling: 1 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 0} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 30919200017f4879867c3b6289429924, type: 3} + m_Name: + m_EditorClassIdentifier: + breakPosition: 0.5 + breakEffect: {fileID: 0} + breakSound: {fileID: 0} + ropeFollowSpeed: 5 + ropeTrailing: 0.2 + ropeGravityStrength: 9.8 + ropeVerticalHangStrength: 2 + ropeDamping: 0.3 + initialSeparationDistance: 0.1 + initialFallImpulse: 2 --- !u!1 &1679185997 GameObject: m_ObjectHideFlags: 0 @@ -1842,7 +2075,7 @@ MonoBehaviour: - {fileID: 2956826569642009690, guid: 7f7f10ca24a5afe46be797daea64111a, type: 3} initialTileCount: 3 tileSpawnBuffer: 1 - moveSpeed: 3 + moveSpeed: 2 speedUpFactor: 0 speedUpInterval: 0 maxMoveSpeed: 12 @@ -1855,6 +2088,10 @@ MonoBehaviour: onTileDestroyed: m_PersistentCalls: m_Calls: [] + velocityCalculationInterval: 0.5 + onLastTileLeft: + m_PersistentCalls: + m_Calls: [] --- !u!1 &1834056336 GameObject: m_ObjectHideFlags: 0 @@ -2004,6 +2241,61 @@ Transform: m_Children: [] m_Father: {fileID: 2106431002} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &2064311128 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2064311129} + - component: {fileID: 2064311130} + m_Layer: 0 + m_Name: SurfacingTimeline + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2064311129 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2064311128} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!320 &2064311130 +PlayableDirector: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2064311128} + m_Enabled: 1 + serializedVersion: 3 + m_PlayableAsset: {fileID: 11400000, guid: 5ecd3cfdb172df5439e4522c15c48f75, type: 2} + m_InitialState: 0 + m_WrapMode: 0 + m_DirectorUpdateMode: 1 + m_InitialTime: 0 + m_SceneBindings: + - key: {fileID: 7536617106820686252, guid: 5ecd3cfdb172df5439e4522c15c48f75, type: 2} + value: {fileID: 747976405} + - key: {fileID: 1284158391674687369, guid: 5ecd3cfdb172df5439e4522c15c48f75, type: 2} + value: {fileID: 461301698} + - key: {fileID: -4039891455399305819, guid: 5ecd3cfdb172df5439e4522c15c48f75, type: 2} + value: {fileID: 224729334} + m_ExposedReferences: + m_References: [] --- !u!1 &2106431001 GameObject: m_ObjectHideFlags: 0 @@ -2017,7 +2309,7 @@ GameObject: - component: {fileID: 2106431004} m_Layer: 0 m_Name: Rock - m_TagString: Untagged + m_TagString: Rock m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 @@ -2095,3 +2387,5 @@ SceneRoots: - {fileID: 116234201} - {fileID: 824396217} - {fileID: 323864665} + - {fileID: 461301697} + - {fileID: 2064311129} diff --git a/Assets/Scripts/AppleHillsScripts.asmdef b/Assets/Scripts/AppleHillsScripts.asmdef index 0a67cb12..9b0a338d 100644 --- a/Assets/Scripts/AppleHillsScripts.asmdef +++ b/Assets/Scripts/AppleHillsScripts.asmdef @@ -7,7 +7,8 @@ "AstarPathfindingProject", "Unity.ResourceManager", "Unity.InputSystem", - "Unity.TextMeshPro" + "Unity.TextMeshPro", + "OptimizedRope" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Assets/Scripts/Minigames/DivingForPictures/BubbleSpawner.cs b/Assets/Scripts/Minigames/DivingForPictures/BubbleSpawner.cs index 31758f57..d4859a84 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/BubbleSpawner.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/BubbleSpawner.cs @@ -26,10 +26,15 @@ namespace Minigames.DivingForPictures public int initialPoolSize = 10; public int maxPoolSize = 30; + [Header("Surfacing Settings")] + [Tooltip("Factor to multiply bubble speed by when surfacing (0.5 = half speed)")] + [SerializeField] private float surfacingSpeedFactor = 0.5f; + private float _timer; private float _nextSpawnInterval; private BubblePool _bubblePool; private Camera _mainCamera; // Cache camera reference + private bool _isSurfacing = false; void Awake() { @@ -98,7 +103,18 @@ namespace Minigames.DivingForPictures } // Randomize bubble properties - bubble.speed = Random.Range(speedRange.x, speedRange.y); + float baseSpeed = Random.Range(speedRange.x, speedRange.y); + + // Apply surfacing speed reduction if needed + if (_isSurfacing) + { + bubble.speed = baseSpeed * surfacingSpeedFactor; + } + else + { + bubble.speed = baseSpeed; + } + bubble.wobbleSpeed = Random.Range(wobbleSpeedRange.x, wobbleSpeedRange.y); // Set base scale (initial size) for the bubble @@ -119,6 +135,25 @@ namespace Minigames.DivingForPictures bubble.SetWobbleScaleLimits(wobbleMinScale, wobbleMaxScale); } + /// + /// Start surfacing mode - slow down all bubbles + /// + public void StartSurfacing() + { + if (_isSurfacing) return; // Already surfacing + + _isSurfacing = true; + + // Slow down all existing bubbles + Bubble[] activeBubbles = FindObjectsOfType(); + foreach (Bubble bubble in activeBubbles) + { + bubble.speed *= surfacingSpeedFactor; + } + + Debug.Log($"[BubbleSpawner] Started surfacing mode. Bubbles slowed to {surfacingSpeedFactor * 100}% speed."); + } + /// /// Logs the current pool statistics for debugging /// diff --git a/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs b/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs index c3a94f56..d97285b4 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs @@ -1,7 +1,9 @@ using UnityEngine; using System.Collections.Generic; using System; +using System.Collections; using UnityEngine.Events; +using UnityEngine.Playables; namespace Minigames.DivingForPictures { @@ -31,6 +33,20 @@ namespace Minigames.DivingForPictures [Tooltip("Additional points per depth unit")] [SerializeField] private int depthMultiplier = 10; + [Header("Rope Damage System")] + [Tooltip("Ropes that will break one by one as player takes damage")] + [SerializeField] private RopeBreaker[] playerRopes; + + [Header("Surfacing Settings")] + [Tooltip("Duration in seconds for speed transition when surfacing")] + [SerializeField] private float speedTransitionDuration = 2.0f; + [Tooltip("Factor to multiply speed by when surfacing (usually 1.0 for same speed)")] + [SerializeField] private float surfacingSpeedFactor = 3.0f; + [Tooltip("How long to continue spawning tiles after surfacing begins (seconds)")] + [SerializeField] private float surfacingSpawnDelay = 5.0f; + [Tooltip("Reference to the PlayableDirector that will play the surfacing timeline")] + [SerializeField] private PlayableDirector surfacingTimeline; + // Private state variables private int playerScore = 0; private float currentSpawnProbability; @@ -38,14 +54,32 @@ namespace Minigames.DivingForPictures private float timeSinceLastSpawn = 0f; private List activeMonsters = new List(); + // Velocity management + // Velocity state tracking + private float _currentVelocityFactor = 1.0f; // 1.0 = normal descent speed, -1.0 * surfacingSpeedFactor = full surfacing speed + private Coroutine _velocityTransitionCoroutine; + private Coroutine _surfacingSequenceCoroutine; + // Public properties public int PlayerScore => playerScore; + public float CurrentVelocityFactor => _currentVelocityFactor; // Events public event Action OnScoreChanged; public event Action OnMonsterSpawned; public event Action OnPictureTaken; public event Action OnSpawnProbabilityChanged; + public event Action OnGameOver; + public event Action OnRopeBroken; // Passes remaining ropes count + public event Action OnVelocityFactorChanged; + + // Private state variables for rope system + private int currentRopeIndex = 0; + private bool isGameOver = false; + private bool _isSurfacing = false; + + // Used to track if we're currently surfacing + public bool IsSurfacing => _isSurfacing; private void Awake() { @@ -64,6 +98,18 @@ namespace Minigames.DivingForPictures { Debug.LogWarning("No TrenchTileSpawner found in scene. Monster spawning won't work."); } + + // Subscribe to player damage events + PlayerCollisionBehavior.OnDamageTaken += OnPlayerDamageTaken; + + // Validate rope references + ValidateRopeReferences(); + } + + private void OnDestroy() + { + // Unsubscribe from events when the manager is destroyed + PlayerCollisionBehavior.OnDamageTaken -= OnPlayerDamageTaken; } private void Update() @@ -92,6 +138,9 @@ namespace Minigames.DivingForPictures if (spawnPoints.Length == 0) return; + // If we're surfacing, don't spawn new monsters + if (_isSurfacing) return; + bool forceSpawn = timeSinceLastSpawn >= guaranteedSpawnTime; bool onCooldown = timeSinceLastSpawn < spawnCooldown; @@ -176,6 +225,335 @@ namespace Minigames.DivingForPictures monster.OnMonsterDespawned -= OnMonsterDespawned; } + /// + /// Called when the player takes damage from any collision + /// + private void OnPlayerDamageTaken() + { + if (isGameOver) return; + + // Break the next rope in sequence + BreakNextRope(); + + // Check if all ropes are broken + if (currentRopeIndex >= playerRopes.Length) + { + TriggerGameOver(); + } + else + { + // Notify listeners about rope break and remaining ropes + int remainingRopes = playerRopes.Length - currentRopeIndex; + OnRopeBroken?.Invoke(remainingRopes); + + Debug.Log($"[DivingGameManager] Rope broken! {remainingRopes} ropes remaining."); + } + } + + /// + /// Breaks the next available rope in the sequence + /// + private void BreakNextRope() + { + if (currentRopeIndex < playerRopes.Length) + { + RopeBreaker ropeToBreak = playerRopes[currentRopeIndex]; + + if (ropeToBreak != null) + { + // Let the RopeBreaker component handle the breaking, effects, and sounds + ropeToBreak.BreakRope(); + } + else + { + Debug.LogWarning($"[DivingGameManager] Rope at index {currentRopeIndex} is null!"); + } + + // Move to the next rope regardless if current was null + currentRopeIndex++; + } + } + + /// + /// Manually break a rope (for testing or external events) + /// + public void ForceBreakRope() + { + if (!isGameOver) + { + OnPlayerDamageTaken(); + } + } + + /// + /// Triggers game over state when all ropes are broken + /// + private void TriggerGameOver() + { + if (isGameOver) return; + + isGameOver = true; + Debug.Log("[DivingGameManager] Game Over! All ropes broken. Starting surfacing sequence..."); + + // Fire game over event + OnGameOver?.Invoke(); + + // Start surfacing instead of directly ending the game + StartSurfacing(); + } + + /// + /// Validates rope references and logs warnings if any are missing + /// + private void ValidateRopeReferences() + { + if (playerRopes == null || playerRopes.Length == 0) + { + Debug.LogWarning("[DivingGameManager] No ropes assigned to break! Damage system won't work properly."); + return; + } + + for (int i = 0; i < playerRopes.Length; i++) + { + if (playerRopes[i] == null) + { + Debug.LogWarning($"[DivingGameManager] Rope at index {i} is null!"); + } + } + } + + /// + /// Resets the rope system for a new game + /// + public void ResetRopeSystem() + { + // Reset rope state + currentRopeIndex = 0; + isGameOver = false; + + // Restore all broken ropes + if (playerRopes != null) + { + foreach (var rope in playerRopes) + { + if (rope != null) + { + rope.RestoreRope(); + } + } + } + + Debug.Log("[DivingGameManager] Rope system reset."); + } + + /// + /// Starts the surfacing mode - reverses trench direction and adjusts all spawned entities + /// + public void StartSurfacing() + { + if (_isSurfacing) return; // Already surfacing + + _isSurfacing = true; + + // 1. Initiate smooth velocity transition to surfacing speed + float targetVelocityFactor = -1.0f * surfacingSpeedFactor; + SetVelocityFactor(targetVelocityFactor); + + // 2. Find and notify trench tile spawner about direction change (for spawning/despawning logic) + TrenchTileSpawner tileSpawner = FindFirstObjectByType(); + if (tileSpawner != null) + { + // Subscribe to velocity changes if not already subscribed + OnVelocityFactorChanged -= tileSpawner.OnVelocityFactorChanged; + OnVelocityFactorChanged += tileSpawner.OnVelocityFactorChanged; + + // Subscribe to the last tile event + tileSpawner.onLastTileLeft.RemoveListener(OnLastTileLeft); + tileSpawner.onLastTileLeft.AddListener(OnLastTileLeft); + + // Tell spawner to reverse spawn/despawn logic + tileSpawner.StartSurfacing(); + + // Immediately send current velocity factor + tileSpawner.OnVelocityFactorChanged(_currentVelocityFactor); + } + + // Handle the Rock object - disable components and animate it falling offscreen + GameObject rockObject = GameObject.FindGameObjectWithTag("Rock"); + if (rockObject != null) + { + // Disable all components except Transform on the rock object (not its children) + foreach (Component component in rockObject.GetComponents()) + { + if (!(component is Transform)) + { + if (component is Behaviour behaviour) + { + behaviour.enabled = false; + } + } + } + + // Start coroutine to animate the rock falling offscreen + StartCoroutine(MoveRockOffscreen(rockObject.transform)); + + Debug.Log("[DivingGameManager] Disabled rock components and animating it offscreen"); + } + + // Handle the Player object - disable components and reset X position + GameObject playerObject = GameObject.FindGameObjectWithTag("Player"); + if (playerObject != null) + { + // Disable all components except Transform and Animator on the player object (not its children) + foreach (Component component in playerObject.GetComponents()) + { + if (!(component is Transform) && !(component is Animator)) + { + if (component is Behaviour behaviour) + { + behaviour.enabled = false; + } + } + } + + // Start coroutine to reset X position to 0 over 1 second + StartCoroutine(ResetPlayerPosition(playerObject.transform)); + + Debug.Log("[DivingGameManager] Disabled player components (keeping Animator) and resetting position"); + } + + // 3. Find bubble spawner and slow down existing bubbles (no velocity management needed) + BubbleSpawner bubbleSpawner = FindFirstObjectByType(); + if (bubbleSpawner != null) + { + bubbleSpawner.StartSurfacing(); + } + + // 4. Find obstacle spawner and set up for velocity changes + ObstacleSpawner obstacleSpawner = FindFirstObjectByType(); + if (obstacleSpawner != null) + { + // Subscribe to velocity changes + OnVelocityFactorChanged -= obstacleSpawner.OnVelocityFactorChanged; + OnVelocityFactorChanged += obstacleSpawner.OnVelocityFactorChanged; + + // Tell spawner to reverse spawn/despawn logic + obstacleSpawner.StartSurfacing(); + + // Immediately send current velocity factor + obstacleSpawner.OnVelocityFactorChanged(_currentVelocityFactor); + } + + // Start the surfacing sequence coroutine + if (_surfacingSequenceCoroutine != null) + { + StopCoroutine(_surfacingSequenceCoroutine); + } + _surfacingSequenceCoroutine = StartCoroutine(SurfacingSequence()); + + Debug.Log($"[DivingGameManager] Started surfacing with target velocity factor: {targetVelocityFactor}"); + } + + /// + /// Coroutine to animate the rock falling below the screen + /// + private IEnumerator MoveRockOffscreen(Transform rockTransform) + { + Vector3 startPosition = rockTransform.position; + + // Calculate position below the screen + Camera mainCamera = Camera.main; + if (mainCamera == null) + { + Debug.LogWarning("[DivingGameManager] Cannot find main camera to calculate offscreen position"); + yield break; + } + + // Get a position below the bottom of the screen + Vector3 offscreenPosition = mainCamera.ViewportToWorldPoint(new Vector3(0.5f, -0.2f, mainCamera.nearClipPlane)); + Vector3 targetPosition = new Vector3(startPosition.x, offscreenPosition.y, startPosition.z); + + float duration = 2.0f; // Animation duration in seconds + float elapsed = 0f; + + while (elapsed < duration) + { + elapsed += Time.deltaTime; + float t = Mathf.Clamp01(elapsed / duration); + + // Use an easing function that accelerates to simulate falling + float easedT = t * t; // Quadratic easing + + rockTransform.position = Vector3.Lerp(startPosition, targetPosition, easedT); + yield return null; + } + + // Ensure final position is exactly at target + rockTransform.position = targetPosition; + } + + /// + /// Coroutine to reset the player's X position to 0 over time + /// + private IEnumerator ResetPlayerPosition(Transform playerTransform) + { + Vector3 startPosition = playerTransform.position; + Vector3 targetPosition = new Vector3(0f, startPosition.y, startPosition.z); + + float duration = 1.0f; // Reset duration in seconds (as requested) + float elapsed = 0f; + + while (elapsed < duration) + { + elapsed += Time.deltaTime; + float t = Mathf.Clamp01(elapsed / duration); + + // Use smooth step for more natural movement + float smoothT = Mathf.SmoothStep(0f, 1f, t); + + playerTransform.position = Vector3.Lerp(startPosition, targetPosition, smoothT); + yield return null; + } + + // Ensure final position is exactly at target + playerTransform.position = targetPosition; + } + + /// + /// Coroutine to handle the surfacing sequence timing + /// + private IEnumerator SurfacingSequence() + { + // Wait for the configured delay + yield return new WaitForSeconds(surfacingSpawnDelay); + + // Find tile spawner and tell it to stop spawning + TrenchTileSpawner tileSpawner = FindFirstObjectByType(); + if (tileSpawner != null) + { + // Tell it to stop spawning new tiles + tileSpawner.StopSpawning(); + Debug.Log("[DivingGameManager] Stopped spawning new tiles after delay"); + } + } + + /// + /// Called when the last tile leaves the screen + /// + private void OnLastTileLeft() + { + // Play the timeline + if (surfacingTimeline != null) + { + surfacingTimeline.Play(); + Debug.Log("[DivingGameManager] Last tile left the screen, playing timeline"); + } + else + { + Debug.LogWarning("[DivingGameManager] No surfacing timeline assigned!"); + } + } + // Call this when the game ends public void EndGame() { @@ -193,5 +571,49 @@ namespace Minigames.DivingForPictures // Final score could be saved to player prefs or other persistence Debug.Log($"Final Score: {playerScore}"); } + + /// + /// Starts a smooth transition to the new velocity factor + /// + /// Target velocity factor (e.g., -1.0 for surfacing speed) + public void SetVelocityFactor(float targetFactor) + { + if (_velocityTransitionCoroutine != null) + { + StopCoroutine(_velocityTransitionCoroutine); + } + + _velocityTransitionCoroutine = StartCoroutine(TransitionVelocityFactor(targetFactor)); + } + + /// + /// Coroutine to smoothly transition the velocity factor over time + /// + private IEnumerator TransitionVelocityFactor(float targetFactor) + { + float startFactor = _currentVelocityFactor; + float elapsed = 0f; + + while (elapsed < speedTransitionDuration) + { + elapsed += Time.deltaTime; + float t = Mathf.Clamp01(elapsed / speedTransitionDuration); + + // Smooth step interpolation + float smoothStep = t * t * (3f - 2f * t); + + _currentVelocityFactor = Mathf.Lerp(startFactor, targetFactor, smoothStep); + + // Notify listeners about the velocity factor change + OnVelocityFactorChanged?.Invoke(_currentVelocityFactor); + + yield return null; + } + + _currentVelocityFactor = targetFactor; + + // Final assignment to ensure exact target value + OnVelocityFactorChanged?.Invoke(_currentVelocityFactor); + } } } diff --git a/Assets/Scripts/Minigames/DivingForPictures/FloatingObstacle.cs b/Assets/Scripts/Minigames/DivingForPictures/FloatingObstacle.cs index 52338634..2d285271 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/FloatingObstacle.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/FloatingObstacle.cs @@ -44,8 +44,12 @@ namespace Minigames.DivingForPictures private Collider2D _collider; private Camera _mainCamera; private float _screenTop; + private float _screenBottom; // Added to track bottom of screen private Coroutine _movementCoroutine; private Coroutine _offScreenCheckCoroutine; + private bool _isSurfacing = false; // Flag to track surfacing state + private float _velocityFactor = 1.0f; // Current velocity factor from game manager + private float _baseMoveSpeed; // Original move speed before velocity factor is applied private void Awake() { @@ -62,6 +66,7 @@ namespace Minigames.DivingForPictures } _mainCamera = Camera.main; + _baseMoveSpeed = moveSpeed; // Store original speed } private void OnEnable() @@ -105,6 +110,30 @@ namespace Minigames.DivingForPictures } } + /// + /// Called when the velocity factor changes from the DivingGameManager via ObstacleSpawner + /// + public void OnVelocityFactorChanged(float velocityFactor) + { + _velocityFactor = velocityFactor; + + // Update actual move speed based on velocity factor and base speed + // We use Abs for magnitude and Sign for direction + moveSpeed = _baseMoveSpeed * Mathf.Abs(_velocityFactor); + + // Restart movement with new speed if needed + if (enableMovement && gameObject.activeInHierarchy) + { + if (_movementCoroutine != null) + { + StopCoroutine(_movementCoroutine); + } + _movementCoroutine = StartCoroutine(MovementCoroutine()); + } + + Debug.Log($"[FloatingObstacle] {gameObject.name} velocity factor updated to {_velocityFactor:F2}, speed: {moveSpeed:F2}"); + } + /// /// Coroutine that handles obstacle movement /// @@ -112,8 +141,12 @@ namespace Minigames.DivingForPictures { while (enabled && gameObject.activeInHierarchy) { - // Move the obstacle upward - transform.position += Vector3.up * (moveSpeed * Time.deltaTime); + // Use velocity factor sign to determine direction + Vector3 direction = Vector3.up * Mathf.Sign(_velocityFactor); + float speed = moveSpeed * Time.deltaTime; + + // Apply movement in correct direction + transform.position += direction * speed; // Wait for next frame yield return null; @@ -165,6 +198,9 @@ namespace Minigames.DivingForPictures Vector3 topWorldPoint = _mainCamera.ViewportToWorldPoint(new Vector3(0.5f, 1f, _mainCamera.transform.position.z)); _screenTop = topWorldPoint.y; + Vector3 bottomWorldPoint = _mainCamera.ViewportToWorldPoint(new Vector3(0.5f, 0f, _mainCamera.transform.position.z)); + _screenBottom = bottomWorldPoint.y; + // Check if obstacle is significantly above screen top (obstacles move upward) // Use a larger buffer to ensure obstacles are truly off-screen before returning to pool if (transform.position.y > _screenTop + 5f) @@ -172,6 +208,11 @@ namespace Minigames.DivingForPictures Debug.Log($"[FloatingObstacle] {gameObject.name} off-screen at Y:{transform.position.y:F2}, screen top:{_screenTop:F2}"); ReturnToPool(); } + else if (transform.position.y < _screenBottom - 5f) // Added check for bottom screen edge + { + Debug.Log($"[FloatingObstacle] {gameObject.name} below screen at Y:{transform.position.y:F2}, screen bottom:{_screenBottom:F2}"); + ReturnToPool(); + } } /// @@ -279,5 +320,20 @@ namespace Minigames.DivingForPictures StartObstacleBehavior(); } } + + /// + /// Sets surfacing mode, which reverses obstacle movement direction + /// + public void StartSurfacing() + { + if (_isSurfacing) return; // Already surfacing + + _isSurfacing = true; + + // Reverse movement speed (already handled by ObstacleSpawner, but this ensures consistency) + moveSpeed *= -1; + + Debug.Log($"[FloatingObstacle] {gameObject.name} started surfacing with speed: {moveSpeed}"); + } } } diff --git a/Assets/Scripts/Minigames/DivingForPictures/ObstacleSpawner.cs b/Assets/Scripts/Minigames/DivingForPictures/ObstacleSpawner.cs index 67f0cffd..8c69ec38 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/ObstacleSpawner.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/ObstacleSpawner.cs @@ -75,6 +75,8 @@ namespace Minigames.DivingForPictures private Coroutine _spawnCoroutine; private readonly List _activeObstacles = new List(); private int _obstacleCounter = 0; // Counter for unique obstacle naming + private bool _isSurfacing = false; // Flag to track surfacing state + private float _velocityFactor = 1.0f; // Current velocity factor from the game manager private void Awake() { @@ -250,6 +252,13 @@ namespace Minigames.DivingForPictures /// private void TrySpawnObstacle() { + // Don't spawn new obstacles when surfacing + if (_isSurfacing) + { + Debug.Log("[ObstacleSpawner] Skipping obstacle spawn - currently surfacing"); + return; + } + Debug.Log($"[ObstacleSpawner] TrySpawnObstacle called at {Time.time:F2}"); if (obstaclePrefabs == null || obstaclePrefabs.Count == 0) @@ -338,25 +347,53 @@ namespace Minigames.DivingForPictures return; } - Debug.Log($"[ObstacleSpawner] Got obstacle {obstacle.name} from pool, active state: {obstacle.activeInHierarchy}"); - - // FORCE ACTIVATION - bypass pool issues - if (!obstacle.activeInHierarchy) - { - Debug.LogWarning($"[ObstacleSpawner] Pool returned inactive object {obstacle.name}, force activating!"); - obstacle.SetActive(true); - Debug.Log($"[ObstacleSpawner] After force activation, {obstacle.name} active state: {obstacle.activeInHierarchy}"); - } - + // Important: Set position/parent/rotation BEFORE activation to avoid visual glitches obstacle.transform.position = position; obstacle.transform.rotation = prefab.transform.rotation; obstacle.transform.SetParent(transform); - Debug.Log($"[ObstacleSpawner] After positioning, obstacle {obstacle.name} active state: {obstacle.activeInHierarchy}"); + + Debug.Log($"[ObstacleSpawner] Got obstacle {obstacle.name} from pool, active state: {obstacle.activeInHierarchy}"); + + // ENHANCED FORCE ACTIVATION - more robust approach + if (!obstacle.activeInHierarchy) + { + Debug.LogWarning($"[ObstacleSpawner] Pool returned inactive object {obstacle.name}, force activating!"); + + // Configure obstacle BEFORE activation + ConfigureObstacle(obstacle, prefabIndex); + + // Force activate the obstacle + obstacle.SetActive(true); + + // Double-check activation status + if (!obstacle.activeInHierarchy) + { + Debug.LogError($"[ObstacleSpawner] CRITICAL ERROR: Failed to activate {obstacle.name} after multiple attempts!"); + + // Last resort: try to instantiate a new one instead + GameObject newObstacle = Instantiate(prefab, position, prefab.transform.rotation, transform); + if (newObstacle != null) + { + obstacle = newObstacle; + ConfigureObstacle(obstacle, prefabIndex); + } + } + + Debug.Log($"[ObstacleSpawner] After force activation, {obstacle.name} active state: {obstacle.activeInHierarchy}"); + } + else + { + // Still configure if already active + ConfigureObstacle(obstacle, prefabIndex); + } } else { Debug.Log($"[ObstacleSpawner] Instantiating new obstacle (pooling disabled)"); obstacle = Instantiate(prefab, position, prefab.transform.rotation, transform); + + // Configure the newly instantiated obstacle + ConfigureObstacle(obstacle, prefabIndex); } // Assign unique name with counter @@ -364,10 +401,6 @@ namespace Minigames.DivingForPictures string oldName = obstacle.name; obstacle.name = $"Obstacle{_obstacleCounter:D3}"; Debug.Log($"[ObstacleSpawner] Renamed obstacle from '{oldName}' to '{obstacle.name}', active state: {obstacle.activeInHierarchy}"); - - // Configure the obstacle - ConfigureObstacle(obstacle, prefabIndex); - Debug.Log($"[ObstacleSpawner] After configuration, obstacle {obstacle.name} active state: {obstacle.activeInHierarchy}"); // Track active obstacles _activeObstacles.Add(obstacle); @@ -459,6 +492,55 @@ namespace Minigames.DivingForPictures CalculateScreenBounds(); } + /// + /// Called when the velocity factor changes from the DivingGameManager + /// + public void OnVelocityFactorChanged(float velocityFactor) + { + _velocityFactor = velocityFactor; + + // Update all active obstacles with the new velocity factor + foreach (GameObject obstacle in _activeObstacles) + { + if (obstacle != null) + { + FloatingObstacle obstacleComponent = obstacle.GetComponent(); + if (obstacleComponent != null) + { + obstacleComponent.OnVelocityFactorChanged(velocityFactor); + } + } + } + + Debug.Log($"[ObstacleSpawner] Velocity factor updated to {_velocityFactor:F2}, propagated to {_activeObstacles.Count} active obstacles"); + } + + /// + /// Start surfacing mode - reverse direction of existing obstacles and stop spawning new ones + /// + public void StartSurfacing() + { + if (_isSurfacing) return; // Already surfacing + + _isSurfacing = true; + + // Notify obstacles about surfacing state (for direction-based logic) + foreach (GameObject obstacle in _activeObstacles) + { + if (obstacle != null) + { + FloatingObstacle obstacleComponent = obstacle.GetComponent(); + if (obstacleComponent != null) + { + // Call StartSurfacing on the obstacle component itself + obstacleComponent.StartSurfacing(); + } + } + } + + Debug.Log($"[ObstacleSpawner] Started surfacing mode for {_activeObstacles.Count} active obstacles"); + } + /// /// Gets the count of currently active obstacles /// diff --git a/Assets/Scripts/Minigames/DivingForPictures/RopeBreaker.cs b/Assets/Scripts/Minigames/DivingForPictures/RopeBreaker.cs new file mode 100644 index 00000000..fa0b022c --- /dev/null +++ b/Assets/Scripts/Minigames/DivingForPictures/RopeBreaker.cs @@ -0,0 +1,331 @@ +using UnityEngine; +using System.Collections; +using GogoGaga.OptimizedRopesAndCables; + +/// +/// Component that allows breaking a rope in half. +/// Attach this to the same GameObject that has a Rope and LineRenderer component. +/// +public class RopeBreaker : MonoBehaviour +{ + [Header("Break Settings")] + [Tooltip("Position along rope where break occurs (0-1)")] + [Range(0f, 1f)] + [SerializeField] private float breakPosition = 0.5f; + + [Tooltip("Effect to spawn at break point (optional)")] + [SerializeField] private GameObject breakEffect; + + [Tooltip("Sound to play when rope breaks (optional)")] + [SerializeField] private AudioClip breakSound; + + [Header("Physics Settings")] + [Tooltip("Follow speed for the rope physics simulation")] + [SerializeField] private float ropeFollowSpeed = 5f; + + [Tooltip("Trailing amount for the rope physics simulation")] + [SerializeField] private float ropeTrailing = 0.2f; + + [Tooltip("Gravity strength applied to hanging rope end")] + [SerializeField] private float ropeGravityStrength = 9.8f; + + [Tooltip("How strongly the rope tries to hang vertically")] + [SerializeField] private float ropeVerticalHangStrength = 2f; + + [Tooltip("Damping for physics movement (higher = less bouncy)")] + [SerializeField] private float ropeDamping = 0.3f; + + [Tooltip("Initial separation distance between rope ends when broken")] + [SerializeField] private float initialSeparationDistance = 0.1f; + + [Tooltip("Initial downward impulse for falling rope end")] + [SerializeField] private float initialFallImpulse = 2.0f; + + // Private references + private Rope originalRope; + private LineRenderer originalLineRenderer; + private GameObject firstHalfRope; + private GameObject secondHalfRope; + private Rope firstHalfRopeComponent; + private Rope secondHalfRopeComponent; + private Transform breakPointTransform; + private Transform secondBreakTransform; + + private void Awake() + { + // Get references to the required components + originalRope = GetComponent(); + originalLineRenderer = GetComponent(); + + if (originalRope == null || originalLineRenderer == null) + { + Debug.LogError("RopeBreaker requires both Rope and LineRenderer components on the same GameObject"); + enabled = false; + } + } + + /// + /// Breaks the rope at the specified position. + /// + /// Optional override for break position (0-1) + /// True if rope was broken successfully, false otherwise + public bool BreakRope(float? breakPositionOverride = null) + { + if (originalRope == null || !originalRope.StartPoint || !originalRope.EndPoint) + { + Debug.LogError("Cannot break rope: Missing rope component or endpoints"); + return false; + } + + // Use override position if provided + float breakPos = breakPositionOverride ?? breakPosition; + breakPos = Mathf.Clamp01(breakPos); + + // Get the world position at the break point + Vector3 breakPointPosition = originalRope.GetPointAt(breakPos); + + // Create a transform at the break point to use as an anchor + CreateBreakPointTransform(breakPointPosition); + + // Create two new rope GameObjects + CreateRopeSegments(breakPointPosition); + + // Hide the original rope + originalLineRenderer.enabled = false; + + // Play effects + PlayBreakEffects(breakPointPosition); + + return true; + } + + /// + /// Creates a transform at the break point to use as an anchor + /// + private void CreateBreakPointTransform(Vector3 breakPointPosition) + { + // Store references to the original rope endpoints + Transform originalStartPoint = originalRope.StartPoint; + Transform originalEndPoint = originalRope.EndPoint; + + // Create a new GameObject for the break point (attached to Player) + GameObject breakPointObj = new GameObject("RopeBreakPoint"); + breakPointTransform = breakPointObj.transform; + breakPointTransform.position = breakPointPosition; + breakPointTransform.SetParent(transform.parent); // Parent to the same parent as the rope + + // Add the physics follower component to the break point + RopeEndPhysicsFollower follower = breakPointObj.AddComponent(); + + // Set specific transform to follow instead of using tag + follower.SetTargetTransform(originalStartPoint); + follower.canFall = false; // Player rope end doesn't fall + follower.followSpeed = ropeFollowSpeed; + follower.trailing = ropeTrailing; + + // Create second break point (for the rock-attached end) + GameObject secondBreakObj = new GameObject("RopeBreakPoint_Second"); + secondBreakTransform = secondBreakObj.transform; + secondBreakTransform.position = breakPointPosition; + secondBreakTransform.SetParent(transform.parent); + + // Add physics behavior to second break point + RopeEndPhysicsFollower secondFollower = secondBreakObj.AddComponent(); + + // Set specific transform to follow instead of using tag + secondFollower.SetTargetTransform(originalEndPoint); + secondFollower.canFall = true; // Rock end can fall + secondFollower.followSpeed = ropeFollowSpeed; + secondFollower.trailing = ropeTrailing; + secondFollower.gravityStrength = ropeGravityStrength; + secondFollower.verticalHangStrength = ropeVerticalHangStrength; + secondFollower.damping = ropeDamping; + secondFollower.initialFallImpulse = initialFallImpulse; + + // Create initial separation + Vector3 direction = (originalEndPoint.position - breakPointPosition).normalized; + if (direction.magnitude < 0.01f) direction = Vector3.down; + + breakPointTransform.position -= direction * initialSeparationDistance * 0.5f; + secondBreakTransform.position += direction * initialSeparationDistance * 0.5f; + } + + /// + /// Creates two new rope GameObjects for the broken segments + /// + private void CreateRopeSegments(Vector3 breakPointPosition) + { + // Create the first half rope (from start to break point) + firstHalfRope = new GameObject("Rope_FirstHalf"); + firstHalfRope.transform.position = transform.position; + firstHalfRope.transform.rotation = transform.rotation; + firstHalfRope.transform.SetParent(transform.parent); + + // Add Rope component which automatically adds LineRenderer due to RequireComponent + firstHalfRopeComponent = firstHalfRope.AddComponent(); + + // Get the LineRenderer that was automatically added + LineRenderer firstLineRenderer = firstHalfRope.GetComponent(); + if (firstLineRenderer == null) + { + // Only add if somehow not created (shouldn't happen, but safety check) + firstLineRenderer = firstHalfRope.AddComponent(); + } + CopyLineRendererProperties(originalLineRenderer, firstLineRenderer); + + // Create the second half rope (from break point to end) + secondHalfRope = new GameObject("Rope_SecondHalf"); + secondHalfRope.transform.position = transform.position; + secondHalfRope.transform.rotation = transform.rotation; + secondHalfRope.transform.SetParent(transform.parent); + + // Add Rope component which automatically adds LineRenderer due to RequireComponent + secondHalfRopeComponent = secondHalfRope.AddComponent(); + + // Get the LineRenderer that was automatically added + LineRenderer secondLineRenderer = secondHalfRope.GetComponent(); + if (secondLineRenderer == null) + { + // Only add if somehow not created (shouldn't happen, but safety check) + secondLineRenderer = secondHalfRope.AddComponent(); + } + CopyLineRendererProperties(originalLineRenderer, secondLineRenderer); + + // Configure the first half rope + firstHalfRopeComponent.SetStartPoint(originalRope.StartPoint); + firstHalfRopeComponent.SetEndPoint(breakPointTransform, false); // Don't recalculate yet + + // Copy properties from original rope + CopyRopeProperties(originalRope, firstHalfRopeComponent); + + // Explicitly initialize the rope + firstHalfRopeComponent.Initialize(); + + // Now force recalculation after initialization + firstHalfRopeComponent.RecalculateRope(); + + // Configure the second half rope - REVERSED: Rock (End) is now Start, Break point is now End + secondHalfRopeComponent.SetStartPoint(originalRope.EndPoint); + secondHalfRopeComponent.SetEndPoint(secondBreakTransform, false); // Don't recalculate yet + + // Copy properties from original rope + CopyRopeProperties(originalRope, secondHalfRopeComponent); + + // Explicitly initialize the rope + secondHalfRopeComponent.Initialize(); + + // Now force recalculation after initialization + secondHalfRopeComponent.RecalculateRope(); + + // Set explicit rope length constraints on the physics followers + // This needs to be done after the rope segments are created so we have the correct rope lengths + RopeEndPhysicsFollower playerFollower = breakPointTransform.GetComponent(); + if (playerFollower != null) + { + playerFollower.SetMaxDistance(firstHalfRopeComponent.ropeLength); + } + + RopeEndPhysicsFollower rockFollower = secondBreakTransform.GetComponent(); + if (rockFollower != null) + { + rockFollower.SetMaxDistance(secondHalfRopeComponent.ropeLength); + } + } + + /// + /// Copies properties from one LineRenderer to another + /// + private void CopyLineRendererProperties(LineRenderer source, LineRenderer destination) + { + // Copy material + destination.material = source.material; + + // Copy colors + destination.startColor = source.startColor; + destination.endColor = source.endColor; + + // Copy width + destination.startWidth = source.startWidth; + destination.endWidth = source.endWidth; + + // Copy other properties + destination.numCornerVertices = source.numCornerVertices; + destination.numCapVertices = source.numCapVertices; + destination.alignment = source.alignment; + destination.textureMode = source.textureMode; + destination.generateLightingData = source.generateLightingData; + destination.useWorldSpace = source.useWorldSpace; + destination.loop = source.loop; + destination.sortingLayerID = source.sortingLayerID; + destination.sortingOrder = source.sortingOrder; + } + + /// + /// Copies properties from one Rope to another + /// + private void CopyRopeProperties(Rope source, Rope destination) + { + destination.linePoints = source.linePoints; + destination.stiffness = source.stiffness; + destination.damping = source.damping; + destination.ropeLength = source.ropeLength / 2f; // Halve the rope length for each segment + destination.ropeWidth = source.ropeWidth; + destination.midPointWeight = source.midPointWeight; + destination.midPointPosition = source.midPointPosition; + + // Recalculate the rope to update its appearance + destination.RecalculateRope(); + } + + /// + /// Plays visual and audio effects at the break point + /// + private void PlayBreakEffects(Vector3 breakPointPosition) + { + // Spawn break effect if assigned + if (breakEffect != null) + { + Instantiate(breakEffect, breakPointPosition, Quaternion.identity); + } + + // Play break sound if assigned + if (breakSound != null) + { + AudioSource.PlayClipAtPoint(breakSound, breakPointPosition); + } + } + + /// + /// Restores the original rope and cleans up the broken pieces + /// + public void RestoreRope() + { + // Re-enable the original rope + if (originalLineRenderer != null) + { + originalLineRenderer.enabled = true; + } + + // Clean up the broken rope pieces + if (firstHalfRope != null) + { + Destroy(firstHalfRope); + } + + if (secondHalfRope != null) + { + Destroy(secondHalfRope); + } + + // Clean up both break points + if (breakPointTransform != null) + { + Destroy(breakPointTransform.gameObject); + } + + if (secondBreakTransform != null) + { + Destroy(secondBreakTransform.gameObject); + } + } +} diff --git a/Assets/Scripts/Minigames/DivingForPictures/RopeBreaker.cs.meta b/Assets/Scripts/Minigames/DivingForPictures/RopeBreaker.cs.meta new file mode 100644 index 00000000..9cd7aa9f --- /dev/null +++ b/Assets/Scripts/Minigames/DivingForPictures/RopeBreaker.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 30919200017f4879867c3b6289429924 +timeCreated: 1758466190 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/DivingForPictures/RopeEndPhysicsFollower.cs b/Assets/Scripts/Minigames/DivingForPictures/RopeEndPhysicsFollower.cs new file mode 100644 index 00000000..a9549101 --- /dev/null +++ b/Assets/Scripts/Minigames/DivingForPictures/RopeEndPhysicsFollower.cs @@ -0,0 +1,306 @@ +using GogoGaga.OptimizedRopesAndCables; +using UnityEngine; + +public class RopeEndPhysicsFollower : MonoBehaviour +{ + [Header("Target Settings")] + [Tooltip("Transform this endpoint should follow")] + public Transform targetTransform; + [Tooltip("Tag of the object this endpoint should follow (only used if targetTransform is not set)")] + public string targetTag; + [Tooltip("How quickly the endpoint follows the target when not using physics")] + public float followSpeed = 5f; + [Tooltip("How much trailing (0 = instant, 1 = very slow)")] + public float trailing = 0.2f; + + [Header("Physics Simulation")] + [Tooltip("Gravity strength")] + public float gravityStrength = 9.8f; + [Tooltip("How strongly the rope attempts to hang vertically")] + public float verticalHangStrength = 2f; + [Tooltip("Damping for physics movement (higher = less bouncy)")] + public float damping = 0.3f; + [Tooltip("Initial downward impulse when enabled")] + public float initialFallImpulse = 2.0f; + [Tooltip("Whether this end can fall with gravity (false for player-attached ends)")] + public bool canFall = true; + + // Private variables + private Transform target; + private Vector2 physicsVelocity; + private Vector2 offset; + private Vector3 lastTargetPosition; + private bool initialized = false; + private bool debugLog = true; + + // Rope reference to get the actual rope length + private Rope attachedRope; + private float maxDistance; + + void Start() + { + // Find the Rope component to determine the maximum distance + FindAttachedRope(); + + // Use targetTransform if set, otherwise try to find by tag + if (targetTransform != null) + { + target = targetTransform; + if (debugLog) Debug.Log($"[RopeEndPhysicsFollower] Using assigned target transform: {target.name}"); + } + else if (!string.IsNullOrEmpty(targetTag)) + { + GameObject found = GameObject.FindGameObjectWithTag(targetTag); + if (found) + { + target = found.transform; + if (debugLog) Debug.Log($"[RopeEndPhysicsFollower] Found target by tag '{targetTag}': {target.name}"); + } + } + + // Initialize offset and velocities + if (target) + { + // Only store horizontal offset, not vertical for physics simulation + Vector2 offsetVec = transform.position - target.position; + offset.x = offsetVec.x; + offset.y = 0; // Don't preserve vertical offset for gravity simulation + lastTargetPosition = target.position; + + // Apply initial falling impulse if this end can fall + if (canFall) + { + physicsVelocity = new Vector2(0, -initialFallImpulse); + if (debugLog) Debug.Log($"[RopeEndPhysicsFollower] Initialized with target: {target.name}, initial Y velocity: {physicsVelocity.y}"); + } + } + else + { + offset = Vector2.zero; + lastTargetPosition = transform.position; + if (debugLog) Debug.Log($"[RopeEndPhysicsFollower] No target found"); + } + + initialized = true; + } + + void Update() + { + if (!target) return; + + // Calculate deltaTime for physics stability + float deltaTime = Time.deltaTime; + + // Get target velocity + Vector3 targetVelocity = (target.position - lastTargetPosition) / deltaTime; + lastTargetPosition = target.position; + + // Current position relative to target + Vector2 relativePos = new Vector2( + transform.position.x - target.position.x, + transform.position.y - target.position.y + ); + + // Get the straight-line distance between target and this transform + float currentDistance = relativePos.magnitude; + + // Normalized direction from target to this transform + Vector2 directionToTarget = relativePos.normalized; + + // Apply forces based on whether this end can fall + if (canFall) + { + // 1. Gravity - always pulls down + physicsVelocity.y -= gravityStrength * deltaTime; + } + + // 2. Vertical hanging force - try to align X with target when stationary + if (Mathf.Abs(targetVelocity.x) < 0.1f) + { + // Use the actual X position of the target as the desired X position + float xOffset = transform.position.x - target.position.x; + physicsVelocity.x -= xOffset * verticalHangStrength * deltaTime; + + // Debug log to track vertical hanging behavior + if (debugLog && Time.frameCount % 120 == 0) + { + Debug.Log($"[RopeEndPhysicsFollower] Vertical hanging: target X={target.position.x}, my X={transform.position.x}, offset={xOffset}"); + } + } + + // 3. Rope length constraint - apply a force toward the target if we're exceeding the rope length + if (currentDistance > maxDistance) + { + // Calculate constraint force proportional to how much we're exceeding the rope length + float exceededDistance = currentDistance - maxDistance; + + // Apply a stronger constraint force the more we exceed the max distance + Vector2 constraintForce = -directionToTarget * exceededDistance * 10f; + + // Apply to velocity + physicsVelocity += constraintForce * deltaTime; + + if (debugLog && Time.frameCount % 60 == 0) + { + Debug.Log($"[RopeEndPhysicsFollower] Exceeding max distance: {exceededDistance}, applying constraint"); + } + } + + // Apply damping to physics velocity + physicsVelocity *= (1f - damping * deltaTime); + + // Log physics state periodically for debugging + if (debugLog && Time.frameCount % 60 == 0) + { + Debug.Log($"[RopeEndPhysicsFollower] Y position: {transform.position.y}, Y velocity: {physicsVelocity.y}, Distance: {currentDistance}/{maxDistance}"); + } + + // Apply physics velocity to position + Vector3 newPos = transform.position; + newPos.x += physicsVelocity.x * deltaTime; + + // Only apply vertical movement if this end can fall + if (canFall) + { + newPos.y += physicsVelocity.y * deltaTime; + } + + transform.position = newPos; + + // Final distance check - hard constraint to ensure we never exceed the rope length + // This prevents numerical instability from causing the rope to stretch + float finalDistance = Vector2.Distance( + new Vector2(transform.position.x, transform.position.y), + new Vector2(target.position.x, target.position.y) + ); + + if (finalDistance > maxDistance) + { + // Calculate the direction from target to this transform + Vector2 direction = new Vector2( + transform.position.x - target.position.x, + transform.position.y - target.position.y + ).normalized; + + // Set position to be exactly at the maximum distance + Vector3 constrainedPos = new Vector3( + target.position.x + direction.x * maxDistance, + target.position.y + direction.y * maxDistance, + transform.position.z + ); + + transform.position = constrainedPos; + } + } + + private void FindAttachedRope() + { + // Find the Rope component on the same GameObject or parent + attachedRope = GetComponent(); + if (attachedRope == null) + { + attachedRope = GetComponentInParent(); + } + + // If we still couldn't find it, look for it on a child GameObject + if (attachedRope == null) + { + attachedRope = GetComponentInChildren(); + } + + // Look for a rope attached to this endpoint + if (attachedRope == null) + { + // Find any rope that has this transform as an endpoint + Rope[] allRopes = FindObjectsOfType(); + foreach (var rope in allRopes) + { + if (rope.EndPoint == transform || rope.StartPoint == transform) + { + attachedRope = rope; + break; + } + } + } + + // Set max distance based on rope length if we found a rope + if (attachedRope != null) + { + maxDistance = attachedRope.ropeLength; + if (debugLog) Debug.Log($"[RopeEndPhysicsFollower] Found attached rope with length: {maxDistance}"); + } + else + { + // Default fallback value if no rope is found + maxDistance = 2f; + if (debugLog) Debug.Log("[RopeEndPhysicsFollower] No attached rope found, using default max distance"); + } + } + + public void SetTargetTransform(Transform newTarget) + { + targetTransform = newTarget; + target = newTarget; + + if (target != null) + { + lastTargetPosition = target.position; + + // Only update horizontal offset to maintain current vertical position + if (initialized) + { + Vector2 newOffset = transform.position - target.position; + offset.x = newOffset.x; + // Don't update offset.y to allow gravity to work + } + else + { + Vector2 newOffset = transform.position - target.position; + offset.x = newOffset.x; + offset.y = 0; // Don't preserve vertical offset for gravity simulation + } + + // Apply initial falling impulse if this end can fall + if (canFall) + { + physicsVelocity = new Vector2(physicsVelocity.x, -initialFallImpulse); + if (debugLog) Debug.Log($"[RopeEndPhysicsFollower] Reset Y velocity to {physicsVelocity.y} after target change to {target.name}"); + } + } + } + + // Original tag-based method kept for backward compatibility + public void SetTargetTag(string tag) + { + targetTag = tag; + GameObject found = GameObject.FindGameObjectWithTag(targetTag); + if (found) + { + SetTargetTransform(found.transform); + } + } + + // Debug method to force reset the physics + public void ForceResetPhysics() + { + if (target) + { + // Reset velocity with a strong downward impulse + physicsVelocity = new Vector2(0, -initialFallImpulse * 2f); + + // Reset position to be at the same level as the target + Vector3 pos = transform.position; + pos.y = target.position.y; + transform.position = pos; + + if (debugLog) Debug.Log($"[RopeEndPhysicsFollower] Physics forcibly reset, new Y velocity: {physicsVelocity.y}"); + } + } + + // Method to manually set the maximum distance + public void SetMaxDistance(float distance) + { + maxDistance = distance; + if (debugLog) Debug.Log($"[RopeEndPhysicsFollower] Max distance manually set to: {maxDistance}"); + } +} diff --git a/Assets/Scripts/Minigames/DivingForPictures/RopeEndPhysicsFollower.cs.meta b/Assets/Scripts/Minigames/DivingForPictures/RopeEndPhysicsFollower.cs.meta new file mode 100644 index 00000000..d7876677 --- /dev/null +++ b/Assets/Scripts/Minigames/DivingForPictures/RopeEndPhysicsFollower.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bc5a0e35b5e74474b4241fae08971e7a +timeCreated: 1758485385 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/DivingForPictures/TrenchTileSpawner.cs b/Assets/Scripts/Minigames/DivingForPictures/TrenchTileSpawner.cs index 7d2bf387..064944dc 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/TrenchTileSpawner.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/TrenchTileSpawner.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System.Collections; +using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using UnityEngine.Serialization; @@ -48,13 +49,31 @@ namespace Minigames.DivingForPictures private float _screenBottom; private float _screenTop; private TrenchTilePool _tilePool; + + // Current velocity for tile movement + private float _currentVelocity; + + // Interval for velocity calculations (seconds) + [SerializeField] private float velocityCalculationInterval = 0.5f; private const float TileSpawnZ = -1f; private const float DefaultTileHeight = 5f; + // Direction state + private bool _isSurfacing = false; + private bool _stopSpawning = false; + + // Event triggered when the last tile leaves the screen after stopping spawning + public UnityEvent onLastTileLeft = new UnityEvent(); + + // Velocity management + private float _baseMoveSpeed; + private float _velocityFactor = 1.0f; + private void Awake() { _mainCamera = Camera.main; + _baseMoveSpeed = moveSpeed; // Store the original base speed // Calculate tile heights for each prefab CalculateTileHeights(); @@ -89,15 +108,57 @@ namespace Minigames.DivingForPictures { CalculateScreenBounds(); SpawnInitialTiles(); + + // Initialize velocity and start the velocity calculation coroutine + _currentVelocity = moveSpeed * Time.fixedDeltaTime; + StartCoroutine(VelocityCalculationRoutine()); } private void Update() { - MoveTiles(); + HandleMovement(); HandleTileDestruction(); HandleTileSpawning(); HandleSpeedRamping(); } + + /// + /// Gets the current velocity of the tiles + /// + /// The current upward velocity of the tiles + public float GetCurrentVelocity() + { + return _currentVelocity; + } + + /// + /// Sets a custom velocity, overriding the calculated one + /// + /// The new velocity value + public void SetVelocity(float velocity) + { + _currentVelocity = velocity; + } + + /// + /// Coroutine that periodically calculates the velocity based on game state + /// + private IEnumerator VelocityCalculationRoutine() + { + while (true) + { + CalculateVelocity(); + yield return new WaitForSeconds(velocityCalculationInterval); + } + } + + /// + /// Calculates the current velocity based on move speed + /// + private void CalculateVelocity() + { + _currentVelocity = moveSpeed * Time.fixedDeltaTime; + } /// /// Calculate height values for all tile prefabs @@ -170,9 +231,25 @@ namespace Minigames.DivingForPictures /// private void SpawnInitialTiles() { + // Calculate starting Y position - moved 2 tiles up from the bottom of the screen + float startingY = _screenBottom; + + // If we have prefab tiles with known heights, use their average height for offset calculation + float tileHeightEstimate = DefaultTileHeight; + if (tilePrefabs != null && tilePrefabs.Count > 0 && tilePrefabs[0] != null) + { + if (_tileHeights.TryGetValue(tilePrefabs[0], out float height)) + { + tileHeightEstimate = height; + } + } + + // Move starting position up by 2 tile heights + startingY += tileHeightEstimate * 2; + for (int i = 0; i < initialTileCount; i++) { - float y = _screenBottom; + float y = startingY; // Calculate proper Y position based on previous tiles if (i > 0 && _activeTiles.Count > 0) { @@ -206,16 +283,61 @@ namespace Minigames.DivingForPictures } /// - /// Move all active tiles upward + /// Called when the velocity factor changes from the DivingGameManager /// - private void MoveTiles() + public void OnVelocityFactorChanged(float velocityFactor) + { + _velocityFactor = velocityFactor; + + // Update the actual move speed based on the velocity factor + // This keeps the original move speed intact for game logic + moveSpeed = _baseMoveSpeed * Mathf.Abs(_velocityFactor); + + // Recalculate velocity immediately + CalculateVelocity(); + + Debug.Log($"[TrenchTileSpawner] Velocity factor updated to {_velocityFactor:F2}, moveSpeed: {moveSpeed:F2}"); + } + + /// + /// Reverses direction to start surfacing + /// + public void StartSurfacing() + { + if (_isSurfacing) return; // Already surfacing + + // Set surfacing flag for spawn/despawn logic + _isSurfacing = true; + + // Reverse the active tiles array to maintain consistent indexing logic + _activeTiles.Reverse(); + + Debug.Log("[TrenchTileSpawner] Started surfacing - reversed array order"); + } + + /// + /// Stops spawning new tiles + /// + public void StopSpawning() + { + _stopSpawning = true; + } + + /// + /// Handles the movement of all active tiles based on the current velocity + /// + private void HandleMovement() { - float moveDelta = moveSpeed * Time.deltaTime; foreach (var tile in _activeTiles) { if (tile != null) { - tile.transform.position += Vector3.up * moveDelta; + // Use velocity factor to determine direction + Vector3 direction = Vector3.up * Mathf.Sign(_velocityFactor); + float speed = _currentVelocity; + + // Apply movement + tile.transform.position += direction * speed; } } } @@ -235,7 +357,20 @@ namespace Minigames.DivingForPictures } float tileHeight = GetTileHeight(topTile); - if (topTile.transform.position.y - tileHeight / 2 > _screenTop + tileSpawnBuffer) + + bool shouldDestroy; + if (_isSurfacing) + { + // When surfacing, destroy tiles at the bottom + shouldDestroy = topTile.transform.position.y + tileHeight / 2 < _screenBottom - tileSpawnBuffer; + } + else + { + // When descending, destroy tiles at the top + shouldDestroy = topTile.transform.position.y - tileHeight / 2 > _screenTop + tileSpawnBuffer; + } + + if (shouldDestroy) { _activeTiles.RemoveAt(0); onTileDestroyed?.Invoke(topTile); @@ -265,7 +400,15 @@ namespace Minigames.DivingForPictures /// private void HandleTileSpawning() { - if (_activeTiles.Count == 0) return; + if (_activeTiles.Count == 0) + { + // If we have no active tiles and spawning is stopped, trigger the event + if (_stopSpawning) + { + onLastTileLeft.Invoke(); + } + return; + } GameObject bottomTile = _activeTiles[^1]; if (bottomTile == null) @@ -274,15 +417,60 @@ namespace Minigames.DivingForPictures return; } + // Get the tile height once to use in all calculations float tileHeight = GetTileHeight(bottomTile); - float bottomEdge = bottomTile.transform.position.y - tileHeight / 2; - if (bottomEdge > _screenBottom - tileSpawnBuffer) + + // If we're in stop spawning mode, don't spawn new tiles + if (_stopSpawning) + { + // Check if this is the last tile, and if it's about to leave the screen + if (_activeTiles.Count == 1) + { + bool isLastTileLeaving; + + if (_isSurfacing) + { + // When surfacing, check if the bottom of the tile is above the top of the screen + isLastTileLeaving = bottomTile.transform.position.y - tileHeight / 2 > _screenTop + tileSpawnBuffer; + } + else + { + // When descending, check if the top of the tile is below the bottom of the screen + isLastTileLeaving = bottomTile.transform.position.y + tileHeight / 2 < _screenBottom - tileSpawnBuffer; + } + + if (isLastTileLeaving) + { + onLastTileLeft.Invoke(); + } + } + return; + } + + bool shouldSpawn; + float newY; + + if (_isSurfacing) + { + // When surfacing, spawn new tiles at the top + float topEdge = bottomTile.transform.position.y + tileHeight / 2; + shouldSpawn = topEdge < _screenTop + tileSpawnBuffer; + newY = bottomTile.transform.position.y + tileHeight; + } + else + { + // When descending, spawn new tiles at the bottom + float bottomEdge = bottomTile.transform.position.y - tileHeight / 2; + shouldSpawn = bottomEdge > _screenBottom - tileSpawnBuffer; + newY = bottomTile.transform.position.y - tileHeight; + } + + if (shouldSpawn) { - float newY = bottomTile.transform.position.y - tileHeight; SpawnTileAtY(newY); } } - + /// /// Handle increasing the movement speed over time /// diff --git a/ProjectSettings/TagManager.asset b/ProjectSettings/TagManager.asset index c795aa89..3436af9a 100644 --- a/ProjectSettings/TagManager.asset +++ b/ProjectSettings/TagManager.asset @@ -6,6 +6,7 @@ TagManager: tags: - CharacterArt - Pulver + - Rock layers: - Default - TransparentFX