去除odin
This commit is contained in:
@@ -122,6 +122,12 @@ public class BobberPresentationController : MonoBehaviour
|
||||
|
||||
[Tooltip("姿态切换滞回")] public float postureHysteresis = 0.04f;
|
||||
|
||||
[Header("Posture Stability")] [Tooltip("候选姿态需持续多久才真正切换")]
|
||||
public float postureConfirmTime = 0.08f;
|
||||
|
||||
[Tooltip("姿态切换后的最短冷却时间,避免来回闪烁")]
|
||||
public float postureSwitchCooldown = 0.10f;
|
||||
|
||||
[Header("Posture Rotation")] [Tooltip("倾斜状态角度")]
|
||||
public float tiltedAngle = 38f;
|
||||
|
||||
@@ -131,6 +137,10 @@ public class BobberPresentationController : MonoBehaviour
|
||||
|
||||
[Tooltip("平面方向对立漂/斜漂附加倾角的影响强度")] public float planarTiltFactor = 120f;
|
||||
|
||||
[Tooltip("平面方向死区,小于该值时保持上一帧方向")] public float planarDirectionDeadZone = 0.01f;
|
||||
|
||||
[Tooltip("平面方向平滑速度")] public float planarDirectionLerpSpeed = 10f;
|
||||
|
||||
[Tooltip("姿态平滑速度")] public float rotationLerpSpeed = 8f;
|
||||
|
||||
[Header("Debug Input")] [Tooltip("调试:按 R 恢复默认")]
|
||||
@@ -146,6 +156,9 @@ public class BobberPresentationController : MonoBehaviour
|
||||
|
||||
[Header("Debug")] public bool drawDebug = false;
|
||||
|
||||
public bool UseTestPosture;
|
||||
public BobberPosture TestPosture;
|
||||
|
||||
public BobberControlMode CurrentMode => _mode;
|
||||
public BobberPosture CurrentPosture => _posture;
|
||||
public float CurrentVerticalRatio => _verticalRatio;
|
||||
@@ -190,6 +203,10 @@ public class BobberPresentationController : MonoBehaviour
|
||||
private float _planarRatio;
|
||||
private float _verticalDistance;
|
||||
private float _planarDistance;
|
||||
private BobberPosture _pendingPosture;
|
||||
private float _pendingPostureTimer;
|
||||
private float _postureCooldownTimer;
|
||||
private Vector3 _stablePlanarDir = Vector3.forward;
|
||||
|
||||
private bool _hasCrestSampleThisFrame;
|
||||
private readonly Vector3[] _waterQueryPoints = new Vector3[1];
|
||||
@@ -211,6 +228,15 @@ public class BobberPresentationController : MonoBehaviour
|
||||
if (waterRenderer == null && SceneSettings.Instance != null)
|
||||
waterRenderer = SceneSettings.Instance.Water;
|
||||
|
||||
_pendingPosture = _posture;
|
||||
_pendingPostureTimer = 0f;
|
||||
_postureCooldownTimer = 0f;
|
||||
_stablePlanarDir = Vector3.ProjectOnPlane(transform.forward, Vector3.up);
|
||||
if (_stablePlanarDir.sqrMagnitude < 1e-6f)
|
||||
_stablePlanarDir = Vector3.forward;
|
||||
else
|
||||
_stablePlanarDir.Normalize();
|
||||
|
||||
_targetRotation = transform.rotation;
|
||||
}
|
||||
|
||||
@@ -344,6 +370,14 @@ public class BobberPresentationController : MonoBehaviour
|
||||
_planarRatio = 0f;
|
||||
_verticalDistance = 0f;
|
||||
_planarDistance = 0f;
|
||||
_pendingPosture = _posture;
|
||||
_pendingPostureTimer = 0f;
|
||||
_postureCooldownTimer = 0f;
|
||||
_stablePlanarDir = Vector3.ProjectOnPlane(transform.forward, Vector3.up);
|
||||
if (_stablePlanarDir.sqrMagnitude < 1e-6f)
|
||||
_stablePlanarDir = Vector3.forward;
|
||||
else
|
||||
_stablePlanarDir.Normalize();
|
||||
|
||||
_rb.useGravity = false;
|
||||
_rb.linearVelocity = Vector3.zero;
|
||||
@@ -425,34 +459,56 @@ public class BobberPresentationController : MonoBehaviour
|
||||
(waterY - GetBottomWorldPosition().y) / Mathf.Max(0.0001f, floatHeight)
|
||||
);
|
||||
|
||||
bool hasLure = lureBody != null;
|
||||
|
||||
if (lureBody == null)
|
||||
{
|
||||
_verticalDistance = 0f;
|
||||
_planarDistance = 0f;
|
||||
_verticalRatio = 0f;
|
||||
_planarRatio = 0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 bobberPos = _rb.worldCenterOfMass;
|
||||
Vector3 lurePos = lureBody.worldCenterOfMass;
|
||||
Vector3 delta = lurePos - bobberPos;
|
||||
|
||||
if (submergeRatio < minSubmergeToStand)
|
||||
_posture = BobberPosture.Lying;
|
||||
else if (ExternalPlanarOffset.magnitude > 0.01f)
|
||||
_posture = BobberPosture.Tilted;
|
||||
else
|
||||
_posture = BobberPosture.Upright;
|
||||
_verticalDistance = Mathf.Max(0f, Vector3.Dot(delta, Vector3.down));
|
||||
_planarDistance = Vector3.ProjectOnPlane(delta, Vector3.up).magnitude;
|
||||
|
||||
return;
|
||||
float refLen = Mathf.Max(0.0001f, referenceLength);
|
||||
_verticalRatio = _verticalDistance / refLen;
|
||||
_planarRatio = _planarDistance / refLen;
|
||||
}
|
||||
|
||||
Vector3 bobberPos = _rb.worldCenterOfMass;
|
||||
Vector3 lurePos = lureBody.worldCenterOfMass;
|
||||
Vector3 delta = lurePos - bobberPos;
|
||||
BobberPosture desiredPosture = DeterminePostureState(submergeRatio, hasLure);
|
||||
ApplyPostureWithStability(desiredPosture);
|
||||
}
|
||||
|
||||
_verticalDistance = Mathf.Max(0f, Vector3.Dot(delta, Vector3.down));
|
||||
_planarDistance = Vector3.ProjectOnPlane(delta, Vector3.up).magnitude;
|
||||
/// <summary>
|
||||
/// 只在这个函数里写姿态状态判断。
|
||||
/// 你后续要改逻辑,改这里即可,外面只负责采样数据和旋转平滑。
|
||||
/// </summary>
|
||||
private BobberPosture DeterminePostureState(float submergeRatio, bool hasLure)
|
||||
{
|
||||
if (UseTestPosture)
|
||||
{
|
||||
return TestPosture;
|
||||
}
|
||||
// 没有 Lure 时,保留简单兜底规则。
|
||||
if (!hasLure)
|
||||
{
|
||||
if (submergeRatio < minSubmergeToStand)
|
||||
return BobberPosture.Lying;
|
||||
|
||||
float refLen = Mathf.Max(0.0001f, referenceLength);
|
||||
_verticalRatio = _verticalDistance / refLen;
|
||||
_planarRatio = _planarDistance / refLen;
|
||||
if (ExternalPlanarOffset.magnitude > 0.01f)
|
||||
return BobberPosture.Tilted;
|
||||
|
||||
return BobberPosture.Upright;
|
||||
}
|
||||
|
||||
// 这里是完整状态判断入口(可按你的需求自由改)。
|
||||
switch (_posture)
|
||||
{
|
||||
case BobberPosture.Lying:
|
||||
@@ -467,15 +523,10 @@ public class BobberPresentationController : MonoBehaviour
|
||||
_verticalRatio > verticalLieThreshold + postureHysteresis;
|
||||
|
||||
if (canStandUpright)
|
||||
{
|
||||
_posture = BobberPosture.Upright;
|
||||
}
|
||||
else if (canTilt)
|
||||
{
|
||||
_posture = BobberPosture.Tilted;
|
||||
}
|
||||
|
||||
break;
|
||||
return BobberPosture.Upright;
|
||||
if (canTilt)
|
||||
return BobberPosture.Tilted;
|
||||
return BobberPosture.Lying;
|
||||
}
|
||||
|
||||
case BobberPosture.Tilted:
|
||||
@@ -491,18 +542,13 @@ public class BobberPresentationController : MonoBehaviour
|
||||
_planarRatio < planarTiltThreshold - postureHysteresis;
|
||||
|
||||
if (shouldLie)
|
||||
{
|
||||
_posture = BobberPosture.Lying;
|
||||
}
|
||||
else if (shouldStand)
|
||||
{
|
||||
_posture = BobberPosture.Upright;
|
||||
}
|
||||
|
||||
break;
|
||||
return BobberPosture.Lying;
|
||||
if (shouldStand)
|
||||
return BobberPosture.Upright;
|
||||
return BobberPosture.Tilted;
|
||||
}
|
||||
|
||||
case BobberPosture.Upright:
|
||||
default:
|
||||
{
|
||||
bool shouldLie =
|
||||
submergeRatio < minSubmergeToStand * 0.75f ||
|
||||
@@ -514,45 +560,92 @@ public class BobberPresentationController : MonoBehaviour
|
||||
_planarRatio > planarTiltThreshold + postureHysteresis;
|
||||
|
||||
if (shouldLie)
|
||||
{
|
||||
_posture = BobberPosture.Lying;
|
||||
}
|
||||
else if (shouldTilt)
|
||||
{
|
||||
_posture = BobberPosture.Tilted;
|
||||
}
|
||||
|
||||
break;
|
||||
return BobberPosture.Lying;
|
||||
if (shouldTilt)
|
||||
return BobberPosture.Tilted;
|
||||
return BobberPosture.Upright;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyPostureWithStability(BobberPosture desiredPosture)
|
||||
{
|
||||
_postureCooldownTimer = Mathf.Max(0f, _postureCooldownTimer - Time.fixedDeltaTime);
|
||||
|
||||
if (desiredPosture == _posture)
|
||||
{
|
||||
_pendingPosture = _posture;
|
||||
_pendingPostureTimer = 0f;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_postureCooldownTimer > 0f)
|
||||
{
|
||||
_pendingPosture = desiredPosture;
|
||||
_pendingPostureTimer = 0f;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_pendingPosture != desiredPosture)
|
||||
{
|
||||
_pendingPosture = desiredPosture;
|
||||
_pendingPostureTimer = 0f;
|
||||
return;
|
||||
}
|
||||
|
||||
_pendingPostureTimer += Time.fixedDeltaTime;
|
||||
if (_pendingPostureTimer >= Mathf.Max(0f, postureConfirmTime))
|
||||
{
|
||||
_posture = desiredPosture;
|
||||
_pendingPosture = _posture;
|
||||
_pendingPostureTimer = 0f;
|
||||
_postureCooldownTimer = Mathf.Max(0f, postureSwitchCooldown);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTargetRotationByPosture()
|
||||
{
|
||||
Vector3 planarDir = Vector3.zero;
|
||||
Vector3 candidateDir = Vector3.zero;
|
||||
|
||||
if (lureBody != null)
|
||||
{
|
||||
Vector3 delta = lureBody.worldCenterOfMass - _rb.worldCenterOfMass;
|
||||
planarDir = Vector3.ProjectOnPlane(delta, Vector3.up);
|
||||
candidateDir = Vector3.ProjectOnPlane(delta, Vector3.up);
|
||||
}
|
||||
|
||||
if (planarDir.sqrMagnitude < 1e-6f)
|
||||
if (candidateDir.sqrMagnitude < 1e-6f)
|
||||
{
|
||||
planarDir = new Vector3(_xzSmoothVelocity.x, 0f, _xzSmoothVelocity.z);
|
||||
candidateDir = new Vector3(_xzSmoothVelocity.x, 0f, _xzSmoothVelocity.z);
|
||||
}
|
||||
|
||||
if (planarDir.sqrMagnitude < 1e-6f)
|
||||
if (candidateDir.sqrMagnitude < 1e-6f)
|
||||
{
|
||||
planarDir = new Vector3(ExternalPlanarOffset.x, 0f, ExternalPlanarOffset.y);
|
||||
candidateDir = new Vector3(ExternalPlanarOffset.x, 0f, ExternalPlanarOffset.y);
|
||||
}
|
||||
|
||||
if (planarDir.sqrMagnitude < 1e-6f)
|
||||
if (_stablePlanarDir.sqrMagnitude < 1e-6f)
|
||||
{
|
||||
planarDir = transform.forward;
|
||||
_stablePlanarDir = Vector3.ProjectOnPlane(transform.forward, Vector3.up);
|
||||
if (_stablePlanarDir.sqrMagnitude < 1e-6f)
|
||||
_stablePlanarDir = Vector3.forward;
|
||||
}
|
||||
_stablePlanarDir.Normalize();
|
||||
|
||||
float dirDeadZone = Mathf.Max(0.0001f, planarDirectionDeadZone);
|
||||
if (candidateDir.sqrMagnitude > dirDeadZone * dirDeadZone)
|
||||
{
|
||||
candidateDir.Normalize();
|
||||
|
||||
// 保持与上一帧同向,避免 180 度翻转造成左右闪。
|
||||
if (Vector3.Dot(candidateDir, _stablePlanarDir) < 0f)
|
||||
candidateDir = -candidateDir;
|
||||
|
||||
float k = 1f - Mathf.Exp(-Mathf.Max(0.01f, planarDirectionLerpSpeed) * Time.fixedDeltaTime);
|
||||
_stablePlanarDir = Vector3.Slerp(_stablePlanarDir, candidateDir, k);
|
||||
_stablePlanarDir.Normalize();
|
||||
}
|
||||
|
||||
planarDir.Normalize();
|
||||
Vector3 planarDir = _stablePlanarDir;
|
||||
|
||||
Vector3 tiltAxis = Vector3.Cross(Vector3.up, planarDir);
|
||||
if (tiltAxis.sqrMagnitude < 1e-6f)
|
||||
@@ -560,27 +653,12 @@ public class BobberPresentationController : MonoBehaviour
|
||||
tiltAxis = transform.right;
|
||||
}
|
||||
|
||||
float angle;
|
||||
switch (_posture)
|
||||
float angle = _posture switch
|
||||
{
|
||||
case BobberPosture.Lying:
|
||||
angle = lyingAngle;
|
||||
break;
|
||||
|
||||
case BobberPosture.Tilted:
|
||||
{
|
||||
float extra = Mathf.Clamp(_planarRatio * planarTiltFactor, 0f, 18f);
|
||||
angle = Mathf.Clamp(tiltedAngle + extra, tiltedAngle, lyingAngle);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
float extra = Mathf.Clamp(_planarRatio * planarTiltFactor, 0f, uprightMaxTiltAngle);
|
||||
angle = extra;
|
||||
break;
|
||||
}
|
||||
}
|
||||
BobberPosture.Lying => lyingAngle,
|
||||
BobberPosture.Tilted => tiltedAngle,
|
||||
_ => 0f
|
||||
};
|
||||
|
||||
_targetRotation = Quaternion.AngleAxis(angle, tiltAxis.normalized);
|
||||
}
|
||||
@@ -842,11 +920,15 @@ public class BobberPresentationController : MonoBehaviour
|
||||
planarTiltThreshold = Mathf.Clamp(planarTiltThreshold, 0f, 2f);
|
||||
planarDominanceMultiplier = Mathf.Max(0.1f, planarDominanceMultiplier);
|
||||
postureHysteresis = Mathf.Clamp(postureHysteresis, 0f, 0.3f);
|
||||
postureConfirmTime = Mathf.Max(0f, postureConfirmTime);
|
||||
postureSwitchCooldown = Mathf.Max(0f, postureSwitchCooldown);
|
||||
|
||||
tiltedAngle = Mathf.Clamp(tiltedAngle, 0f, 89f);
|
||||
lyingAngle = Mathf.Clamp(lyingAngle, tiltedAngle, 89.9f);
|
||||
uprightMaxTiltAngle = Mathf.Clamp(uprightMaxTiltAngle, 0f, tiltedAngle);
|
||||
planarTiltFactor = Mathf.Max(0f, planarTiltFactor);
|
||||
planarDirectionDeadZone = Mathf.Max(0.0001f, planarDirectionDeadZone);
|
||||
planarDirectionLerpSpeed = Mathf.Max(0.01f, planarDirectionLerpSpeed);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user