using System; using UnityEngine; [ExecuteInEditMode] [RequireComponent(typeof(Rigidbody))] public class Buoyancy : MonoBehaviour { // ====== No water plugin dependency ====== [Header("Water (No Plugin)")] [Tooltip("Fallback flat water level (Y). Set this to match your scene water height for now.")] public float waterLevel = 0f; [Tooltip("If false, buoyancy is disabled and rigidbody uses gravity.")] public bool waterAvailable = true; // ====== Original fields (kept) ====== public bool includeDeformation = true; [Tooltip("Approxative radius of object for buoyancy.")] public float sphereRadiusApproximation = 0.25f; [Tooltip("Specifies the multiplier for the movement induced by other deformation (waves, swell... etc).")] public float waveForceMultiplier = 1f; [Tooltip("Specifies the multiplier for the movement induced by the current of the water surface.")] public float currentSpeedMultiplier = 1f; [Tooltip("Specifies the multiplier for the drag forces induced by the viscosity of the mediums.")] public float dragMultiplier = 1f; public float defaultRigidbodyDrag = 0.1f; public float underwaterRigidbodyAngularDrag = 1f; public float overwaterRigidbodyAngularDrag = 0.05f; [Tooltip("Specifies the value for surface tension. A high value will stop the object bouncing faster on water.")] public float surfaceTensionDamping = 10f; [Tooltip("When enabled, the net force is applied with a random offset to create an angular velocity.")] public bool applyForceWithRandomOffset; // 原脚本里这个是 HDRP 的“自定义网格水面高度偏移”,这里保留字段但不再依赖水插件 [Tooltip("Optional extra offset added to sampled water height. Useful if your water mesh pivot isn't at surface level.")] public float waterHeightOffset = 0f; public bool drawDebug; private Vector3 currentDirection; private Vector3 A; private Vector3 B; private Vector3 C; private Vector3 waterPosition; private Vector3 normal; private Vector3 deformationDirection; private Rigidbody rigidbodyComponent; private float h; private float hNormalized; private bool _isEnabled = true; private void Start() { rigidbodyComponent = GetComponent(); rigidbodyComponent.useGravity = false; rigidbodyComponent.linearDamping = defaultRigidbodyDrag; } public void EnablePhysics(bool set) { _isEnabled = set; } private void FixedUpdate() { // ✅ 关键:没有水 / 禁用时,回到“用Unity重力” if (!_isEnabled || !waterAvailable) { h = (hNormalized = 0f); rigidbodyComponent.useGravity = true; return; } rigidbodyComponent.useGravity = false; FetchWaterSurfaceData(transform.position, out waterPosition, out normal, out currentDirection); deformationDirection = Vector3.ProjectOnPlane(normal, Vector3.up); h = Mathf.Clamp( waterPosition.y - (transform.position.y - sphereRadiusApproximation), 0f, 2f * sphereRadiusApproximation ); hNormalized = h * 1f / (2f * sphereRadiusApproximation); float num = MathF.PI * h * h / 3f * (3f * sphereRadiusApproximation - h); rigidbodyComponent.angularDamping = Mathf.Lerp(overwaterRigidbodyAngularDrag, underwaterRigidbodyAngularDrag, hNormalized); // === 以下保持原脚本单位/写法(尽量贴近原行为) === Vector3 b = rigidbodyComponent.mass * Physics.gravity; Vector3 vector = Vector3.Lerp(Physics.gravity, b, hNormalized); float num2 = 997f; float num3 = 0.001293f; float num4 = 1.81E-05f; float num5 = 0.001f; float num6 = 0.47f; Vector3 vector2 = (0f - num2) * num * Physics.gravity; Vector3 a = MathF.PI * 6f * sphereRadiusApproximation * num4 * -rigidbodyComponent.linearVelocity; Vector3 b2 = MathF.PI * 6f * sphereRadiusApproximation * num5 * -rigidbodyComponent.linearVelocity; Vector3 vector3 = Vector3.Lerp(a, b2, hNormalized) * dragMultiplier; float num7 = Mathf.Lerp( b: Mathf.Sqrt(2f * rigidbodyComponent.mass * (0f - Physics.gravity.y) / (num2 * MathF.PI * Mathf.Pow(sphereRadiusApproximation, 2f) * num6)), a: Mathf.Sqrt(2f * rigidbodyComponent.mass * (0f - Physics.gravity.y) / (num3 * MathF.PI * Mathf.Pow(sphereRadiusApproximation, 2f) * num6)), t: hNormalized ); Vector3 force = vector + vector2 + vector3; Vector3 vector4 = applyForceWithRandomOffset ? (new Vector3( UnityEngine.Random.Range(-1f, 1f), UnityEngine.Random.Range(-1f, 1f), UnityEngine.Random.Range(-1f, 1f) ) * sphereRadiusApproximation / 5f) : Vector3.zero; rigidbodyComponent.AddForceAtPosition(force, transform.position + vector4, ForceMode.Acceleration); if (hNormalized > 0f && hNormalized < 1f) { Vector3 force2 = -(Vector3.Dot(rigidbodyComponent.linearVelocity, Physics.gravity.normalized) * Physics.gravity.normalized) * surfaceTensionDamping; rigidbodyComponent.AddForce(force2, ForceMode.Acceleration); if (includeDeformation) { rigidbodyComponent.AddForce(deformationDirection * waveForceMultiplier, ForceMode.Acceleration); rigidbodyComponent.AddForce(currentDirection * currentSpeedMultiplier, ForceMode.Acceleration); } } if (rigidbodyComponent.linearVelocity.magnitude > num7) { rigidbodyComponent.linearVelocity = rigidbodyComponent.linearVelocity.normalized * num7; } } private Vector3 FetchWaterSurfaceData(Vector3 point, out Vector3 positionWS, out Vector3 normalWS, out Vector3 currentDirectionWS) { // ✅ 插件无关:统一从 GetWaterInfo 拿数据 GetWaterInfo(point, out float waterHeight, out normalWS, out currentDirectionWS); positionWS = new Vector3(point.x, waterHeight + waterHeightOffset, point.z); if (normalWS == Vector3.zero) normalWS = Vector3.up; return positionWS; } /// /// Water provider (no plugin dependency). /// 默认:水平水面,高度 = waterLevel /// 以后接 Crest5:你只要改这个函数即可。 /// protected virtual void GetWaterInfo(Vector3 worldPoint, out float waterHeight, out Vector3 waterNormal, out Vector3 waterCurrentDir) { waterHeight = waterLevel; // 默认水面高度(可在Inspector里调对齐) waterNormal = Vector3.up; // 默认法线 waterCurrentDir = Vector3.zero; // 默认水流方向 } public Vector3 GetCurrentWaterPosition() => waterPosition; public float GetNormalizedHeightOfSphereBelowSurface() => hNormalized; private void OnDrawGizmosSelected() { if (!drawDebug) return; Gizmos.color = Color.magenta; Gizmos.DrawLine(transform.position, transform.position + normal); Gizmos.color = Color.green; Gizmos.DrawLine(transform.position, transform.position + deformationDirection * 10f); Gizmos.color = Color.red; Gizmos.DrawLine(transform.position, transform.position + currentDirection); Gizmos.color = Color.yellow; Gizmos.DrawSphere(transform.position, sphereRadiusApproximation); Gizmos.color = Color.blue; Gizmos.DrawSphere(A, sphereRadiusApproximation / 10f); Gizmos.DrawSphere(B, sphereRadiusApproximation / 10f); Gizmos.DrawSphere(C, sphereRadiusApproximation / 10f); } }