修改浮漂和绳子逻辑

This commit is contained in:
Bob.Song
2026-03-26 12:18:24 +08:00
parent 6b14035ad9
commit 83da5b3196
10 changed files with 1774 additions and 1323 deletions

View File

@@ -85,6 +85,12 @@ public class Rope : MonoBehaviour
[SerializeField, Range(1, 8), Tooltip("每隔多少次FixedUpdate更新一次水面约束")]
private int waterUpdateEvery = 1;
[SerializeField, Range(0f, 1f), Tooltip("水面约束抬升强度(每次更新的插值强度),越小越渐进")]
private float waterLiftStrength = 0.25f;
[SerializeField, Tooltip("startAnchor 在水下时,让其相邻端节点强制跟随 startAnchor避免被抬到水面导致脱离")]
private bool keepStartAdjacentNodeFollow = true;
[SerializeField, Range(0, 8), Tooltip("水面约束后,再做几次长度约束,减少局部折角")]
private int waterPostConstraintIterations = 2;
@@ -201,6 +207,7 @@ public class Rope : MonoBehaviour
waterSampleStep = Mathf.Max(1, waterSampleStep);
waterUpdateEvery = Mathf.Max(1, waterUpdateEvery);
waterSurfaceOffset = Mathf.Max(0f, waterSurfaceOffset);
waterLiftStrength = Mathf.Clamp01(waterLiftStrength);
waterPostConstraintIterations = Mathf.Clamp(waterPostConstraintIterations, 0, 8);
}
@@ -630,16 +637,18 @@ public class Rope : MonoBehaviour
int step = Mathf.Max(1, waterSampleStep);
float surfaceY = waterLevelY + waterSurfaceOffset;
bool startUnderWater = _pCurr[0].y < surfaceY;
int startAdjacentIdx = GetStartAdjacentNodeIndex(last);
int prevSampleIdx = 1;
float prevSurfaceY = surfaceY;
ApplyWaterSurface(prevSampleIdx, prevSurfaceY);
ApplyWaterSurface(prevSampleIdx, prevSurfaceY, startUnderWater, startAdjacentIdx);
for (int i = 1 + step; i < last; i += step)
{
float nextSurfaceY = surfaceY;
ApplyWaterSurface(i, nextSurfaceY);
ApplyWaterSurface(i, nextSurfaceY, startUnderWater, startAdjacentIdx);
if (waterInterpolate)
{
@@ -651,13 +660,13 @@ public class Rope : MonoBehaviour
int idx = a + j;
float t = j / (float)span;
float y = Mathf.Lerp(prevSurfaceY, nextSurfaceY, t);
ApplyWaterSurface(idx, y);
ApplyWaterSurface(idx, y, startUnderWater, startAdjacentIdx);
}
}
else
{
for (int idx = prevSampleIdx + 1; idx < i; idx++)
ApplyWaterSurface(idx, prevSurfaceY);
ApplyWaterSurface(idx, prevSurfaceY, startUnderWater, startAdjacentIdx);
}
prevSampleIdx = i;
@@ -665,20 +674,38 @@ public class Rope : MonoBehaviour
}
for (int i = prevSampleIdx + 1; i < last; i++)
ApplyWaterSurface(i, prevSurfaceY);
ApplyWaterSurface(i, prevSurfaceY, startUnderWater, startAdjacentIdx);
}
private void ApplyWaterSurface(int i, float surfaceY)
private int GetStartAdjacentNodeIndex(int last)
{
if (last <= 1) return 1;
Vector3 s = _pCurr[0];
float d1 = (_pCurr[1] - s).sqrMagnitude;
float d2 = (_pCurr[last - 1] - s).sqrMagnitude;
return d1 <= d2 ? 1 : last - 1;
}
private void ApplyWaterSurface(int i, float surfaceY, bool startUnderWater, int startAdjacentIdx)
{
if (keepStartAdjacentNodeFollow && startUnderWater && i == startAdjacentIdx)
{
Vector3 s = _pCurr[0];
_pCurr[i] = s;
_pPrev[i] = s;
return;
}
Vector3 p = _pCurr[i];
if (p.y < surfaceY)
{
p.y = surfaceY;
p.y = Mathf.Lerp(p.y, surfaceY, waterLiftStrength);
_pCurr[i] = p;
// 同步 prev杀掉向下惯性,避免反复穿透水面
// 渐进同步 prev削弱向下惯性,避免反复穿透水面
Vector3 prev = _pPrev[i];
if (prev.y < surfaceY) prev.y = surfaceY;
if (prev.y < p.y) prev.y = Mathf.Lerp(prev.y, p.y, waterLiftStrength);
_pPrev[i] = prev;
}
}
@@ -798,4 +825,4 @@ public class Rope : MonoBehaviour
for (int i = 0; i < _physicsNodes; i++)
Gizmos.DrawSphere(_pCurr[i], 0.01f);
}
}
}