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(); capsule = GetComponent(); 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; } } }