修改鱼线逻辑

This commit is contained in:
2026-03-29 21:30:18 +08:00
parent 54a1b43585
commit 78bc4dfc53

View File

@@ -116,6 +116,18 @@ public class Rope : MonoBehaviour
[SerializeField, Min(0.0001f)] private float lineWidth = 0.001f;
[Header("Performance")] [SerializeField, Tooltip("远端玩家鱼线不可见时,直接停止整条渲染线的模拟与绘制")]
private bool cullRemoteRopeWhenInvisible = true;
[SerializeField, Tooltip("本地玩家自己的鱼线始终保持完整计算")]
private bool localOwnerAlwaysSimulate = true;
[SerializeField, Range(1, 60), Tooltip("每隔多少个 FixedUpdate 重新判断一次可见性")]
private int visibilityCheckEvery = 10;
[SerializeField, Range(0f, 0.5f), Tooltip("屏幕边缘额外留白,避免刚进视野就闪现")]
private float visibilityViewportPadding = 0.08f;
[Header("Air Drag (Stable)")] [SerializeField, Range(0f, 5f), Tooltip("空气阻力Y向指数衰减越大越不飘")]
private float airDrag = 0.9f;
@@ -155,9 +167,19 @@ public class Rope : MonoBehaviour
private float _dt2;
private float _kY;
private float _kXZ;
private Transform _cameraTr;
private int _visibilityCheckCounter;
private bool _isCulledByVisibility;
private int _tIdleSubdiv = -1;
private int _tMovingSubdiv = -1;
private FRod _rod;
public void Init(FRod rod) => _rod = rod;
public void Init(FRod rod)
{
_rod = rod;
if (Application.isPlaying)
RefreshVisibilityState(true);
}
// Catmull t caches只缓存 idle/moving 两档,减少每帧重复乘法)
private struct TCaches
@@ -175,18 +197,12 @@ public class Rope : MonoBehaviour
_lineRenderer = GetComponent<LineRenderer>();
_gravity = new Vector3(0f, -gravityStrength, 0f);
_startTr = startAnchor ? startAnchor.transform : null;
_endTr = endAnchor ? endAnchor.transform : null;
RefreshAnchorTransforms();
InitLengthSystem();
AllocateAndInitNodes();
int maxSubdiv = Mathf.Max(1, renderSubdivisionsIdle);
_rCapacity = (maxPhysicsNodes - 1) * maxSubdiv + 1;
_rPoints = new Vector3[_rCapacity];
BuildTCaches(renderSubdivisionsIdle, ref _tIdle);
BuildTCaches(renderSubdivisionsMoving, ref _tMoving);
EnsureRenderCaches();
RefreshVisibilityState(true);
}
private void OnValidate()
@@ -217,6 +233,153 @@ public class Rope : MonoBehaviour
waterSurfaceOffset = Mathf.Max(0f, waterSurfaceOffset);
waterLiftStrength = Mathf.Clamp01(waterLiftStrength);
waterPostConstraintIterations = Mathf.Clamp(waterPostConstraintIterations, 0, 8);
visibilityCheckEvery = Mathf.Clamp(visibilityCheckEvery, 1, 60);
visibilityViewportPadding = Mathf.Clamp(visibilityViewportPadding, 0f, 0.5f);
}
private void RefreshAnchorTransforms()
{
_startTr = startAnchor ? startAnchor.transform : null;
_endTr = endAnchor ? endAnchor.transform : null;
}
private bool ShouldAlwaysSimulate()
{
if (!localOwnerAlwaysSimulate)
return false;
var owner = _rod?.PlayerItem?.Owner;
return owner == null || owner.IsSelf;
}
private Transform GetActiveCameraTransform()
{
Camera main = BaseCamera.Main;
if (main)
{
_cameraTr = main.transform;
return _cameraTr;
}
if (!_cameraTr)
{
Camera fallback = Camera.main;
if (fallback)
_cameraTr = fallback.transform;
}
return _cameraTr;
}
private static bool IsViewportPointVisible(Vector3 viewportPoint, float padding)
{
if (viewportPoint.z <= 0f)
return false;
return viewportPoint.x >= -padding && viewportPoint.x <= 1f + padding &&
viewportPoint.y >= -padding && viewportPoint.y <= 1f + padding;
}
private bool IsVisibleToMainCamera()
{
Transform camTr = GetActiveCameraTransform();
if (!camTr)
return true;
Camera cam = camTr.GetComponent<Camera>();
if (!cam)
cam = BaseCamera.Main ? BaseCamera.Main : Camera.main;
if (!cam)
return true;
Vector3 start = _startTr ? _startTr.position : (startAnchor ? startAnchor.position : transform.position);
Vector3 end = _endTr ? _endTr.position : (endAnchor ? endAnchor.position : transform.position);
Vector3 middle = (start + end) * 0.5f;
float padding = visibilityViewportPadding;
return IsViewportPointVisible(cam.WorldToViewportPoint(start), padding) ||
IsViewportPointVisible(cam.WorldToViewportPoint(end), padding) ||
IsViewportPointVisible(cam.WorldToViewportPoint(middle), padding);
}
private void RefreshVisibilityState(bool force = false)
{
if (!cullRemoteRopeWhenInvisible || ShouldAlwaysSimulate())
{
_isCulledByVisibility = false;
if (_lineRenderer)
_lineRenderer.enabled = true;
return;
}
if (!force)
{
_visibilityCheckCounter++;
if (_visibilityCheckCounter < visibilityCheckEvery)
return;
}
_visibilityCheckCounter = 0;
bool wasCulled = _isCulledByVisibility;
_isCulledByVisibility = !IsVisibleToMainCamera();
if (_lineRenderer)
_lineRenderer.enabled = !_isCulledByVisibility;
if (wasCulled && !_isCulledByVisibility)
SyncVisibleStateAfterCulling();
}
private void SyncVisibleStateAfterCulling()
{
_currentLength = Mathf.Max(_targetLength, 0.01f);
UpdateNodesFromLength();
UpdateHeadRestLenFromCurrentLength();
ResetNodesBetweenAnchors();
LockAnchorsHard();
}
private void ResetNodesBetweenAnchors()
{
if (_physicsNodes < 2)
return;
Vector3 start = _startTr ? _startTr.position : (startAnchor ? startAnchor.position : transform.position);
Vector3 end = _endTr ? _endTr.position : (endAnchor ? endAnchor.position : transform.position);
int last = _physicsNodes - 1;
for (int i = 0; i <= last; i++)
{
float t = (last > 0) ? i / (float)last : 0f;
Vector3 pos = Vector3.Lerp(start, end, t);
_pCurr[i] = pos;
_pPrev[i] = pos;
}
}
private void EnsureRenderCaches()
{
int idle = Mathf.Max(1, renderSubdivisionsIdle);
if (_tIdleSubdiv != idle)
{
BuildTCaches(idle, ref _tIdle);
_tIdleSubdiv = idle;
}
int moving = Mathf.Max(1, renderSubdivisionsMoving);
if (_tMovingSubdiv != moving)
{
BuildTCaches(moving, ref _tMoving);
_tMovingSubdiv = moving;
}
int maxSubdiv = Mathf.Max(idle, moving);
int neededCapacity = (maxPhysicsNodes - 1) * maxSubdiv + 1;
if (_rPoints == null || neededCapacity > _rCapacity)
{
_rCapacity = neededCapacity;
_rPoints = new Vector3[_rCapacity];
}
}
private void InitLengthSystem()
@@ -284,6 +447,9 @@ public class Rope : MonoBehaviour
public float GetLengthByPoints()
{
if (!smooth)
return GetPhysicsPolylineLength();
if (_rPoints == null || _lineRenderer == null) return 0f;
int count = _lineRenderer.positionCount;
@@ -338,6 +504,11 @@ public class Rope : MonoBehaviour
{
if (!startAnchor || !endAnchor) return;
RefreshAnchorTransforms();
RefreshVisibilityState();
if (_isCulledByVisibility)
return;
_dt = Time.fixedDeltaTime;
if (_dt < 1e-6f) _dt = 1e-6f;
_dt2 = _dt * _dt;
@@ -394,6 +565,12 @@ public class Rope : MonoBehaviour
{
if (!startAnchor || !endAnchor || _pCurr == null || _physicsNodes < 2) return;
RefreshAnchorTransforms();
if (_isCulledByVisibility)
return;
EnsureRenderCaches();
int last = _physicsNodes - 1;
Vector3 s = _startTr.position;