内容提交
This commit is contained in:
130
Assets/Scripts/Test/BobberBuoyancyStable.cs
Normal file
130
Assets/Scripts/Test/BobberBuoyancyStable.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
using UnityEngine;
|
||||
|
||||
[DisallowMultipleComponent]
|
||||
[RequireComponent(typeof(Rigidbody))]
|
||||
[RequireComponent(typeof(CapsuleCollider))]
|
||||
public class BobberBuoyancyStable : MonoBehaviour
|
||||
{
|
||||
[Header("Water")]
|
||||
public float waterLevelY = 0f;
|
||||
|
||||
[Tooltip("必须至少浸入这么深才开始产生浮力(防止还没入水就被顶)")]
|
||||
public float enterWaterDepth = 0.003f; // 3mm(按你的尺度改)
|
||||
|
||||
[Tooltip("在这个深度范围内做平滑过渡(越大越软)")]
|
||||
public float smoothDepth = 0.02f;
|
||||
|
||||
[Header("Buoyancy Spring")]
|
||||
public float buoyancySpring = 30f;
|
||||
public float buoyancyDamping = 8f;
|
||||
|
||||
[Tooltip("最大上浮加速度限制(0=不限制)")]
|
||||
public float maxUpAcceleration = 0f;
|
||||
|
||||
[Header("Water Drag")]
|
||||
public float extraLinearDampingInWater = 2f;
|
||||
public float extraAngularDampingInWater = 2f;
|
||||
|
||||
[Header("Center Of Mass")]
|
||||
public bool driveCenterOfMassFromCapsule = true;
|
||||
public Vector3 extraCenterOfMassOffset = new Vector3(0f, -0.01f, 0f);
|
||||
|
||||
[Header("Righting")]
|
||||
public float rightingTorque = 1.5f;
|
||||
public float rightingDamping = 0.5f;
|
||||
|
||||
Rigidbody rb;
|
||||
CapsuleCollider cap;
|
||||
|
||||
float airLinearDamping;
|
||||
float airAngularDamping;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
rb = GetComponent<Rigidbody>();
|
||||
cap = GetComponent<CapsuleCollider>();
|
||||
rb.useGravity = true;
|
||||
|
||||
airLinearDamping = rb.linearDamping;
|
||||
airAngularDamping = rb.angularDamping;
|
||||
|
||||
ApplyCenterOfMass();
|
||||
rb.maxAngularVelocity = 50f;
|
||||
}
|
||||
|
||||
void FixedUpdate()
|
||||
{
|
||||
ApplyCenterOfMass();
|
||||
|
||||
Bounds b = cap.bounds;
|
||||
float bottomY = b.min.y;
|
||||
float topY = b.max.y;
|
||||
|
||||
// 用“底部点”判定是否真正入水(必须超过阈值)
|
||||
float bottomSubmersion = waterLevelY - bottomY; // >0 表示底部在水下
|
||||
if (bottomSubmersion <= enterWaterDepth)
|
||||
{
|
||||
// 认为未入水:不施加浮力,恢复空气阻尼
|
||||
rb.linearDamping = airLinearDamping;
|
||||
rb.angularDamping = airAngularDamping;
|
||||
return;
|
||||
}
|
||||
|
||||
// 进入水中:阻尼随浸入增强
|
||||
// 这里用一个0~1的平滑权重,避免刚入水就“猛顶”
|
||||
float w = Smooth01((bottomSubmersion - enterWaterDepth) / Mathf.Max(1e-4f, smoothDepth));
|
||||
|
||||
rb.linearDamping = airLinearDamping + extraLinearDampingInWater * w;
|
||||
rb.angularDamping = airAngularDamping + extraAngularDampingInWater * w;
|
||||
|
||||
// 垂直速度(用刚体自身速度就够稳定)
|
||||
float vY = rb.linearVelocity.y;
|
||||
|
||||
// 弹簧+阻尼浮力(仅向上)
|
||||
float forceY = buoyancySpring * bottomSubmersion - buoyancyDamping * vY;
|
||||
if (forceY < 0f) forceY = 0f;
|
||||
|
||||
// 平滑权重:刚入水时逐渐接管
|
||||
forceY *= w;
|
||||
|
||||
// 限制最大上浮加速度(可选)
|
||||
if (maxUpAcceleration > 0f)
|
||||
{
|
||||
float maxForce = rb.mass * maxUpAcceleration;
|
||||
if (forceY > maxForce) forceY = maxForce;
|
||||
}
|
||||
|
||||
// 浮力作用点:必须放在水面下(否则会出现奇怪力矩)
|
||||
float buoyY = Mathf.Min(waterLevelY - 0.001f, topY); // 强制在水面下1mm
|
||||
buoyY = Mathf.Max(buoyY, bottomY); // 不低于底部
|
||||
Vector3 buoyPoint = new Vector3(b.center.x, buoyY, b.center.z);
|
||||
|
||||
rb.AddForceAtPosition(Vector3.up * forceY, buoyPoint, ForceMode.Force);
|
||||
|
||||
// 归正扭矩(只在水里生效)
|
||||
Vector3 up = transform.up;
|
||||
Vector3 axis = Vector3.Cross(up, Vector3.up);
|
||||
float mag = axis.magnitude;
|
||||
if (mag > 1e-4f)
|
||||
{
|
||||
axis /= mag;
|
||||
float angle = Mathf.Asin(Mathf.Clamp(mag, -1f, 1f));
|
||||
float angVelOnAxis = Vector3.Dot(rb.angularVelocity, axis);
|
||||
float torque = (rightingTorque * angle - rightingDamping * angVelOnAxis) * w;
|
||||
rb.AddTorque(axis * torque, ForceMode.Acceleration);
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyCenterOfMass()
|
||||
{
|
||||
if (!driveCenterOfMassFromCapsule) return;
|
||||
rb.centerOfMass = cap.center + extraCenterOfMassOffset;
|
||||
}
|
||||
|
||||
static float Smooth01(float t)
|
||||
{
|
||||
t = Mathf.Clamp01(t);
|
||||
// smoothstep
|
||||
return t * t * (3f - 2f * t);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user