From c33bc44ba5cf066db41a0dc52d0f58c7d8938ec1 Mon Sep 17 00:00:00 2001 From: BobSong <605277374@qq.com> Date: Sat, 10 May 2025 21:10:06 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=B3=E5=AD=90=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/Scenes/SampleScene.unity | 10 +-- Assets/Scripts/Rope.cs | 104 +++++++++++++++++++++++--------- 2 files changed, 81 insertions(+), 33 deletions(-) diff --git a/Assets/Scenes/SampleScene.unity b/Assets/Scenes/SampleScene.unity index 5f54f4638..bef4f7ba7 100644 --- a/Assets/Scenes/SampleScene.unity +++ b/Assets/Scenes/SampleScene.unity @@ -404,7 +404,7 @@ BoxCollider: m_ProvidesContacts: 0 m_Enabled: 1 serializedVersion: 3 - m_Size: {x: 10, y: 2, z: 10} + m_Size: {x: 10, y: 1, z: 10} m_Center: {x: 0, y: 0, z: 0} --- !u!23 &306060541 MeshRenderer: @@ -468,8 +468,8 @@ Transform: m_GameObject: {fileID: 306060539} serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: -100, z: 10} - m_LocalScale: {x: 10, y: 2, z: 10} + m_LocalPosition: {x: 0, y: -3, z: 10} + m_LocalScale: {x: 14.43, y: 2, z: 16.04} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} @@ -934,9 +934,9 @@ MonoBehaviour: m_EditorClassIdentifier: mouseOffset: 10 nodeDistance: 0.1 - nodeColliderRadius: 0.2 + nodeColliderRadius: 0.3 gravityStrength: 1.962 - totalLength: 10 + totalLength: 6 velocityDampen: 0.95 stiffness: 0.99 iterateCollisionsEvery: 1 diff --git a/Assets/Scripts/Rope.cs b/Assets/Scripts/Rope.cs index ff47ea980..a48e749a1 100644 --- a/Assets/Scripts/Rope.cs +++ b/Assets/Scripts/Rope.cs @@ -11,7 +11,7 @@ public class Rope : MonoBehaviour [SerializeField] float nodeColliderRadius = 0.2f; [SerializeField] float gravityStrength = 2; - [SerializeField] float totalLength = 10f; // 新增总长度参数 + [SerializeField] float totalLength = 10f; [SerializeField, Range(0, 1)] float velocityDampen = 0.95f; [SerializeField, Range(0, 0.99f)] float stiffness = 0.8f; [SerializeField, Range(1, 10)] int iterateCollisionsEvery = 1; @@ -36,25 +36,11 @@ public class Rope : MonoBehaviour LineRenderer lineRenderer; GameObject nodeTester; SphereCollider nodeCollider; - int totalNodes; // 现在由代码计算 + int totalNodes; + float lastTotalLength; // 用于检测长度变化 void Awake() { - // 计算节点数量 - totalNodes = Mathf.FloorToInt(totalLength / nodeDistance) + 1; - float remainingLength = totalLength % nodeDistance; - - // 如果剩余长度大于0,增加一个节点 - if (remainingLength > 0 && totalLength > nodeDistance) - { - totalNodes++; - } - - // 初始化数组 - currentNodePositions = new Vector3[totalNodes]; - previousNodePositions = new Vector3[totalNodes]; - colliderHitBuffer = new Collider[colliderBufferSize]; - // 获取组件引用 lineRenderer = GetComponent(); cam = Camera.main; @@ -66,25 +52,59 @@ public class Rope : MonoBehaviour nodeCollider = nodeTester.AddComponent(); nodeCollider.radius = nodeColliderRadius; + // 初始化长度跟踪 + lastTotalLength = totalLength; + InitializeRope(); + } + + void InitializeRope() + { + // 计算节点数量 + totalNodes = Mathf.FloorToInt(totalLength / nodeDistance) + 1; + float remainingLength = totalLength % nodeDistance; + + // 如果剩余长度大于0,增加一个节点 + if (remainingLength > 0 && totalLength > nodeDistance) + { + totalNodes++; + } + + // 初始化或调整数组大小 + System.Array.Resize(ref currentNodePositions, totalNodes); + System.Array.Resize(ref previousNodePositions, totalNodes); + colliderHitBuffer = new Collider[colliderBufferSize]; + // 初始化节点位置 Vector3 startPos = transform.position; for (int i = 0; i < totalNodes; i++) { // 如果是最后一个节点且有剩余长度,使用剩余长度 float distance = (i == totalNodes - 1 && remainingLength > 0) ? remainingLength : nodeDistance; - - currentNodePositions[i] = startPos; - previousNodePositions[i] = startPos; + + // 如果数组已有数据,保持现有位置,否则初始化新位置 + if (currentNodePositions[i] == null) + { + currentNodePositions[i] = startPos; + previousNodePositions[i] = startPos; + } startPos.y -= distance; } // 设置线渲染器 lineRenderer.startWidth = ropeWidth; lineRenderer.endWidth = ropeWidth; + lineRenderer.positionCount = totalNodes; } void Update() { + // 检查长度是否变化 + if (!Mathf.Approximately(totalLength, lastTotalLength)) + { + AdjustRopeLength(); + lastTotalLength = totalLength; + } + // 处理鼠标输入 if (Input.GetMouseButtonDown(0)) { @@ -111,6 +131,36 @@ public class Rope : MonoBehaviour DrawRope(); } + void AdjustRopeLength() + { + // 保存旧位置 + Vector3[] oldPositions = (Vector3[])currentNodePositions.Clone(); + Vector3[] oldPrevPositions = (Vector3[])previousNodePositions.Clone(); + + // 重新初始化绳索 + InitializeRope(); + + // 尽可能保留旧位置数据 + int copyLength = Mathf.Min(oldPositions.Length, currentNodePositions.Length); + System.Array.Copy(oldPositions, currentNodePositions, copyLength); + System.Array.Copy(oldPrevPositions, previousNodePositions, copyLength); + + // 如果长度增加,初始化新增节点的位置 + if (currentNodePositions.Length > oldPositions.Length) + { + Vector3 lastPos = oldPositions[oldPositions.Length - 1]; + for (int i = oldPositions.Length; i < currentNodePositions.Length; i++) + { + float distance = (i == currentNodePositions.Length - 1 && (totalLength % nodeDistance) > 0) ? + (totalLength % nodeDistance) : nodeDistance; + + lastPos.y -= distance; + currentNodePositions[i] = lastPos; + previousNodePositions[i] = lastPos; + } + } + } + void FixedUpdate() { Simulate(); @@ -164,10 +214,9 @@ public class Rope : MonoBehaviour Vector3 diff = node1 - node2; // 计算期望的距离 - 如果是最后一个段且有剩余长度,使用剩余长度 - float desiredDistance = (i == nodeCountMinusOne - 1 && (totalLength % nodeDistance) > 0) - ? (totalLength % nodeDistance) - : nodeDistance; - + float desiredDistance = (i == nodeCountMinusOne - 1 && (totalLength % nodeDistance) > 0) ? + (totalLength % nodeDistance) : nodeDistance; + float sqrDesiredDistance = desiredDistance * desiredDistance; float sqrDistance = diff.x * diff.x + diff.y * diff.y + diff.z * diff.z; @@ -176,7 +225,7 @@ public class Rope : MonoBehaviour { float distance = Mathf.Sqrt(sqrDistance); float difference = desiredDistance - distance; - Vector3 direction = diff / distance; // 比 normalized 更快 + Vector3 direction = diff / distance; Vector3 adjustment = direction * (difference * halfStiffness); @@ -188,13 +237,13 @@ public class Rope : MonoBehaviour void AdjustCollisions() { - for (int i = 1; i < totalNodes; i += 2) // 跳过更多节点减少计算 + for (int i = 1; i < totalNodes; i += 2) { int hits = Physics.OverlapSphereNonAlloc( currentNodePositions[i], nodeColliderRadius, colliderHitBuffer, - ~(1 << 8)); // 忽略特定层 + ~(1 << 8)); for (int n = 0; n < hits; n++) { @@ -216,7 +265,6 @@ public class Rope : MonoBehaviour void DrawRope() { - // 直接使用currentNodePositions数组避免额外拷贝 lineRenderer.positionCount = totalNodes; lineRenderer.SetPositions(currentNodePositions); }