Files
Fishing2/Assets/Scripts/BobberBuoyancy.cs

124 lines
4.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class BobberBuoyancy : MonoBehaviour
{
[Header("Water")]
public float waterLevel = 0f; // 水面是 0
public Vector3 waterFlow = Vector3.zero;
[Header("Bobber Size (origin at bottom)")]
public float bobberHeight = 0.18f; // 浮漂总高度(底部原点 → 顶部)
[Header("Buoyancy")]
public float maxBuoyancy = 12f; // 完全浸没浮力
public float buoyancyMultiplier = 1.0f;
public float waterDrag = 0.7f;
public float waterAngularDrag = 0.4f;
[Header("Vertical Damping控制“慢慢上浮”避免弹跳")]
public float verticalDamping = 4.0f; // 数值越大,上浮越慢、越不弹
[Header("Upright")]
public float uprightStrength = 8f; // 站漂恢复力
public float uprightDamping = 1.2f;
[Header("Lay Down (躺漂)")]
public float layDownThreshold = 0.15f; // 低于 15% 浸没 → 转入躺漂模式
public float layDownUprightMultiplier = 0.2f; // 躺漂时保留多少站立力度(越小越“翘头”)
private Rigidbody rb;
private void Awake()
{
rb = GetComponent<Rigidbody>();
rb.useGravity = true;
// 重心稍微靠上,配合 AddForceAtPosition才能让“底在水里、头上翘”
rb.centerOfMass = new Vector3(0, bobberHeight * 0.4f, 0);
}
private void FixedUpdate()
{
ApplyBuoyancy();
ApplyFlowForce();
ApplyOrientationControl();
}
void ApplyBuoyancy()
{
float bottom = rb.position.y; // 原点就是最底部
float depth = waterLevel - bottom; // 浸入深度 = 水面 - 底部
if (depth <= 0f) return; // 完全在水面上方,无浮力
// 当前浸没比例
float submersionRatio = Mathf.Clamp01(depth / bobberHeight);
// 基础浮力(和你之前一致)
float baseForce = maxBuoyancy * submersionRatio * buoyancyMultiplier;
// ⭐ 竖直速度(用你原来习惯的 linearVelocity
float vy = rb.linearVelocity.y;
// ⭐ 阻尼项:速度越快,反向力越大
// 下沉很快 → 给一个向上的阻尼(减缓下沉)
// 向上很快 → 给一个向下的阻尼(防止弹出水面)
float damping = -vy * verticalDamping;
// 总的向上力:基础浮力 + 阻尼修正
float totalUpForce = baseForce + damping;
// 物理上浮力不能把它“往下按”,所以最少为 0
if (totalUpForce < 0f) totalUpForce = 0f;
// ⭐ 浮力作用点 = 浸没体积中心(不动,保持你之前的设计)
float clampedDepth = Mathf.Clamp(depth, 0, bobberHeight);
float centerY = bottom + clampedDepth * 0.5f;
Vector3 buoyancyPoint = new Vector3(rb.position.x, centerY, rb.position.z);
rb.AddForceAtPosition(Vector3.up * totalUpForce, buoyancyPoint, ForceMode.Acceleration);
// 水中阻力(保留原逻辑)
rb.AddForce(-rb.linearVelocity * waterDrag, ForceMode.Acceleration);
rb.AddTorque(-rb.angularVelocity * waterAngularDrag, ForceMode.Acceleration);
}
void ApplyFlowForce()
{
if (waterFlow.sqrMagnitude <= 0.0001f) return;
rb.AddForce((waterFlow - rb.linearVelocity) * 0.3f, ForceMode.Acceleration);
}
void ApplyOrientationControl()
{
float bottom = rb.position.y;
float depth = waterLevel - bottom;
float submersionRatio = Mathf.Clamp01(depth / bobberHeight);
Vector3 up = transform.up;
Vector3 worldUp = Vector3.up;
if (submersionRatio > layDownThreshold)
{
// 深浸 → 正常站漂
Vector3 uprightTorqueVec =
Vector3.Cross(up, worldUp) * uprightStrength
- rb.angularVelocity * uprightDamping;
rb.AddTorque(uprightTorqueVec, ForceMode.Acceleration);
}
else
{
// 浅浸 → “躺漂”,只保留少量站立力,让它自然斜、头上翘
float reduced = uprightStrength * layDownUprightMultiplier;
Vector3 uprightTorqueVec =
Vector3.Cross(up, worldUp) * reduced
- rb.angularVelocity * uprightDamping;
rb.AddTorque(uprightTorqueVec, ForceMode.Acceleration);
}
}
}