Files
Fishing2/Assets/Scripts/Test/Buoyancy.cs
2026-02-27 00:40:45 +08:00

209 lines
7.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<Rigidbody>();
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;
}
/// <summary>
/// Water provider (no plugin dependency).
/// 默认:水平水面,高度 = waterLevel
/// 以后接 Crest5你只要改这个函数即可。
/// </summary>
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);
}
}