修改浮漂和绳子逻辑
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using UnityEngine;
|
||||
|
||||
using WaveHarmonic.Crest;
|
||||
|
||||
/// <summary>
|
||||
/// 简单水面接口。你可以替换成自己的水系统。
|
||||
/// </summary>
|
||||
@@ -26,10 +28,10 @@ public enum BobberControlMode
|
||||
public enum BobberBiteType
|
||||
{
|
||||
None,
|
||||
Tap, // 轻点
|
||||
SlowSink, // 缓沉
|
||||
Lift, // 送漂
|
||||
BlackDrift // 黑漂/快速拖入
|
||||
Tap, // 轻点
|
||||
SlowSink, // 缓沉
|
||||
Lift, // 送漂
|
||||
BlackDrift // 黑漂/快速拖入
|
||||
}
|
||||
|
||||
public enum BobberPosture
|
||||
@@ -43,135 +45,106 @@ public enum BobberPosture
|
||||
[RequireComponent(typeof(Rigidbody))]
|
||||
public class BobberPresentationController : MonoBehaviour
|
||||
{
|
||||
[Header("Water")]
|
||||
[Tooltip("没有水提供器时使用固定水位")]
|
||||
[Header("Water")] [Tooltip("没有水提供器时使用固定水位")]
|
||||
public float fallbackWaterLevel = 0f;
|
||||
|
||||
[Tooltip("Crest 水体。为空时会尝试从 SceneSettings 读取")]
|
||||
public WaterRenderer waterRenderer;
|
||||
|
||||
[Tooltip("Crest 查询层级")] public CollisionLayer waterCollisionLayer = CollisionLayer.AfterAnimatedWaves;
|
||||
|
||||
[Tooltip("Crest 波面查询宽度(参考 BobberFloating)")]
|
||||
public float waterQueryObjectWidth = 0.5f;
|
||||
|
||||
[Tooltip("可选:挂实现了 IWaterSurfaceProvider 的组件")]
|
||||
public MonoBehaviour waterProviderBehaviour;
|
||||
|
||||
[Header("Enter Water")]
|
||||
[Tooltip("底部进入水面多少米后切换为漂像控制")]
|
||||
[Header("Enter Water")] [Tooltip("底部进入水面多少米后切换为漂像控制")]
|
||||
public float enterWaterDepth = 0.002f;
|
||||
|
||||
[Tooltip("离开水面多少米后回到空中物理。一般给负值做滞回")]
|
||||
public float exitWaterDepth = -0.01f;
|
||||
[Tooltip("离开水面多少米后回到空中物理。一般给负值做滞回")] public float exitWaterDepth = -0.01f;
|
||||
|
||||
[Header("Geometry")]
|
||||
[Tooltip("浮漂总高度(米)")]
|
||||
[Header("Geometry")] [Tooltip("浮漂总高度(米)")]
|
||||
public float floatHeight = 0.08f;
|
||||
|
||||
[Tooltip("如果 Pivot 在浮漂底部,这里填 0;如果 Pivot 在模型中心,就填底部相对 Pivot 的本地 Y")]
|
||||
public float bottomOffsetLocalY = 0f;
|
||||
|
||||
[Header("Base Float")]
|
||||
[Tooltip("基础吃铅比例,决定静止时有多少在水下")]
|
||||
[Range(0.05f, 0.95f)]
|
||||
[Header("Base Float")] [Tooltip("基础吃铅比例,决定静止时有多少在水下")] [Range(0.05f, 0.95f)]
|
||||
public float baseSubmergeRatio = 0.28f;
|
||||
|
||||
[Tooltip("Y 轴平滑时间,越小响应越快")]
|
||||
public float ySmoothTime = 0.08f;
|
||||
[Tooltip("Y 轴平滑时间,越小响应越快")] public float ySmoothTime = 0.08f;
|
||||
|
||||
[Tooltip("最大竖直速度限制(用于 SmoothDamp)")]
|
||||
public float maxYSpeed = 2f;
|
||||
[Tooltip("最大竖直速度限制(用于 SmoothDamp)")] public float maxYSpeed = 2f;
|
||||
|
||||
[Tooltip("静止小死区,减少微抖")]
|
||||
public float yDeadZone = 0.0005f;
|
||||
[Tooltip("静止小死区,减少微抖")] public float yDeadZone = 0.0005f;
|
||||
|
||||
[Header("Surface Motion")]
|
||||
[Tooltip("是否启用轻微水面起伏")]
|
||||
[Header("Surface Motion")] [Tooltip("是否启用轻微水面起伏")]
|
||||
public bool enableSurfaceBobbing = true;
|
||||
|
||||
[Tooltip("水面轻微起伏振幅(米)")]
|
||||
public float surfaceBobAmplitude = 0.0015f;
|
||||
[Tooltip("水面轻微起伏振幅(米)")] public float surfaceBobAmplitude = 0.0015f;
|
||||
|
||||
[Tooltip("水面轻微起伏频率")]
|
||||
public float surfaceBobFrequency = 1.2f;
|
||||
[Tooltip("水面轻微起伏频率")] public float surfaceBobFrequency = 1.2f;
|
||||
|
||||
[Header("XZ Motion")]
|
||||
[Tooltip("入水后是否锁定 XZ 到入水点附近")]
|
||||
[Header("XZ Motion")] [Tooltip("入水后是否锁定 XZ 到入水点附近")]
|
||||
public bool lockXZAroundAnchor = true;
|
||||
|
||||
[Tooltip("XZ 跟随平滑时间")]
|
||||
public float xzSmoothTime = 0.15f;
|
||||
[Tooltip("XZ 跟随平滑时间")] public float xzSmoothTime = 0.15f;
|
||||
|
||||
[Tooltip("水流/拖拽带来的额外平面偏移最大值")]
|
||||
public float maxPlanarOffset = 0.15f;
|
||||
[Tooltip("水流/拖拽带来的额外平面偏移最大值")] public float maxPlanarOffset = 0.15f;
|
||||
|
||||
[Header("Sink By Weight / Tension")]
|
||||
[Tooltip("外部向下拉力映射为下沉量的系数。你可以把钩/铅/线组的等效向下拉力喂进来")]
|
||||
[Header("Sink By Weight / Tension")] [Tooltip("外部向下拉力映射为下沉量的系数。你可以把钩/铅/线组的等效向下拉力喂进来")]
|
||||
public float downForceToSink = 0.0025f;
|
||||
|
||||
[Tooltip("向下拉力下沉的最大附加量")]
|
||||
public float maxExtraSink = 0.08f;
|
||||
[Tooltip("向下拉力下沉的最大附加量")] public float maxExtraSink = 0.08f;
|
||||
|
||||
[Header("Bottom Touch")]
|
||||
[Tooltip("触底时是否启用修正")]
|
||||
[Header("Bottom Touch")] [Tooltip("触底时是否启用修正")]
|
||||
public bool enableBottomTouchAdjust = true;
|
||||
|
||||
[Tooltip("触底后减少的下沉量(例如铅坠到底,漂会回升一点)")]
|
||||
public float bottomTouchLift = 0.01f;
|
||||
[Tooltip("触底后减少的下沉量(例如铅坠到底,漂会回升一点)")] public float bottomTouchLift = 0.01f;
|
||||
|
||||
[Header("Posture Source")]
|
||||
[Tooltip("下方 Lure / 钩组 / 铅坠的刚体。姿态主要根据它和浮漂的相对位置判断")]
|
||||
[Header("Posture Source")] [Tooltip("下方 Lure / 钩组 / 铅坠的刚体。姿态主要根据它和浮漂的相对位置判断")]
|
||||
public Rigidbody lureBody;
|
||||
|
||||
[Tooltip("用于归一化的参考长度。一般填:浮漂到 Lure 在“正常拉直”时的大致长度")]
|
||||
public float referenceLength = 0.30f;
|
||||
|
||||
[Header("Posture Threshold")]
|
||||
[Tooltip("最小入水比例。不够时优先躺漂")]
|
||||
[Header("Posture Threshold")] [Tooltip("最小入水比例。不够时优先躺漂")]
|
||||
public float minSubmergeToStand = 0.16f;
|
||||
|
||||
[Tooltip("垂直分量比低于该值时,优先躺漂")]
|
||||
public float verticalLieThreshold = 0.18f;
|
||||
[Tooltip("垂直分量比低于该值时,优先躺漂")] public float verticalLieThreshold = 0.18f;
|
||||
|
||||
[Tooltip("垂直分量比高于该值,且水平分量较小时,允许立漂")]
|
||||
public float verticalUprightThreshold = 0.75f;
|
||||
[Tooltip("垂直分量比高于该值,且水平分量较小时,允许立漂")] public float verticalUprightThreshold = 0.75f;
|
||||
|
||||
[Tooltip("水平分量比高于该值时,不允许完全立漂")]
|
||||
public float planarTiltThreshold = 0.30f;
|
||||
[Tooltip("水平分量比高于该值时,不允许完全立漂")] public float planarTiltThreshold = 0.30f;
|
||||
|
||||
[Tooltip("水平分量明显大于垂直分量时,优先躺漂")]
|
||||
public float planarDominanceMultiplier = 1.20f;
|
||||
[Tooltip("水平分量明显大于垂直分量时,优先躺漂")] public float planarDominanceMultiplier = 1.20f;
|
||||
|
||||
[Tooltip("姿态切换滞回")]
|
||||
public float postureHysteresis = 0.04f;
|
||||
[Tooltip("姿态切换滞回")] public float postureHysteresis = 0.04f;
|
||||
|
||||
[Header("Posture Rotation")]
|
||||
[Tooltip("倾斜状态角度")]
|
||||
[Header("Posture Rotation")] [Tooltip("倾斜状态角度")]
|
||||
public float tiltedAngle = 38f;
|
||||
|
||||
[Tooltip("躺漂角度")]
|
||||
public float lyingAngle = 88f;
|
||||
[Tooltip("躺漂角度")] public float lyingAngle = 88f;
|
||||
|
||||
[Tooltip("立漂时允许的最大附加倾角")]
|
||||
public float uprightMaxTiltAngle = 8f;
|
||||
[Tooltip("立漂时允许的最大附加倾角")] public float uprightMaxTiltAngle = 8f;
|
||||
|
||||
[Tooltip("平面方向对立漂/斜漂附加倾角的影响强度")]
|
||||
public float planarTiltFactor = 120f;
|
||||
[Tooltip("平面方向对立漂/斜漂附加倾角的影响强度")] public float planarTiltFactor = 120f;
|
||||
|
||||
[Tooltip("姿态平滑速度")]
|
||||
public float rotationLerpSpeed = 8f;
|
||||
[Tooltip("姿态平滑速度")] public float rotationLerpSpeed = 8f;
|
||||
|
||||
[Header("Debug Input")]
|
||||
[Tooltip("调试:按 R 恢复默认")]
|
||||
[Header("Debug Input")] [Tooltip("调试:按 R 恢复默认")]
|
||||
public bool debugResetKey = true;
|
||||
|
||||
[Tooltip("调试:按 T 触发轻点")]
|
||||
public bool debugTapKey = true;
|
||||
[Tooltip("调试:按 T 触发轻点")] public bool debugTapKey = true;
|
||||
|
||||
[Tooltip("调试:按 G 触发缓沉")]
|
||||
public bool debugSlowSinkKey = true;
|
||||
[Tooltip("调试:按 G 触发缓沉")] public bool debugSlowSinkKey = true;
|
||||
|
||||
[Tooltip("调试:按 H 触发送漂")]
|
||||
public bool debugLiftKey = true;
|
||||
[Tooltip("调试:按 H 触发送漂")] public bool debugLiftKey = true;
|
||||
|
||||
[Tooltip("调试:按 B 触发黑漂")]
|
||||
public bool debugBlackDriftKey = true;
|
||||
[Tooltip("调试:按 B 触发黑漂")] public bool debugBlackDriftKey = true;
|
||||
|
||||
[Header("Debug")]
|
||||
public bool drawDebug = false;
|
||||
[Header("Debug")] public bool drawDebug = false;
|
||||
|
||||
public BobberControlMode CurrentMode => _mode;
|
||||
public BobberPosture CurrentPosture => _posture;
|
||||
@@ -218,6 +191,12 @@ public class BobberPresentationController : MonoBehaviour
|
||||
private float _verticalDistance;
|
||||
private float _planarDistance;
|
||||
|
||||
private bool _hasCrestSampleThisFrame;
|
||||
private readonly Vector3[] _waterQueryPoints = new Vector3[1];
|
||||
private readonly Vector3[] _waterQueryResultDisplacements = new Vector3[1];
|
||||
private readonly Vector3[] _waterQueryResultVelocities = new Vector3[1];
|
||||
private readonly Vector3[] _waterQueryResultNormal = new Vector3[1];
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_rb = GetComponent<Rigidbody>();
|
||||
@@ -229,6 +208,9 @@ public class BobberPresentationController : MonoBehaviour
|
||||
if (waterProviderBehaviour != null)
|
||||
_waterProvider = waterProviderBehaviour as IWaterSurfaceProvider;
|
||||
|
||||
if (waterRenderer == null && SceneSettings.Instance != null)
|
||||
waterRenderer = SceneSettings.Instance.Water;
|
||||
|
||||
_targetRotation = transform.rotation;
|
||||
}
|
||||
|
||||
@@ -404,7 +386,7 @@ public class BobberPresentationController : MonoBehaviour
|
||||
}
|
||||
|
||||
float surfaceBob = 0f;
|
||||
if (enableSurfaceBobbing)
|
||||
if (enableSurfaceBobbing && !_hasCrestSampleThisFrame)
|
||||
{
|
||||
surfaceBob = Mathf.Sin(Time.time * surfaceBobFrequency * Mathf.PI * 2f) * surfaceBobAmplitude;
|
||||
}
|
||||
@@ -701,6 +683,7 @@ public class BobberPresentationController : MonoBehaviour
|
||||
float k = (t - 0.35f) / 0.65f;
|
||||
targetOffset = -Mathf.Lerp(_biteAmplitude, 0f, k);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case BobberBiteType.SlowSink:
|
||||
@@ -742,7 +725,35 @@ public class BobberPresentationController : MonoBehaviour
|
||||
|
||||
private float GetWaterHeight(Vector3 worldPos)
|
||||
{
|
||||
return _waterProvider != null ? _waterProvider.GetWaterHeight(worldPos) : fallbackWaterLevel;
|
||||
if (_waterProvider != null)
|
||||
{
|
||||
_hasCrestSampleThisFrame = false;
|
||||
return _waterProvider.GetWaterHeight(worldPos);
|
||||
}
|
||||
|
||||
if (
|
||||
waterRenderer != null
|
||||
&& waterRenderer.AnimatedWavesLod != null
|
||||
&& waterRenderer.AnimatedWavesLod.Provider != null
|
||||
)
|
||||
{
|
||||
_waterQueryPoints[0] = worldPos;
|
||||
waterRenderer.AnimatedWavesLod.Provider.Query(
|
||||
GetHashCode(),
|
||||
Mathf.Max(0.001f, waterQueryObjectWidth),
|
||||
_waterQueryPoints,
|
||||
_waterQueryResultDisplacements,
|
||||
_waterQueryResultNormal,
|
||||
_waterQueryResultVelocities,
|
||||
waterCollisionLayer
|
||||
);
|
||||
|
||||
_hasCrestSampleThisFrame = true;
|
||||
return _waterQueryResultDisplacements[0].y + waterRenderer.SeaLevel;
|
||||
}
|
||||
|
||||
_hasCrestSampleThisFrame = false;
|
||||
return fallbackWaterLevel;
|
||||
}
|
||||
|
||||
private Vector3 GetBottomWorldPosition()
|
||||
@@ -821,6 +832,7 @@ public class BobberPresentationController : MonoBehaviour
|
||||
maxExtraSink = Mathf.Max(0f, maxExtraSink);
|
||||
surfaceBobAmplitude = Mathf.Max(0f, surfaceBobAmplitude);
|
||||
surfaceBobFrequency = Mathf.Max(0f, surfaceBobFrequency);
|
||||
waterQueryObjectWidth = Mathf.Max(0.001f, waterQueryObjectWidth);
|
||||
yDeadZone = Mathf.Max(0f, yDeadZone);
|
||||
|
||||
referenceLength = Mathf.Max(0.0001f, referenceLength);
|
||||
@@ -839,4 +851,4 @@ public class BobberPresentationController : MonoBehaviour
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user