From 2942b22c623d3eef079a2e770f1f728db19a95c8 Mon Sep 17 00:00:00 2001 From: Michal Pikulski Date: Mon, 22 Sep 2025 00:01:28 +0200 Subject: [PATCH] Add background --- Assets/Art/Textures/DivingBackground.png | Bin 0 -> 26555 bytes Assets/Art/Textures/DivingBackground.png.meta | 195 +++++++++ .../Scenes/MiniGames/DivingForPictures.unity | 149 ++++++- .../DivingForPictures/RopeBreaker.cs | 10 +- .../RopeEndPhysicsFollower.cs | 376 ++++++++---------- 5 files changed, 505 insertions(+), 225 deletions(-) create mode 100644 Assets/Art/Textures/DivingBackground.png create mode 100644 Assets/Art/Textures/DivingBackground.png.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/Scenes/MiniGames/DivingForPictures.unity b/Assets/Scenes/MiniGames/DivingForPictures.unity index 9f57b92b..e30a8a07 100644 --- a/Assets/Scenes/MiniGames/DivingForPictures.unity +++ b/Assets/Scenes/MiniGames/DivingForPictures.unity @@ -436,12 +436,10 @@ MonoBehaviour: ropeFollowSpeed: 5 ropeTrailing: 0.2 ropeGravityStrength: 9.8 - ropeMaxHangDistance: 2 ropeVerticalHangStrength: 2 - ropeOscillationAmplitude: 0.15 - ropeOscillationFrequency: 2 ropeDamping: 0.3 initialSeparationDistance: 0.1 + initialFallImpulse: 2 --- !u!1 &224729330 GameObject: m_ObjectHideFlags: 0 @@ -644,6 +642,93 @@ 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} + 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.12, 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!1 &730962732 GameObject: m_ObjectHideFlags: 0 @@ -1319,12 +1404,10 @@ MonoBehaviour: ropeFollowSpeed: 5 ropeTrailing: 0.2 ropeGravityStrength: 9.8 - ropeMaxHangDistance: 2 ropeVerticalHangStrength: 2 - ropeOscillationAmplitude: 0.15 - ropeOscillationFrequency: 2 ropeDamping: 0.3 initialSeparationDistance: 0.1 + initialFallImpulse: 2 --- !u!1 &1063641111 GameObject: m_ObjectHideFlags: 0 @@ -1337,6 +1420,7 @@ GameObject: - component: {fileID: 1063641113} - component: {fileID: 1063641112} - component: {fileID: 1063641115} + - component: {fileID: 1063641116} m_Layer: 0 m_Name: Main Camera m_TagString: MainCamera @@ -1361,8 +1445,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 @@ -1450,6 +1534,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 @@ -1816,12 +1944,10 @@ MonoBehaviour: ropeFollowSpeed: 5 ropeTrailing: 0.2 ropeGravityStrength: 9.8 - ropeMaxHangDistance: 2 ropeVerticalHangStrength: 2 - ropeOscillationAmplitude: 0.1 - ropeOscillationFrequency: 3 ropeDamping: 0.3 initialSeparationDistance: 0.1 + initialFallImpulse: 2 --- !u!1 &1679185997 GameObject: m_ObjectHideFlags: 0 @@ -2128,3 +2254,4 @@ SceneRoots: - {fileID: 116234201} - {fileID: 824396217} - {fileID: 323864665} + - {fileID: 461301697} diff --git a/Assets/Scripts/Minigames/DivingForPictures/RopeBreaker.cs b/Assets/Scripts/Minigames/DivingForPictures/RopeBreaker.cs index ee91c5c1..fa0b022c 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/RopeBreaker.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/RopeBreaker.cs @@ -40,9 +40,6 @@ public class RopeBreaker : MonoBehaviour [Tooltip("Initial downward impulse for falling rope end")] [SerializeField] private float initialFallImpulse = 2.0f; - - [Tooltip("Force Y position reset on start to ensure proper falling")] - [SerializeField] private bool forceYReset = true; // Private references private Rope originalRope; @@ -122,10 +119,9 @@ public class RopeBreaker : MonoBehaviour // 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; - follower.useGravity = true; // Player rope end doesn't use gravity // Create second break point (for the rock-attached end) GameObject secondBreakObj = new GameObject("RopeBreakPoint_Second"); @@ -138,15 +134,13 @@ public class RopeBreaker : MonoBehaviour // 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.useGravity = true; // Enable gravity for hanging rope end secondFollower.gravityStrength = ropeGravityStrength; secondFollower.verticalHangStrength = ropeVerticalHangStrength; secondFollower.damping = ropeDamping; secondFollower.initialFallImpulse = initialFallImpulse; - secondFollower.forceYReset = forceYReset; // Create initial separation Vector3 direction = (originalEndPoint.position - breakPointPosition).normalized; diff --git a/Assets/Scripts/Minigames/DivingForPictures/RopeEndPhysicsFollower.cs b/Assets/Scripts/Minigames/DivingForPictures/RopeEndPhysicsFollower.cs index 2d832e54..a9549101 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/RopeEndPhysicsFollower.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/RopeEndPhysicsFollower.cs @@ -4,43 +4,196 @@ using UnityEngine; public class RopeEndPhysicsFollower : MonoBehaviour { [Header("Target Settings")] - [Tooltip("Tag of the object this endpoint should follow (used if targetTransform is not set)")] - public string targetTag; - [Tooltip("Transform this endpoint should follow (takes precedence over targetTag)")] + [Tooltip("Transform this endpoint should follow")] public Transform targetTransform; - [Tooltip("How quickly the endpoint follows the target")] + [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("Enable/disable gravity effect")] - public bool useGravity = true; [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 gravity is enabled")] + [Tooltip("Initial downward impulse when enabled")] public float initialFallImpulse = 2.0f; - [Tooltip("Force a Y position reset on start to ensure falling occurs")] - public bool forceYReset = true; + [Tooltip("Whether this end can fall with gravity (false for player-attached ends)")] + public bool canFall = true; // Private variables private Transform target; - private Vector3 velocity; 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(); @@ -82,172 +235,6 @@ public class RopeEndPhysicsFollower : MonoBehaviour maxDistance = 2f; if (debugLog) Debug.Log("[RopeEndPhysicsFollower] No attached rope found, using default max distance"); } - - // 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 - 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 using gravity - if (useGravity) - { - physicsVelocity = new Vector2(0, -initialFallImpulse); - - // Force an initial position change to ensure things start moving - if (forceYReset) - { - Vector3 pos = transform.position; - pos.y = target.position.y; // Reset to target's Y position - transform.position = pos; - } - - if (debugLog) Debug.Log($"[RopeEndPhysicsFollower] Initialized with target: {target.name}, gravity enabled, initial Y velocity: {physicsVelocity.y}"); - } - } - else - { - offset = Vector2.zero; - lastTargetPosition = transform.position; - if (debugLog) Debug.Log($"[RopeEndPhysicsFollower] No target found"); - } - - velocity = Vector3.zero; - 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; - - // Basic position the endpoint should be at based on target position and horizontal offset - Vector3 basePosition = target.position + new Vector3(offset.x, 0, 0); - - // Apply physics simulation if enabled - if (useGravity) - { - // Get the straight-line distance between target and this transform - float currentDistance = Vector2.Distance( - new Vector2(transform.position.x, transform.position.y), - new Vector2(target.position.x, target.position.y) - ); - - // Current position relative to target - Vector2 relativePos = new Vector2( - transform.position.x - target.position.x, - transform.position.y - target.position.y - ); - - // Normalized direction from target to this transform - Vector2 directionToTarget = relativePos.normalized; - - // Apply forces: - // 1. Gravity - always pulls down - physicsVelocity.y -= gravityStrength * deltaTime; - - // 2. Vertical hanging force - try to align X with target (not with world origin) - 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; - 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; - } - } - else - { - // Original smooth follow behavior without physics - transform.position = Vector3.SmoothDamp(transform.position, basePosition, ref velocity, trailing, followSpeed); - } } public void SetTargetTransform(Transform newTarget) @@ -273,8 +260,8 @@ public class RopeEndPhysicsFollower : MonoBehaviour offset.y = 0; // Don't preserve vertical offset for gravity simulation } - // Apply initial falling impulse if using gravity - if (useGravity) + // 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}"); @@ -289,30 +276,7 @@ public class RopeEndPhysicsFollower : MonoBehaviour GameObject found = GameObject.FindGameObjectWithTag(targetTag); if (found) { - targetTransform = found.transform; - target = found.transform; - 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 using gravity - if (useGravity) - { - physicsVelocity = new Vector2(physicsVelocity.x, -initialFallImpulse); - if (debugLog) Debug.Log($"[RopeEndPhysicsFollower] Reset Y velocity to {physicsVelocity.y} after target change"); - } + SetTargetTransform(found.transform); } } @@ -323,16 +287,16 @@ public class RopeEndPhysicsFollower : MonoBehaviour { // 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) {