95 lines
2.8 KiB
C#
95 lines
2.8 KiB
C#
using UnityEngine;
|
|
|
|
[RequireComponent(typeof(Rigidbody))]
|
|
[RequireComponent(typeof(CapsuleCollider))]
|
|
public class CapsuleBuoyancy : MonoBehaviour
|
|
{
|
|
[Header("Water Settings")]
|
|
public float waterHeight = 0f; // 水面高度
|
|
public float waterDensity = 1000f; // 水密度
|
|
|
|
[Header("Buoyancy Settings")]
|
|
public int samplePoints = 8; // 采样点数量
|
|
public float buoyancyMultiplier = 1.0f; // 浮力强度调节
|
|
public float waterDrag = 1.5f; // 水阻力
|
|
public float waterAngularDrag = 1.5f; // 水角阻力
|
|
|
|
private Rigidbody rb;
|
|
private CapsuleCollider capsule;
|
|
|
|
private float capsuleVolume;
|
|
private float gravity;
|
|
|
|
void Start()
|
|
{
|
|
rb = GetComponent<Rigidbody>();
|
|
capsule = GetComponent<CapsuleCollider>();
|
|
|
|
gravity = Physics.gravity.magnitude;
|
|
|
|
CalculateCapsuleVolume();
|
|
}
|
|
|
|
void FixedUpdate()
|
|
{
|
|
ApplyBuoyancy();
|
|
}
|
|
|
|
void CalculateCapsuleVolume()
|
|
{
|
|
float radius = capsule.radius * Mathf.Max(transform.localScale.x, transform.localScale.z);
|
|
float height = Mathf.Max(0, capsule.height * transform.localScale.y - 2f * radius);
|
|
|
|
float cylinderVolume = Mathf.PI * radius * radius * height;
|
|
float sphereVolume = (4f / 3f) * Mathf.PI * radius * radius * radius;
|
|
|
|
capsuleVolume = cylinderVolume + sphereVolume;
|
|
}
|
|
|
|
void ApplyBuoyancy()
|
|
{
|
|
float submergedRatioTotal = 0f;
|
|
|
|
for (int i = 0; i < samplePoints; i++)
|
|
{
|
|
float t = (float)i / (samplePoints - 1);
|
|
Vector3 localPoint = Vector3.up * Mathf.Lerp(
|
|
-capsule.height * 0.5f + capsule.radius,
|
|
capsule.height * 0.5f - capsule.radius,
|
|
t);
|
|
|
|
Vector3 worldPoint = transform.TransformPoint(localPoint);
|
|
|
|
float depth = waterHeight - worldPoint.y;
|
|
|
|
if (depth > 0f)
|
|
{
|
|
float normalizedDepth = Mathf.Clamp01(depth / (capsule.height / samplePoints));
|
|
submergedRatioTotal += normalizedDepth;
|
|
|
|
float forceMagnitude =
|
|
waterDensity *
|
|
gravity *
|
|
(capsuleVolume / samplePoints) *
|
|
normalizedDepth *
|
|
buoyancyMultiplier;
|
|
|
|
Vector3 buoyancyForce = Vector3.up * forceMagnitude;
|
|
|
|
rb.AddForceAtPosition(buoyancyForce, worldPoint, ForceMode.Force);
|
|
}
|
|
}
|
|
|
|
// 如果在水中,加阻力
|
|
if (submergedRatioTotal > 0f)
|
|
{
|
|
rb.linearDamping = waterDrag;
|
|
rb.angularDamping = waterAngularDrag;
|
|
}
|
|
else
|
|
{
|
|
rb.linearDamping = 0f;
|
|
rb.angularDamping = 0.05f;
|
|
}
|
|
}
|
|
} |