124 lines
4.4 KiB
C#
124 lines
4.4 KiB
C#
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);
|
||
}
|
||
}
|
||
}
|