修改鱼线逻辑
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user