From 95700b71c1efbd17bb306edefc9b351defb91a65 Mon Sep 17 00:00:00 2001 From: "Bob.Song" <605277374@qq.com> Date: Sun, 12 Apr 2026 23:19:41 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=BA=BF=E7=9A=84=E6=B8=B2?= =?UTF-8?q?=E6=9F=93=E9=95=BF=E5=BA=A6=E4=B8=8D=E4=B8=80=E8=87=B4=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/Scripts/Fishing/Rope/Rope.cs | 76 ++++++++++++++++++++++------- 1 file changed, 58 insertions(+), 18 deletions(-) diff --git a/Assets/Scripts/Fishing/Rope/Rope.cs b/Assets/Scripts/Fishing/Rope/Rope.cs index 03a9cf3a8..e4e60a055 100644 --- a/Assets/Scripts/Fishing/Rope/Rope.cs +++ b/Assets/Scripts/Fishing/Rope/Rope.cs @@ -31,6 +31,12 @@ public class Rope : MonoBehaviour [SerializeField, Range(0, 16), Tooltip("主求解后追加的硬长度约束次数。只负责把 poly 拉回到 rest total,不改变可变长度逻辑")] private int hardTightenIterations = 2; + [SerializeField, Range(0, 32), Tooltip("当绳子接近拉直时,按误差自动追加的硬长度约束次数上限")] + private int adaptiveHardTightenMaxIterations = 8; + + [SerializeField, Min(0f), Tooltip("单段允许的最大超长误差;超过时继续追加硬长度约束")] + private float hardConstraintTolerance = 0.0005f; + [Header("Length Control (No Min/Max Clamp)")] [Tooltip("初始总长度(米)。如果为 0,则用 physicsSegmentLen*(minPhysicsNodes-1) 作为初始长度")] [SerializeField, Min(0f)] @@ -211,6 +217,8 @@ public class Rope : MonoBehaviour renderSubdivisionsMoving = Mathf.Max(renderSubdivisionsMoving, 1); iterations = Mathf.Clamp(iterations, 1, 80); hardTightenIterations = Mathf.Clamp(hardTightenIterations, 0, 16); + adaptiveHardTightenMaxIterations = Mathf.Clamp(adaptiveHardTightenMaxIterations, 0, 32); + hardConstraintTolerance = Mathf.Max(0f, hardConstraintTolerance); groundCastDistance = Mathf.Max(groundCastDistance, 0.01f); groundCastHeight = Mathf.Max(groundCastHeight, 0f); lineWidth = Mathf.Max(lineWidth, 0.0001f); @@ -532,6 +540,7 @@ public class Rope : MonoBehaviour } SolveHardDistanceConstraints(hardTightenIterations); + SolveHardDistanceConstraintsAdaptive(); LockAnchorsHard(); if (constrainToGround) @@ -572,16 +581,7 @@ public class Rope : MonoBehaviour EnsureRenderCaches(); int last = _physicsNodes - 1; - - Vector3 s = _startTr.position; - Vector3 e = _endTr.position; - - _pCurr[0] = s; - _pCurr[last] = e; - // _pPrev[0] = s; - // _pPrev[last] = e; - - DrawHighResLine_Fast(); + DrawHighResLine_Fast(_startTr.position, _endTr.position, last); } private void UpdateLengthSmooth() @@ -734,6 +734,21 @@ public class Rope : MonoBehaviour } } + private void SolveHardDistanceConstraintsAdaptive() + { + if (adaptiveHardTightenMaxIterations <= 0 || hardConstraintTolerance <= 0f) + return; + + for (int it = 0; it < adaptiveHardTightenMaxIterations; it++) + { + if (GetMaxPositiveSegmentDelta() <= hardConstraintTolerance) + break; + + LockAnchorsHard(); + SolveDistanceConstraints_HeadOnly_Hard(); + } + } + private void SolveDistanceConstraints_HeadOnly_Hard() { SolveDistanceConstraints_HeadOnly_Bidirectional(1f); @@ -787,6 +802,21 @@ public class Rope : MonoBehaviour } } + private float GetMaxPositiveSegmentDelta() + { + float maxDelta = 0f; + for (int i = 1; i < _physicsNodes; i++) + { + float rest = (i == 1) ? _headRestLen : physicsSegmentLen; + float segLen = Vector3.Distance(_pCurr[i - 1], _pCurr[i]); + float delta = segLen - rest; + if (delta > maxDelta) + maxDelta = delta; + } + + return maxDelta; + } + private void ConstrainToGround() { if (groundMask == 0) return; @@ -938,7 +968,7 @@ public class Rope : MonoBehaviour } } - private void DrawHighResLine_Fast() + private void DrawHighResLine_Fast(Vector3 renderStart, Vector3 renderEnd, int last) { if (_pCurr == null || _physicsNodes < 2) return; @@ -949,7 +979,9 @@ public class Rope : MonoBehaviour if (!smooth) { _lineRenderer.positionCount = _physicsNodes; - _lineRenderer.SetPositions(_pCurr); + for (int i = 0; i <= last; i++) + _rPoints[i] = GetRenderPoint(i, last, renderStart, renderEnd); + _lineRenderer.SetPositions(_rPoints); return; } @@ -964,7 +996,6 @@ public class Rope : MonoBehaviour } int idx = 0; - int last = _physicsNodes - 1; for (int seg = 0; seg < last; seg++) { @@ -975,10 +1006,10 @@ public class Rope : MonoBehaviour int i3 = seg + 2; if (i3 > last) i3 = last; - Vector3 p0 = _pCurr[i0]; - Vector3 p1 = _pCurr[i1]; - Vector3 p2 = _pCurr[i2]; - Vector3 p3 = _pCurr[i3]; + Vector3 p0 = GetRenderPoint(i0, last, renderStart, renderEnd); + Vector3 p1 = GetRenderPoint(i1, last, renderStart, renderEnd); + Vector3 p2 = GetRenderPoint(i2, last, renderStart, renderEnd); + Vector3 p3 = GetRenderPoint(i3, last, renderStart, renderEnd); for (int s = 0; s < subdiv; s++) { @@ -1001,12 +1032,21 @@ public class Rope : MonoBehaviour } } - _rPoints[idx++] = _pCurr[last]; + _rPoints[idx++] = renderEnd; _lineRenderer.positionCount = idx; _lineRenderer.SetPositions(_rPoints); } + private Vector3 GetRenderPoint(int index, int last, Vector3 renderStart, Vector3 renderEnd) + { + if (index <= 0) + return renderStart; + if (index >= last) + return renderEnd; + return _pCurr[index]; + } + private static float ClampMonotonic(float value, float p0, float p1, float p2, float p3) { bool rising = p0 <= p1 && p1 <= p2 && p2 <= p3;