using UnityEngine; public enum BobberState { LyingDown, // 躺漂 RisingUp, // 起漂 Standing, // 正常站立 Bottom, // 挂底 TopLift, // 顶漂 DownPull, // 黑漂 Nibble // 小顿口 } public class FloatBobberControllerProV4 : MonoBehaviour { [Header("Environment")] public float waterLevel = 0f; [Header("Float Settings")] public float floatLength = 0.20f; // 漂总长度 public float buoyancyForce = 0.35f; // 浮力强度 public float mass = 0.015f; // 重量 public float tiltRecoverySpeed = 3f; // 漂恢复垂直速度 public float maxTiltAngle = 60f; // 躺漂最大角度 [Header("Line Settings")] public float lineTension = 0f; // 动态线张力(由鱼影响) public float bottomDrag = 1.5f; // 铅坠触底时的阻力 [Header("State Machine")] public BobberState state = BobberState.LyingDown; // internal vars private float verticalSpeed = 0f; private float angle = 60f; // 初始躺漂角度 private float lastHeight; private float deltaY; void Start() { lastHeight = transform.position.y; state = BobberState.LyingDown; } void Update() { deltaY = transform.position.y - lastHeight; lastHeight = transform.position.y; ApplyPhysics(); ProcessStateMachine(); ApplyRotation(); } // --------------------------------------------------------------------- // 一切物理都由状态机控制 // --------------------------------------------------------------------- void ProcessStateMachine() { switch (state) { case BobberState.LyingDown: LyingDownBehaviour(); break; case BobberState.RisingUp: RisingUpBehaviour(); break; case BobberState.Standing: StandingBehaviour(); break; case BobberState.Bottom: BottomBehaviour(); break; case BobberState.TopLift: TopLiftBehaviour(); break; case BobberState.DownPull: DownPullBehaviour(); break; case BobberState.Nibble: NibbleBehaviour(); break; } AutoTransition(); } // --------------------------------------------------------------------- // 【状态 → 行为】 // --------------------------------------------------------------------- void LyingDownBehaviour() { // 浮漂处于平躺,几乎无浮力 angle = Mathf.Lerp(angle, maxTiltAngle, Time.deltaTime * 1.5f); // 水面浮力很小 verticalSpeed += (buoyancyForce * 0.1f - mass * 9.8f) * Time.deltaTime; } void RisingUpBehaviour() { // 浮漂正在被浮力慢慢扶正 angle = Mathf.Lerp(angle, 0, Time.deltaTime * (tiltRecoverySpeed * 0.7f)); // 浮力略加强 verticalSpeed += (buoyancyForce * 0.5f) * Time.deltaTime; } void StandingBehaviour() { // 完全立稳 angle = Mathf.Lerp(angle, 0, Time.deltaTime * tiltRecoverySpeed); // 浮力与重力平衡,小幅波动 verticalSpeed += Mathf.Sin(Time.time * 4f) * 0.001f; } void BottomBehaviour() { // 铅坠或饵触底 → 浮漂立不起来 angle = Mathf.Lerp(angle, 20f, Time.deltaTime * 2f); // 上浮被底部拖住 verticalSpeed *= 0.6f; } void TopLiftBehaviour() { // 顶漂 → 漂被往上托一点 verticalSpeed += 0.02f; } void DownPullBehaviour() { // 黑漂 → 往下猛拉 verticalSpeed -= 0.05f; } void NibbleBehaviour() { // 小顿口 → 轻微波动 verticalSpeed += Mathf.Sin(Time.time * 20f) * 0.0015f; } // --------------------------------------------------------------------- // 状态自动切换 // --------------------------------------------------------------------- void AutoTransition() { // 1. 浮漂露出 40% 以上 → 起漂或站漂 float headHeight = transform.position.y + floatLength; if (state == BobberState.LyingDown && headHeight > waterLevel - 0.02f) state = BobberState.RisingUp; if (state == BobberState.RisingUp && angle < 12f) state = BobberState.Standing; // 2. 挂底判定 float tailHeight = transform.position.y - floatLength; if (tailHeight < waterLevel - 0.03f) state = BobberState.Bottom; // 3. 顶漂 if (deltaY > 0.015f) state = BobberState.TopLift; // 4. 黑漂 if (deltaY < -0.02f) state = BobberState.DownPull; // 5. 小顿口 if (Mathf.Abs(deltaY) > 0.003f && Mathf.Abs(deltaY) < 0.015f) state = BobberState.Nibble; } // --------------------------------------------------------------------- // 垂直物理 // --------------------------------------------------------------------- void ApplyPhysics() { float submerged = Mathf.Clamp01((waterLevel - transform.position.y) * 8f); float upForce = buoyancyForce * submerged - mass * 9.8f; verticalSpeed += upForce * Time.deltaTime; verticalSpeed = Mathf.Clamp(verticalSpeed, -0.2f, 0.2f); transform.position += new Vector3(0, verticalSpeed, 0); } // --------------------------------------------------------------------- // 倾斜角控制 // --------------------------------------------------------------------- void ApplyRotation() { Quaternion q = Quaternion.Euler(angle, 0, 0); transform.rotation = Quaternion.Slerp(transform.rotation, q, Time.deltaTime * 8f); } }