去除odin

This commit is contained in:
Bob.Song
2026-03-26 16:39:20 +08:00
parent 7f0255574c
commit 3e11f158e9
125 changed files with 155 additions and 43985 deletions

View File

@@ -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