diff --git a/Assets/ResRaw/Prefabs/Line/fishing line float set.prefab b/Assets/ResRaw/Prefabs/Line/fishing line float set.prefab index 0ba4526bc..a3e70573e 100644 --- a/Assets/ResRaw/Prefabs/Line/fishing line float set.prefab +++ b/Assets/ResRaw/Prefabs/Line/fishing line float set.prefab @@ -47,7 +47,7 @@ MonoBehaviour: m_EditorClassIdentifier: startAnchor: {fileID: 0} endAnchor: {fileID: 54298866000586118} - LineMultiple: 1 + LineMultiple: 5 physicsSegmentLen: 0.1 minPhysicsNodes: 2 maxPhysicsNodes: 200 @@ -68,6 +68,8 @@ MonoBehaviour: groundRadius: 0.01 groundCastHeight: 1 groundCastDistance: 2.5 + groundSampleStep: 3 + groundInterpolate: 1 renderSubdivisionsIdle: 6 renderSubdivisionsMoving: 2 movingSpeedThreshold: 2 @@ -663,7 +665,7 @@ MonoBehaviour: m_EditorClassIdentifier: startAnchor: {fileID: 54298866000586118} endAnchor: {fileID: 54679398375713381} - LineMultiple: 1 + LineMultiple: 5 physicsSegmentLen: 0.2 minPhysicsNodes: 2 maxPhysicsNodes: 120 @@ -684,6 +686,8 @@ MonoBehaviour: groundRadius: 0.01 groundCastHeight: 1 groundCastDistance: 2.5 + groundSampleStep: 3 + groundInterpolate: 1 renderSubdivisionsIdle: 6 renderSubdivisionsMoving: 2 movingSpeedThreshold: 2 diff --git a/Assets/Scripts/Fishing/Rope/Rope.cs b/Assets/Scripts/Fishing/Rope/Rope.cs index 083610996..d7a2f5bd6 100644 --- a/Assets/Scripts/Fishing/Rope/Rope.cs +++ b/Assets/Scripts/Fishing/Rope/Rope.cs @@ -55,6 +55,17 @@ public class Rope : MonoBehaviour [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; + + [SerializeField, Range(1, 8), Tooltip("每隔多少个节点做一次地面检测;越大越省")] + private int groundSampleStep = 3; + + [SerializeField, Tooltip("未采样的点用插值还是直接拷贝邻近采样值")] + private bool groundInterpolate = true; + + [SerializeField, Range(1, 8), Tooltip("每隔多少次FixedUpdate更新一次地面约束")] + private int groundUpdateEvery = 2; + private int _groundFrameCounter; + [Header("Render (High Resolution)")] [SerializeField, Min(1), Tooltip("静止时每段物理线段插值加密数量(越大越顺,越耗)")] private int renderSubdivisionsIdle = 6; @@ -120,6 +131,7 @@ public class Rope : MonoBehaviour public float[] t2; public float[] t3; } + private TCaches _tIdle; private TCaches _tMoving; @@ -256,7 +268,14 @@ public class Rope : MonoBehaviour LockAnchorsHard(); if (constrainToGround) - ConstrainToGround(); + { + _groundFrameCounter++; + if (_groundFrameCounter >= groundUpdateEvery) + { + _groundFrameCounter = 0; + ConstrainToGround(); + } + } LockAnchorsHard(); } @@ -435,25 +454,94 @@ public class Rope : MonoBehaviour } } + // private void ConstrainToGround() + // { + // if (groundMask == 0) return; + // + // // RaycastHit 是 struct,这里不会 GC + // for (int i = 1; i < _physicsNodes - 1; i++) + // { + // Vector3 p = _pCurr[i]; + // Vector3 origin = p + Vector3.up * groundCastHeight; + // + // if (Physics.Raycast(origin, Vector3.down, out RaycastHit hit, groundCastDistance, groundMask, + // QueryTriggerInteraction.Ignore)) + // { + // float minY = hit.point.y + groundRadius; + // if (p.y < minY) p.y = minY; + // } + // + // _pCurr[i] = p; + // } + // } + private void ConstrainToGround() { if (groundMask == 0) return; - // RaycastHit 是 struct,这里不会 GC - for (int i = 1; i < _physicsNodes - 1; i++) - { - Vector3 p = _pCurr[i]; - Vector3 origin = p + Vector3.up * groundCastHeight; + int last = _physicsNodes - 1; + int step = Mathf.Max(1, groundSampleStep); - if (Physics.Raycast(origin, Vector3.down, out RaycastHit hit, groundCastDistance, groundMask, - QueryTriggerInteraction.Ignore)) + // 记录采样点的“最低允许Y” + // 不想分配数组就用局部变量滚动插值 + int prevSampleIdx = 1; + float prevMinY = SampleMinY(_pCurr[prevSampleIdx]); + + // 把采样点先处理掉 + ApplyMinY(prevSampleIdx, prevMinY); + + for (int i = 1 + step; i < last; i += step) + { + float nextMinY = SampleMinY(_pCurr[i]); + ApplyMinY(i, nextMinY); + + if (groundInterpolate) { - float minY = hit.point.y + groundRadius; - if (p.y < minY) p.y = minY; + // 在两个采样点之间插值 minY(视觉更平滑) + int a = prevSampleIdx; + int b = i; + int span = b - a; + for (int j = 1; j < span; j++) + { + int idx = a + j; + float t = j / (float)span; + float minY = Mathf.Lerp(prevMinY, nextMinY, t); + ApplyMinY(idx, minY); + } + } + else + { + // 直接用 prevMinY 填充中间点(更省) + for (int idx = prevSampleIdx + 1; idx < i; idx++) + ApplyMinY(idx, prevMinY); } - _pCurr[i] = p; + prevSampleIdx = i; + prevMinY = nextMinY; } + + // 尾巴剩余部分用最后一个采样值填 + for (int i = prevSampleIdx + 1; i < last; i++) + ApplyMinY(i, prevMinY); + } + + private float SampleMinY(Vector3 p) + { + Vector3 origin = p + Vector3.up * groundCastHeight; + if (Physics.Raycast(origin, Vector3.down, out RaycastHit hit, groundCastDistance, groundMask, + QueryTriggerInteraction.Ignore)) + return hit.point.y + groundRadius; + + // 没命中就不抬(返回极小值) + return float.NegativeInfinity; + } + + private void ApplyMinY(int i, float minY) + { + if (float.IsNegativeInfinity(minY)) return; + Vector3 p = _pCurr[i]; + if (p.y < minY) p.y = minY; + _pCurr[i] = p; } private void DrawHighResLine_Fast() @@ -488,10 +576,12 @@ public class Rope : MonoBehaviour for (int seg = 0; seg < last; seg++) { - int i0 = seg - 1; if (i0 < 0) i0 = 0; + int i0 = seg - 1; + if (i0 < 0) i0 = 0; int i1 = seg; int i2 = seg + 1; - int i3 = seg + 2; if (i3 > last) i3 = last; + int i3 = seg + 2; + if (i3 > last) i3 = last; Vector3 p0 = _pCurr[i0]; Vector3 p1 = _pCurr[i1];