diff --git a/Assets/ResRaw/Prefabs/Line/LineHand1.prefab b/Assets/ResRaw/Prefabs/Line/LineHand1.prefab index 62f488b75..e61eac7a0 100644 --- a/Assets/ResRaw/Prefabs/Line/LineHand1.prefab +++ b/Assets/ResRaw/Prefabs/Line/LineHand1.prefab @@ -47,7 +47,7 @@ MonoBehaviour: m_EditorClassIdentifier: startAnchor: {fileID: 5597807613657979793} endAnchor: {fileID: 54298866000586118} - LineMultiple: 5 + LineMultiple: 1 physicsSegmentLen: 0.1 minPhysicsNodes: 2 maxPhysicsNodes: 200 @@ -56,6 +56,8 @@ MonoBehaviour: stiffness: 0.8 iterations: 10 hardTightenIterations: 2 + adaptiveHardTightenMaxIterations: 8 + hardConstraintTolerance: 0.0005 initialLength: 0 lengthSmoothTime: 0.15 lengthChangeVelocityKill: 0.4 @@ -217,7 +219,7 @@ GameObject: - component: {fileID: 2951454344396477079} - component: {fileID: 2305106969988397276} - component: {fileID: 6377942246174119720} - m_Layer: 7 + m_Layer: 15 m_Name: End m_TagString: Untagged m_Icon: {fileID: 0} @@ -493,7 +495,7 @@ GameObject: - component: {fileID: 4367274852511404246} - component: {fileID: 8491405271793597799} - component: {fileID: 6946262978138518655} - m_Layer: 16 + m_Layer: 15 m_Name: Float m_TagString: Untagged m_Icon: {fileID: 0} @@ -766,7 +768,7 @@ MonoBehaviour: m_EditorClassIdentifier: startAnchor: {fileID: 54298866000586118} endAnchor: {fileID: 54679398375713381} - LineMultiple: 5 + LineMultiple: 1 physicsSegmentLen: 0.2 minPhysicsNodes: 2 maxPhysicsNodes: 120 @@ -775,6 +777,8 @@ MonoBehaviour: stiffness: 0.8 iterations: 10 hardTightenIterations: 2 + adaptiveHardTightenMaxIterations: 8 + hardConstraintTolerance: 0.0005 initialLength: 0 lengthSmoothTime: 0.15 lengthChangeVelocityKill: 0.6 @@ -933,7 +937,7 @@ GameObject: - component: {fileID: 9208415877353988341} - component: {fileID: 5597807613657979793} - component: {fileID: 3463242999848273700} - m_Layer: 0 + m_Layer: 15 m_Name: Start m_TagString: Untagged m_Icon: {fileID: 0} diff --git a/Assets/Scripts/Fishing/Item/FishingLine/FLine.cs b/Assets/Scripts/Fishing/Item/FishingLine/FLine.cs index 80aac7453..1d824a1d1 100644 --- a/Assets/Scripts/Fishing/Item/FishingLine/FLine.cs +++ b/Assets/Scripts/Fishing/Item/FishingLine/FLine.cs @@ -99,7 +99,7 @@ namespace NBF BobberNode.gameObject.SetActive(false); BobberNode.Rope.gameObject.SetActive(false); EndNode.SetConnectedBody(StartNode.Rigidbody); - EndNode.SetLenght(totalLenght); + EndNode.SetLenght(totalLenght + 0.2f); } else { diff --git a/Assets/Scripts/Fishing/Item/FishingLine/FLineLogicNode.cs b/Assets/Scripts/Fishing/Item/FishingLine/FLineLogicNode.cs index ffbe796a2..88639218a 100644 --- a/Assets/Scripts/Fishing/Item/FishingLine/FLineLogicNode.cs +++ b/Assets/Scripts/Fishing/Item/FishingLine/FLineLogicNode.cs @@ -50,7 +50,7 @@ namespace NBF if (rope) { - rope.SetTargetLength(lenght); + rope.SetTargetLength(lenght - lenght * 0.02f); } } diff --git a/Assets/Scripts/Fishing/Item/FishingLine/Rope.cs b/Assets/Scripts/Fishing/Item/FishingLine/Rope.cs index 214944abc..1e65c84ab 100644 --- a/Assets/Scripts/Fishing/Item/FishingLine/Rope.cs +++ b/Assets/Scripts/Fishing/Item/FishingLine/Rope.cs @@ -14,23 +14,29 @@ public class Rope : MonoBehaviour [Header("Physics (Dynamic Nodes, Fixed Segment Len)")] [SerializeField, Min(0.01f), Tooltip("物理每段固定长度(越小越细致越耗)")] private float physicsSegmentLen = 0.15f; - [SerializeField, Range(2, 200)] private int minPhysicsNodes = 12; + [SerializeField, Range(2, 200)] private int minPhysicsNodes = 2; [SerializeField, Range(2, 400), Tooltip("物理节点上限(仅用于性能保护;与“最大长度不限制”不是一回事)")] - private int maxPhysicsNodes = 120; + private int maxPhysicsNodes = 200; - [SerializeField] private float gravityStrength = 2.0f; + [SerializeField] private float gravityStrength = 6.0f; [SerializeField, Range(0f, 1f)] private float velocityDampen = 0.95f; [SerializeField, Range(0.0f, 1.0f), Tooltip("约束修正强度,越大越硬。0.6~0.9 常用")] private float stiffness = 0.8f; - [SerializeField, Range(1, 80), Tooltip("迭代次数。鱼线 10~30 通常够用")] - private int iterations = 20; + [SerializeField, Range(1, 80), Tooltip("迭代次数")] + private int iterations = 10; [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)] @@ -40,7 +46,7 @@ public class Rope : MonoBehaviour private float lengthSmoothTime = 0.15f; [Tooltip("当长度在变化时,额外把速度压掉一些(防抖)。0=不额外处理,1=变化时几乎清速度(建议只在收线生效)")] [SerializeField, Range(0f, 1f)] - private float lengthChangeVelocityKill = 0.6f; + private float lengthChangeVelocityKill = 0.4f; [Tooltip("允许的最小松弛余量(避免目标长度刚好等于锚点距离时抖动)")] [SerializeField, Min(0f)] private float minSlack = 0.002f; @@ -52,9 +58,9 @@ public class Rope : MonoBehaviour private float nodeHysteresis = 0.05f; [Header("Simple Ground/Water Constraint (Cheap)")] [SerializeField] - private bool constrainToGround = true; + private bool constrainToGround = false; - [SerializeField] private LayerMask groundMask = ~0; + [SerializeField] private LayerMask groundMask = 0; [SerializeField, Min(0f)] private float groundRadius = 0.01f; [SerializeField, Min(0f)] private float groundCastHeight = 1.0f; [SerializeField, Min(0.01f)] private float groundCastDistance = 2.5f; @@ -66,7 +72,7 @@ public class Rope : MonoBehaviour private bool groundInterpolate = true; [SerializeField, Range(1, 8), Tooltip("每隔多少次FixedUpdate更新一次地面约束")] - private int groundUpdateEvery = 2; + private int groundUpdateEvery = 1; [SerializeField, Range(0, 8), Tooltip("地面约束后,再做几次长度约束,减少 poly 被地面抬长")] private int groundPostConstraintIterations = 2; @@ -74,7 +80,7 @@ public class Rope : MonoBehaviour private int _groundFrameCounter; [Header("Simple Water Float (Cheap)")] [SerializeField, Tooltip("绳子落到水面以下时,是否把节点约束回水面")] - private bool constrainToWaterSurface = true; + private bool constrainToWaterSurface = false; [SerializeField, Tooltip("静态水面高度;如果你后面接波浪水面,可改成采样函数")] private float waterLevelY = 0f; @@ -129,7 +135,7 @@ public class Rope : MonoBehaviour private float visibilityViewportPadding = 0.08f; [Header("Air Drag (Stable)")] [SerializeField, Range(0f, 5f), Tooltip("空气阻力(Y向),指数衰减,越大越不飘")] - private float airDrag = 0.9f; + private float airDrag = 0.2f; [SerializeField, Range(0f, 2f), Tooltip("横向额外阻力(XZ),指数衰减,越大越不左右飘")] private float airDragXZ = 0.6f; @@ -172,7 +178,7 @@ public class Rope : MonoBehaviour private bool _isCulledByVisibility; private int _tIdleSubdiv = -1; private int _tMovingSubdiv = -1; - + // Catmull t caches(只缓存 idle/moving 两档,减少每帧重复乘法) private struct TCaches @@ -198,12 +204,15 @@ public class Rope : MonoBehaviour RefreshVisibilityState(true); } + private void OnValidate() { renderSubdivisionsIdle = Mathf.Max(renderSubdivisionsIdle, 1); 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); @@ -236,15 +245,6 @@ public class Rope : MonoBehaviour _endTr = endAnchor ? endAnchor.transform : null; } - private bool ShouldAlwaysSimulate() - { - if (!localOwnerAlwaysSimulate) - return false; - - // var owner = _rod?.PlayerItem?.Owner; - // return owner == null || owner.IsSelf; - return true; - } private Transform GetActiveCameraTransform() { @@ -298,7 +298,7 @@ public class Rope : MonoBehaviour private void RefreshVisibilityState(bool force = false) { - if (!cullRemoteRopeWhenInvisible || ShouldAlwaysSimulate()) + if (!cullRemoteRopeWhenInvisible) { _isCulledByVisibility = false; if (_lineRenderer) @@ -526,6 +526,7 @@ public class Rope : MonoBehaviour } SolveHardDistanceConstraints(hardTightenIterations); + SolveHardDistanceConstraintsAdaptive(); LockAnchorsHard(); if (constrainToGround) @@ -566,16 +567,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() @@ -592,9 +584,10 @@ public class Rope : MonoBehaviour Time.fixedDeltaTime ); - // 长度变化时额外压一点速度,减少收放线时抖动 - float delta = Mathf.Abs(_targetLength - _currentLength); - if (delta > 0.0001f && lengthChangeVelocityKill > 0f) + // 仅在收线(目标长度小于当前长度)时额外压速度; + // 放线时不要压速度,否则新增节点下落会出现“顿一下再突然加速”。 + float reelInDelta = _currentLength - _targetLength; + if (reelInDelta > 0.0001f && lengthChangeVelocityKill > 0f) { float keep = 1f - Mathf.Clamp01(lengthChangeVelocityKill); for (int i = 1; i < _physicsNodes - 1; i++) @@ -728,6 +721,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); @@ -744,7 +752,8 @@ public class Rope : MonoBehaviour SolveDistanceConstraintsSweep_Fast(last - 1, -1, -1, last, sweepStiffness); } - private void SolveDistanceConstraintsSweep_Fast(int start, int endExclusive, int step, int last, float sweepStiffness) + private void SolveDistanceConstraintsSweep_Fast(int start, int endExclusive, int step, int last, + float sweepStiffness) { for (int i = start; i != endExclusive; i += step) { @@ -781,6 +790,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; @@ -932,7 +956,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; @@ -943,7 +967,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; } @@ -958,7 +984,6 @@ public class Rope : MonoBehaviour } int idx = 0; - int last = _physicsNodes - 1; for (int seg = 0; seg < last; seg++) { @@ -969,10 +994,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++) { @@ -995,12 +1020,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; @@ -1060,4 +1094,4 @@ public class Rope : MonoBehaviour for (int i = 0; i < _physicsNodes; i++) Gizmos.DrawSphere(_pCurr[i], 0.01f); } -} +} \ No newline at end of file